使用JPQL / HQL查询分层数据



我们正在尝试实现一个简单的分层数据模型,如下所示。

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周)。

目前的解决方案:

  1. 查询所有Team实体并在事务中的两级集合上迭代,过滤掉那些不在时间范围内的分配。优点:简单。缺点:可能开销大。
  2. 查询后
  3. :

    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

问题:

  1. 是否有可能用单个SQL语句获取过滤叶级(分配)的整个树状集合?如果不是,建议的解决方案中有什么可以改进的?
  2. 为什么双取不能正常工作?

附加信息:我们使用Hibernate 4.3.5。最后,PostgreSQL .

是否可以使用filtered获取整个树状集合叶级(赋值)与单个SQL语句?如果不是,那又是什么?可以在提议的解决方案中改进吗?

是的,有可能。但是,您需要将映射更改为使用Set而不是List

为什么双取不能正常工作?

当你试图获取多个集合时,你不能在同一个查询中有两个或两个以上的List

因此,将赋值或成员从List更改为Set

要过滤分配,不能在提取的子句中这样做。如果您想获取所有集合并在赋值中进行筛选,您的查询可以是:

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结果中带来很多不必要的信息。

双取意味着笛卡尔积,所以如果你有100个团队,100个成员和100个任务,你将得到100 x 100 x 100 = 1,000,000个结果。

最好的获取方式是自底向上。

SELECT a FROM Assigment a
  inner join fetch a.member m
  inner join fetch m.team t

,自底向上重建树。您可以在Java中使用EntityGraphBuilder来映射它。

最新更新