如何将LEFT JOIN和Where子句与JPQL结合使用?

时间:2012-02-14 00:20:35

标签: java hibernate jpa left-join

我有两个JPA实体:

  • 时间表(包含预订清单)
  • 预订(包含日期字段:日期resDate)

我的目标是只检索与日期参数(planningDate)匹配的预订,同时检索所有时间表,无论在此给定日期是否存在预订。

所以我写道:

SELECT s FROM Schedule as s LEFT JOIN s.reservations as r WHERE r.resDate = :planningDate order by s.startHour

为什么不在这个日期没有预订的时间表,尽管我的LEFT JOIN已经检索到了?

可能与本机查询一样,LEFT JOIN在与WHERE子句组合时看起来像INNER JOIN。

那么,如何更改查询以满足我的要求?我没有在JPQL中找到特定的功能。

3 个答案:

答案 0 :(得分:13)

啊,这确实是JPA的经典之作。 我提供以下答案 - 我无法解释完全为什么会有效,但我可以为你解决这个问题

简短回答,请尝试:

SELECT s FROM Schedule as s LEFT JOIN s.reservations as r WHERE 
(r.resDate is null or r.resDate = :planningDate) order by s.startHour

(这里的关键是“r.resDate为null”部分)

答案很长: 明确表示这不是由hibernate / JPA人员工作的,但确实如此。生成的SQL也非常有效。如果有人能解释为什么会这样,我会留下最深刻的印象。我多年前就学会了这种模式,但不能为我的生活记住哪里。

一个注意事项:有一种情况,这将工作,并且在没有预约此计划的情况下。在这种情况下,我可以提供的唯一答案是您可以将查询包装在try / catch中以获取“NoResultException”,并在没有where子句的情况下再次查询(显然,如果没有预留,则不会对resDate进行保留) planningDate)

答案 1 :(得分:2)

在EclipseLink 2.5(Glassfish 4.0,Oracle 11g XE数据库)中:

不起作用(没有别名分配给r.assignee):

from Request r left join r.assignee 
order by case when r.assignee.id is null then 0 else r.assignee.id end desc

生成的查询部分(使用decart乘法):

  

来自请求t0,用户t1 WHERE((t1.ID =   t0.assignee_id))按顺序排序(t0.assignee_id为空)那么?   ELSE t1.ID END DESC)WHERE ROWNUM< =?)WHERE   rnum> ?

Works(将 a 别名添加到r.assignee):

from Request r left join r.assignee as a
order by case when a.id is null then 0 else a.id end desc

生成的查询部分(使用左连接):

  

FROM requests t1 LEFT OUTER JOIN users t0 ON(t0.ID = t1.assignee_id)   按顺序排序(t0.ID为空)那么? ELSE t0.ID END DESC)WHERE ROWNUM< =?)   在哪里> ?

答案 2 :(得分:1)

最后,我认为JPA中LEFT JOIN的概念不适用。

提醒最初的目标:

  

检索所有计划,无论发生什么,只有在匹配给定的planningDate时才填充预订集合(在这些相应的计划中)。

实际上,即使我设法检索其预订与我的标准不匹配的日程安排,无论如何,这些日程安排将分别重新加载他们的预订集合,如果这些日程表以fetch类型声明为“eager”,那么no限制条款对精确的“规划日期”的影响。这种行为与选择所有日程安排完全相似,没有任何其他限制。

因此,在JPA中解决我的问题的最简单的解决方案是提出2个请求:首先选择计划,然后选择匹配保留到planningDate,然后独立。因此,结果可以重新组合成一个列表并返回。缺点是预订集合会加载到时间。

如果你看到更好的解决方案,我将不胜感激。