【问题标题】:HQL left join with conditionHQL 有条件的左连接
【发布时间】:2017-02-08 06:51:21
【问题描述】:

这可能看起来很基本,但为时已晚,我遇到了以下问题。

class Group {

  @Id
  String id;
}

class Participation {

  @Id
  String id;

  @ManyToOne
  @JoinColumn(name = "GROUP_ID")
  Group group;

  @ManyToOne
  @JoinColumn(name = "USER_ID")
  User user;
}

class User {

  @Id
  String id;

  @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
  Set<Participation> participations;
}

Class diagram

所以

参与 -->1 组

和用户 1N 参与

对于给定的用户,我如何检索所有具有相关参与的组(或 null 表示没有参与)?我一直在玩 join fetches 但到目前为止无济于事......

非常感谢,

中国

PS。因此,我可以在 SQL 中执行此操作:

select g.d, p.id 
from group as g 
left join participation as p 
on p.group_id = g.id and p.user_id = 2;

【问题讨论】:

  • 编辑:添加图表和更好的 sql 解决方案...

标签: java sql hibernate join hql


【解决方案1】:

(HQL 本身可能有一些错字,但想法应该是正确的)

根据您的 SQL 和描述,您要问的是基于User 找出所有Participation(及其对应的Group),这很简单

select p.id, p.group.id from Participation p where p.user.id = :userId

为了使其更好,您应该改为获取实体:

from Participation p left join fetch p.group where p.user.id = :userId

在理解您要执行的操作时存在一些混淆: 您想要所有组(无论条件如何)。而且,对于给定的用户,您希望找到该用户所涉及的所有组和参与。

虽然应该可以使用 Right-outer-join:

select g, p from Participation p 
    right outer join p.group g 
    where p.user.id=:userId

或者,在更高版本的 Hibernate (>= 5.1 ?) 中,它允许显式连接(以前没有尝试过,您可以尝试一下)(如果您使用的是 JPQL,请将 with 替换为 on) :

select g, p from Group g
    left outer join Participation p 
        with p.group = g
    left outer join p.user u
    where u.id = :userId

或者您可以使用其他技术,例如子查询等。但是,在您的情况下,我宁愿将它们分成更简单的查询,并在您的代码中进行简单的聚合。

基本思想是有

  1. 查询所有组:from Groups
  2. 查询用户的所有参与:from Participation p join fetch p.group where p.user.id=:userId

然后您可以轻松地将它们聚合成您想要的形式,例如Map&lt;Group, List&lt;Participation&gt;&gt;,或者更有意义的值对象。

好处是数据访问查询更简单,更可重用(尤其是如果您将它们包装在 DAO/Repository finder 方法中)。多往返一次 DB 不会对性能造成任何明显影响。

【讨论】:

  • 谢谢,除了这样我不会得到没有指定用户参与的组。
  • 我手头没有 dbms,但是作为您的示例使用用户 ID 进行左连接仍然应该只为您提供包含参与者的组,不是吗?而且您要求“对于给定的用户,给定的参与”,这让您在没有用户的情况下参与与您的要求相矛盾。不管怎样,试试from Participation p left join p.user u where u.id =:userid or u is null
  • 啊,我想我误解了你的问题。你真的想要所有的组吗?无论如何iirc,HQL确实支持Right Join,所以您可以从Participation right join p.group开始?
【解决方案2】:

您需要在Group 实体中映射participation 关系。如果ParticipationGroup的关系是1..N:

class Group {
  String id
  List<Participation> participations
}

JPQL 可以是:

SELECT g.id, p.id FROM Group g
JOIN g.participations p
JOIN p.user user
WHERE user.id = :idUser

您可以通过List&lt;Object[]&gt; 接收此信息(Object[0] 是组 ID,Object[1] 是参与 ID)或使用 SELECT NEW

如果没有映射组/参与关系,您可以:

SELECT g.id, p.id FROM Group g, Participation p
JOIN p.user user
JOIN p.group groupp
WHERE g.id = groupp.id
AND user.id = :idUser

但是您不能使用此策略执行LEFT JOIN。上面的查询行为类似于JOIN

在 Hibernate 中,您映射关系的一侧是正常的,您想进行查询。所以,我推荐第一种方法,映射关系。

【讨论】:

  • 恐怕 Participation 和 Group 之间的关系不是 1:1(我在原问题中添加了图表)。
  • @ChambreNoire,没问题!我编辑了我的问题,但工作方式相同
  • 不加群就不行>参与关联?
  • Theta join 是我宁愿避免的(尤其是新版本的 hibernate 现在允许任意“on”子句进行连接)。并且实体中的关系应该足以编写有意义的 HQL
  • @AdrianShum,你在说什么加入?他也没有提供 Hibernate 的版本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-21
  • 1970-01-01
相关资源
最近更新 更多