HQL离开了不相关实体的连接

时间:2012-03-27 14:53:09

标签: java hibernate hql left-join

我有2个实体,AB。它们是相关的,但我不想将关系映射添加到bean。

我们如何使用HQL或条件在AB之间使用左外连接?

有一些可用的解决方法,

  1. 按照here使用原生SQL。
  2. 添加关系并使用从左侧加入a.b 中选择一个。
  3. 我们可以在HQL中执行内部联接,因为从A a中选择*,B b其中a.some = b.some
  4. 我总是回过头来看这两个选项,还有其他选择吗?或者这不可能?

4 个答案:

答案 0 :(得分:56)

目前,使用HQL加入where子句中不相关类的t​​heta-style仅支持内连接。

支持此类情况的外部联接的requestcurrently the 3-rd most voted enhancement但我不认为此功能将在近距离功能中实现,因为它首先需要re-implementation of the current ANTLER-based query parser成为一个巨大的任务IMO。

如果您坚持使用HQL执行左连接而不添加A和B之间的关系,则可以使用选项3先执行内连接,然后使用以下HQL

from A a where a.some not in ( select b.some from B)

找出所有无法加入B的A并以编程方式组合结果。

更新

自版本5.1.0起HHH-16 (Explicit joins on unrelated classes)已修复,我们应该可以加入不相关的实体。

答案 1 :(得分:3)

正如Ken Chan所说,你不能直接在一个HQL查询中完成它。

关于你的三种可能性:

  1. 原生SQL:不推荐。外连接的语法在不同的数据库之间是完全不同的。
  2. 添加关系:这就是我要做的。它不需要花费太多代码或内存,而且可以快速编程。
  3. 内部联接:如果关系确实是数据库中的外部联接,则不起作用(缺少行)。
  4. 如果由于任何特殊原因您真的不想添加关系,可以将查询拆分为两个单独的查询并在java中手动加入结果,例如:

    Query qa = session.createQuery("from A a");
    List la = qa.list();
    
    Query qb = session.createQuery("select distinct b.* from B b, A a where a.some=b.some");
    List lb = qb.list();
    
    Map bMap = new HashMap();
    for (B b : lb) {
      bMap.put(b.getId(), b);
    }
    
    /* example with for loop */
    for (A a : la) {
      B b = bMap.get(a.getForeignKeyForB());
      /* now you have A a and the outer joined B b and you can do with them what you want */
      ...
    }
    

    此解决方案的执行时间和内存成本(几乎)与数据库中的外部联接(解决方案2)相同。它只是一点点java代码。

    (解决方案类似于Ken Chan提出的解决方案,但它避免了“not in”和内部选择,这两者在数据库中都是低效的。)

答案 2 :(得分:1)

如果你知道每个A最多有1个B,你也可以使用子查询。

例如:

select a, (select b from B b where b.some = a.some)
from A a

如果您知道至少存在1个B,您也可以使用以下查询,但不建议这样做,因为它是黑客攻击:

select a, (select b4 from B b4 where b4=b and b4.some=a.some) from A a, B b 
where a.some=b.some or (a.some not in (select b2.some from B b2) 
and b.id = (select min(b3.id) from B b3))

答案 3 :(得分:-1)

大胆的声明:你不能。

为什么呢? JPQL(和HQL)期望实体之间的路径以加入它们。

我通常在这种情况下做的(首选订单):

  1. 关联实体。
  2. 以编程方式获取组装结果所需的数据。
  3. 您已提及的三个选项中的1个或3个。