背景
我在 SO 和许多流行博客中看到了关于必要性的多个答案和问题distinct
JPQL 中的关键字JOIN FETCH
查询和有关PASS_DISTINCT_THROUGH
查询提示。
例如,看这两个问题
- 使用 JPA 和 Hibernate 时 DISTINCT 如何工作 https://stackoverflow.com/questions/1346181/how-does-distinct-work-when-using-jpa-and-hibernate
- 在 JPA 上选择 DISTINCT https://stackoverflow.com/questions/42830497/select-distinct-on-jpa
和这些博客文章
- 将 JPQL DISTINCT 关键字与 JPA 和 Hibernate 结合使用的最佳方法 https://vladmihalcea.com/jpql-distinct-jpa-hibernate
- DISTINCT 传递 Hibernate 查询提示 https://in.relation.to/2016/08/04/introducing-distinct-pass-through-query-hint/
- Hibernate 技巧:如何将 DISTINCT 应用于 JPQL 而不是 SQL 查询 https://thorben-janssen.com/hibernate-tips-apply-distinct-to-jpql-but-not-sql-query/
我缺少什么
现在我的问题是我无法完全理解到底什么时候distinct
JPQL 查询中必须包含关键字。更具体地说,是否取决于使用哪种方法来执行查询(getResultList
or getSingleResult
).
下面是一个例子来阐明我的意思。
我从现在开始编写的所有内容都在 Ubuntu Linux 18.04 上进行了测试,使用 Java 8、Hibernate 5.4.13 和内存 H2 数据库(版本 1.4.200)。
假设我有一个Department
实体具有lazy与 a 的双向一对多关系DepartmentDirector
entity:
// Department.java
@Entity
public class Department {
// ...
private Set<DepartmentDirector> directors;
@OneToMany(mappedBy = "department", fetch = FetchType.LAZY)
public Set<DepartmentDirector> getDirectors() {
return directors;
}
// ...
}
// DepartmentDirector.java
@Entity
public class DepartmentDirector {
// ...
private Department department
@ManyToOne
@JoinColumn(name = "department_fk")
public Department getDepartment() {
return department;
}
// ...
}
假设我的数据库当前包含一个部门(department1
) 以及两名与之相关的董事。
现在我想通过其 uuid(主键)检索该部门及其所有主管。这可以通过以下方式完成JOIN FETCH
JPQL查询:
String query = "select department from Department department left join fetch "
+ "department.directors where department.uuid = :uuid";
由于前面的查询使用了join fetch
对于子集合,我希望它在发布时返回两个重复的部门:但是,这只在使用带有以下查询的查询时才会发生:getResultList
方法而不是使用时getSingleResult
方法。这在某种程度上是合理的,但我发现 Hibernate 的实现getSingleResult
uses getResultList
在窗帘后面所以我期待着NonUniqueResultException
被扔掉。
我还简要浏览了 JPA 2.2 规范,但没有提到处理两种方法之间的重复项的区别,并且涉及此问题的每个代码示例都使用getResultList
method.
结论
在我的例子中我发现JOIN FETCH
执行的查询getSingleResult
不会遇到我在本节中链接的资源中解释的重复实体问题背景.
如果上述说法是正确的,那就意味着同样的JOIN FETCH
查询需要distinct
如果执行getResultList
,但在执行时不需要它getSingleResult
.
我需要有人向我解释这是预期的情况还是我误解了什么。
Appendix
两次查询的结果:
-
查询运行的是getResultList
方法。我按预期得到了两个重复的部门(这样做只是为了测试查询的行为,getSingleResult
应该用来代替这个):
List<Department> resultList = entityManager.createQuery(query, Department.class)
.setParameter("uuid", department1.getUuid())
.getResultList();
assertThat(resultList).containsExactly(department1, department1); // passes
-
查询运行的是getSingleResult
方法。我希望检索到相同的重复部门,因此NonUniqueResultException
被扔掉。相反,检索到一个部门并且一切正常:
Department singleResult = entityManager.createQuery(query, Department.class)
.setParameter("uuid", department1.getUuid())
.getSingleResult();
assertThat(singleResult).isEqualTo(department1); // passes