使用JPQL / HQL查询分层数据

时间:2014-08-05 13:19:42

标签: hibernate postgresql jpa hql jpql

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

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;
}

映射背后的想法非常简单 - 团队由成员组成,而成员又被分配了一些职责。

问题:创建一个查询,该查询将返回team-&gt; member-&gt;分配的层次结构,其中包含对分配施加的条件(例如,<1周内的截止日期)。

到目前为止的解决方案:

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

    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
    
  3. 我不明白为什么它不允许同时抓取两个关系,因为Hibernate docs中显示了一个类似的例子:

    from Cat as cat
      inner join fetch cat.mate
      left join fetch cat.kittens child
      left join fetch child.kittens
    

    问题:

    1. 是否可以使用单个SQL语句获取带有过滤的叶级(赋值)的整个树状集合?如果没有,可以在拟议的解决方案中改进什么?
    2. 为什么双重提取无法正常工作?
    3. 其他信息:我们正在使用Hibernate 4.3.5.FINAL&amp;的PostgreSQL。

2 个答案:

答案 0 :(得分:0)

双重抓取意味着笛卡尔积,所以如果你有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

从下到上重建树。您可以使用this article中解释的EntityGraphBuilder。

答案 1 :(得分:0)

  

是否可以通过过滤获取整个树状集合   使用单个SQL语句的叶级(赋值)?如果没有,那是什么   在拟议的解决方案中可以改进吗?

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

  

为什么双重提取无法正常工作?

当您尝试获取多个集合时,同一查询中不能有两个或更多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结果中带来了大量不必要的信息。