JPQL:OR 不会按预期工作
JPQL: OR won't work as expected
我在存储库中定义了以下方法:
@Query("SELECT t FROM Treatment t WHERE " +
" (t.promotionCode.promotion.id=:promotionId) " +
" order by t.id desc")
Page<Treatment> findByPromotionId(@Param("promotionId")Integer id, Pageable pr);
它按预期工作:我得到了一个包含属于给定促销的促销代码的治疗列表。
但后来我需要添加第二个促销代码,这样一个 Treatment 最多可以链接到两个促销(两个促销代码可能属于同一个促销,这不是问题)。所以我尝试将新要求添加到查询中:
@Query("SELECT t FROM Treatment t WHERE " +
" (t.promotionCode.promotion.id=:promotionId) " +
" OR " +
" (t.promotionCode2.promotion.id=:promotionId) " +
" order by t.id desc")
Page<Treatment> findByPromotionId(@Param("promotionId")Integer id, Pageable pr);
但是我不会工作。生成的SQL是
select ...
from treatment treatment0_
cross join promotion_code promotionc1_
cross join promotion_code promotionc2_
where
treatment0_.promotion_code_id=promotionc1_.id and
treatment0_.promotion_code2_id=promotionc2_.id and
(promotionc1_.promo_id=? or promotionc2_.promo_id=?)
order by
treatment0_.id desc limit ?
如您所见,只要其中一个促销代码为空,即不满足条件。
一些细节,即使它们从代码中显而易见:
- 除了
treatment
还有一个table叫promotion_code
和另一个叫promotion
.
- 所有 table 都有一个数字 ID(自动递增)。
promotion_code_id
和promotion_code2_id
是指向promotion_code
的FK,也有指向promotion
的FK,不能为空(所有促销代码属于促销).
我想通过任何促销代码列查找与促销链接的所有治疗。两个字段都可以为空。
我该如何解决这个问题?
您可以尝试使用条件 API。
CriteriaBuilder 接口提供采用两个表达式操作数(包括 Predicate 实例)和 return 一个新的 Predicate 实例的工厂方法:
Predicate p1 = cb.and(isInUN, isInEU); // Member of both UN and EU
Predicate p2 = cb.or(isInOECD, isLarge); // Either OECD member or large
额外的工厂方法可用于不同数量的谓词:
Predicate p3 = cb.and(p1, isLarge, cb.isTrue(isInOECD));
Predicate p4 = cb.or(p2, cb.isTrue(isInUN), cb.isTrue(isInEU));
在上面的代码中,使用 isTrue 方法将非 Predicate 布尔表达式转换为 Predicate 实例。这是必需的,因为在非二进制版本中,工厂方法只接受 Predicate 实例作为参数。
来源url:https://www.objectdb.com/java/jpa/query/jpql/logical#Criteria_Query_Logical_Operators_
我试着模仿 UNION,它成功了:
SELECT t
FROM Treatment t
WHERE t IN (SELECT t FROM Treatment t
WHERE t.promotionCode.promotion.id = :promotionId)
OR t IN (SELECT t FROM Treatment t
WHERE t.promotionCode2.promotion.id = :promotionId)
ORDER BY t.id desc
在此之前,我尝试使用
的 LEFT JOIN FETCH 选项
SELECT t
FROM Treatment t
LEFT JOIN t.promotionCode.promotion as pc
LEFT JOIN t.promotionCode2.promotion as pc2
WHERE
(pc.id=:promotionId)
OR (pc2.id=:promotionId)
order by t.id desc
并与
SELECT t
FROM Treatment t
LEFT JOIN t.promotionCode as pc
LEFT JOIN t.promotionCode2 as pc2
WHERE
(pc.promotion.id=:promotionId)
OR (pc2.promotion.id=:promotionId)
order by t.id desc
但它们没有用(我得到很长的堆栈跟踪,说启动应用程序时查询不正确),
我在存储库中定义了以下方法:
@Query("SELECT t FROM Treatment t WHERE " +
" (t.promotionCode.promotion.id=:promotionId) " +
" order by t.id desc")
Page<Treatment> findByPromotionId(@Param("promotionId")Integer id, Pageable pr);
它按预期工作:我得到了一个包含属于给定促销的促销代码的治疗列表。
但后来我需要添加第二个促销代码,这样一个 Treatment 最多可以链接到两个促销(两个促销代码可能属于同一个促销,这不是问题)。所以我尝试将新要求添加到查询中:
@Query("SELECT t FROM Treatment t WHERE " +
" (t.promotionCode.promotion.id=:promotionId) " +
" OR " +
" (t.promotionCode2.promotion.id=:promotionId) " +
" order by t.id desc")
Page<Treatment> findByPromotionId(@Param("promotionId")Integer id, Pageable pr);
但是我不会工作。生成的SQL是
select ...
from treatment treatment0_
cross join promotion_code promotionc1_
cross join promotion_code promotionc2_
where
treatment0_.promotion_code_id=promotionc1_.id and
treatment0_.promotion_code2_id=promotionc2_.id and
(promotionc1_.promo_id=? or promotionc2_.promo_id=?)
order by
treatment0_.id desc limit ?
如您所见,只要其中一个促销代码为空,即不满足条件。
一些细节,即使它们从代码中显而易见:
- 除了
treatment
还有一个table叫promotion_code
和另一个叫promotion
. - 所有 table 都有一个数字 ID(自动递增)。
promotion_code_id
和promotion_code2_id
是指向promotion_code
的FK,也有指向promotion
的FK,不能为空(所有促销代码属于促销).
我想通过任何促销代码列查找与促销链接的所有治疗。两个字段都可以为空。
我该如何解决这个问题?
您可以尝试使用条件 API。
CriteriaBuilder 接口提供采用两个表达式操作数(包括 Predicate 实例)和 return 一个新的 Predicate 实例的工厂方法:
Predicate p1 = cb.and(isInUN, isInEU); // Member of both UN and EU
Predicate p2 = cb.or(isInOECD, isLarge); // Either OECD member or large
额外的工厂方法可用于不同数量的谓词:
Predicate p3 = cb.and(p1, isLarge, cb.isTrue(isInOECD));
Predicate p4 = cb.or(p2, cb.isTrue(isInUN), cb.isTrue(isInEU));
在上面的代码中,使用 isTrue 方法将非 Predicate 布尔表达式转换为 Predicate 实例。这是必需的,因为在非二进制版本中,工厂方法只接受 Predicate 实例作为参数。
来源url:https://www.objectdb.com/java/jpa/query/jpql/logical#Criteria_Query_Logical_Operators_
我试着模仿 UNION,它成功了:
SELECT t
FROM Treatment t
WHERE t IN (SELECT t FROM Treatment t
WHERE t.promotionCode.promotion.id = :promotionId)
OR t IN (SELECT t FROM Treatment t
WHERE t.promotionCode2.promotion.id = :promotionId)
ORDER BY t.id desc
在此之前,我尝试使用
的 LEFT JOIN FETCH 选项SELECT t
FROM Treatment t
LEFT JOIN t.promotionCode.promotion as pc
LEFT JOIN t.promotionCode2.promotion as pc2
WHERE
(pc.id=:promotionId)
OR (pc2.id=:promotionId)
order by t.id desc
并与
SELECT t
FROM Treatment t
LEFT JOIN t.promotionCode as pc
LEFT JOIN t.promotionCode2 as pc2
WHERE
(pc.promotion.id=:promotionId)
OR (pc2.promotion.id=:promotionId)
order by t.id desc
但它们没有用(我得到很长的堆栈跟踪,说启动应用程序时查询不正确),