如何使用JPA Criteria API构建Specification查询价格区间内的Product实体
正确的JPA Specification实现方案
你之前的写法错误是因为root.get(Product_.PRICES)获取的是Product关联的Price集合,无法直接对集合使用between运算符做值区间判断,你需要通过exists子查询判断是否存在至少一个关联的Price满足价格区间条件,这种写法还可以避免join关联带来的Product结果重复问题。
实现代码
import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Subquery; import java.math.BigDecimal; import java.util.Optional; public static Specification<Product> priceBetween(Optional<BigDecimal> minP, Optional<BigDecimal> maxP) { return (root, query, builder) -> { // 两个参数都为空时不追加该查询条件 if (minP.isEmpty() && maxP.isEmpty()) { return null; } // 构建exists子查询,查询满足价格条件的Price实体 Subquery<Price> priceSubquery = query.subquery(Price.class); var priceRoot = priceSubquery.from(Price.class); // 构建价格区间谓词,兼容仅传单边界的场景 Predicate pricePredicate = builder.conjunction(); minP.ifPresent(min -> pricePredicate.getExpressions() .add(builder.greaterThanOrEqualTo(priceRoot.get(Price_.PRICE), min))); maxP.ifPresent(max -> pricePredicate.getExpressions() .add(builder.lessThanOrEqualTo(priceRoot.get(Price_.PRICE), max))); // 子查询追加关联条件:Price对应的Product等于外层当前查询的Product priceSubquery.select(priceRoot).where( builder.equal(priceRoot.get(Price_.PRODUCT), root), pricePredicate ); // 外层查询条件:存在满足要求的Price即可 return builder.exists(priceSubquery); }; }
注意事项
- 如果你没有开启JPA元模型生成,把代码里的
Price_.PRODUCT替换为字符串"product",Price_.PRICE替换为字符串"price"即可正常运行 - 该实现同时支持三种参数场景:仅传最小价格、仅传最大价格、同时传价格上下限
- 生成的SQL自带exists子句,不会返回重复的Product记录,无需额外做去重处理
内容的提问来源于stack exchange,提问作者nurmanbetov
相关产品推荐
相关产品推荐

