我们正在尝试实现一个简单的分层数据模型,如下所示。
public class Team {
/* ... */
@OneToMany(fetch = FetchType.LAZY, mappedBy = "team")
protected List<Member> members;
}
public class Member {
/* ... */
@ManyToOne(fetch = FetchType.LAZY)
protected Team team;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "member")
protected List<Assignment> assignments;
}
public class Assigment {
/* ... */
@ManyToOne(fetch = FetchType.LAZY)
protected Member member;
}
映射背后的想法非常简单 - 一个团队由成员组成,而这些成员又被分配了一些职责。
问题:创建一个查询,该查询将返回团队->成员->分配的层次结构,并对分配施加条件(例如,截止日期 < 1 周内)。
目前的解决方案:
- 查询所有团队实体并迭代事务中的两级集合,过滤掉那些不在时间范围内的分配。 优点:简单。缺点:可能会产生大量开销。
以下查询:
SELECT t FROM Team t left join fetch t.members m left join fetch m.assignments
不幸的是,即使没有任何条件进行分配过滤,查询也会失败,抛出:
org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
我不明白为什么它不允许同时获取两个关系,因为 Hibernate 文档中显示了一个类似的例子:
from Cat as cat
inner join fetch cat.mate
left join fetch cat.kittens child
left join fetch child.kittens
问题:
- 是否可以使用单个 SQL 语句获取具有过滤叶级(分配)的整个树状集合?如果不是,建议的解决方案有哪些可以改进的地方?
- 为什么双重提取无法正常工作?
附加信息:我们正在使用 Hibernate 4.3.5.FINAL 和 PostgreSQL。
最佳答案
Is it possible to fetch the whole tree-like collection with filtered leaf-level (assignments) with a single SQL statement? If not, what could be improved in the proposed solution?
是的,这是可能的。但是,您需要更改映射以使用 Set
而不是 List
。
Why the double fetch does not work properly?
当您尝试获取多个集合时,您不能在同一个查询中有两个或多个 List
。
因此,将分配或成员从 List
更改为 Set
。
要过滤您的分配 cannot do that in a fetched clause .如果您想获取所有集合并在分配中进行过滤,您的查询可以是:
SELECT t FROM Team t
join fetch t.members m -- only for fetch
join fetch m.assignments -- only for fetch
join t.members member -- new join to do the where
join member.assigments assigment -- new join to do the where
where assigment.anyAttribute = someValue -- filter assigment
但是,正如@Vlad 所说,此解决方案的笛卡尔积可能很大,并在 SQL 结果中带来大量不必要的信息。
关于hibernate - 使用 JPQL/HQL 查询分层数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25139879/