【问题标题】:How to combine LEFT JOIN and Where clause with JPQL?如何将 LEFT JOIN 和 Where 子句与 JPQL 结合起来?
【发布时间】:2012-03-05 10:01:54
【问题描述】:

我有两个 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 中找到特定的功能。

【问题讨论】:

  • 是的,我注意到了。我还知道,使用本机查询,可以将条件放在 LEFT JOIN 的“ON”子句上。但在 JPQL 中似乎是不可能的;这就是我问的原因:)
  • 你说得对,问题不清楚。我正在重新编辑它。
  • 您是否尝试过LEFT OUTER JOIN 不确定语法是否允许,或者某些语言​​使用它?
  • 是的,我试过了。效果一样。
  • 你的两个实体有什么关系?如果没有现成的关系(例如@JoinColumn( name="mycolumn" )我不认为你可以使用join。

标签: java hibernate jpa left-join


【解决方案1】:

啊,这确实是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 is null”部分)

长答案: hibernate/JPA 人员明确表示这不起作用,但确实如此。生成的 SQL 也相当高效。如果有人能解释为什么会这样,我会印象最深刻的。我几年前就学会了这种模式,但我一生都不记得在哪里。

注意:有一种情况不起作用,即在没有对此时间表进行预订的情况下。在这种情况下,我能提供的唯一答案是,您可以将查询包装在“NoResultException”的 try/catch 中,然后在没有 where 子句的情况下再次查询(显然,如果没有保留,则没有 resDate 的保留计划日期)

【讨论】:

  • 这仅在 resDate 是非 NULL 列时有效。如果它可以为空,那么您可能会得到错误的结果。您可以改用 Hibernate 特定的 WITH,例如 LEFT JOIN s.reservations r WITH r.resDate = :planningDate,这将产生正确的 SQL 语句,并在 JOIN 中添加一个附加子句,例如 from t_schedule s left join t_reservations r on r.schedule_id = s.id and r.resDate='some date'
  • 我尝试了“WITH”关键字,但它不起作用,因为我懒得装行李。我得看看“过滤器”
  • @Arjan,如果你知道的话,你能提供一个简单的过滤器示例吗?
【解决方案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 乘法):

FROM 请求 t0 ,用户 t1 WHERE ((t1.ID = t0.assignee_id)) 按案例排序(t0.assignee_id 为空)那么? ELSE t1.ID END DESC) a WHERE ROWNUM ?

作品(为 r.assignee 添加了 a 别名):

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) A WHERE ROWNUM ?

【讨论】:

    【解决方案3】:

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

    提醒最初的目标:

    在匹配给定的计划日期时仅填充预订集合(在这些各自的时间表中)时检索所有发生的计划。

    确实,即使我设法检索到其预订与我的标准不匹配的日程,如果这些日程被声明为“eager”的获取类型,那么无论如何,这些日程将分别重新加载它们的预订集合,因此不会限制条款对精确的“planningDate”的影响。在没有任何其他限制的情况下选择所有计划的所有预订是一种完全相同的行为。

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

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

    【讨论】:

    • (很晚了,但请参阅我在 Chaos 的回答中对 WITH 的评论。虽然是特定于 Hibernate 的。)
    猜你喜欢
    • 2015-05-19
    • 2021-09-29
    • 1970-01-01
    • 2012-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-31
    相关资源
    最近更新 更多