Spring JPQL中如何给SIZE函数加条件统计未删除的Dock?
解决方案:无需原生查询,JPQL可实现需求
你的需求完全可以通过JPQL实现,不需要切换到原生SQL。问题出在SIZE(tw.docks)会直接统计实体关联集合中的所有元素,不受JOIN子句条件的影响,所以之前加ON d.isDeleted = false无法改变统计结果。
下面提供两种可行的JPQL写法:
方法一:子查询统计符合条件的Dock数量
这种方式逻辑直观,通过子查询单独统计当前TimeWindow下未被删除的Dock数量:
@Query(""" SELECT tw FROM TW tw JOIN tw.docks d WHERE d.id = :dockId AND d.isDeleted = false AND tw.status <> 'DELETED' AND (SELECT COUNT(d2) FROM TW tw2 JOIN tw2.docks d2 WHERE tw2.id = tw.id AND d2.isDeleted = false) = 1 """) List<TW> findByDockIdAndValidDockCountOne(@Param("dockId") Long dockId);
- 首先通过
JOIN tw.docks d并过滤d.id = :dockId和d.isDeleted = false,确保TimeWindow关联了指定的未删除Dock; - 子查询部分专门统计当前TimeWindow下所有未删除的Dock数量,判断是否等于1。
方法二:GROUP BY + HAVING条件计数
利用分组和条件计数来实现需求,避免子查询:
@Query(""" SELECT tw FROM TW tw LEFT JOIN tw.docks d ON d.isDeleted = false WHERE EXISTS (SELECT 1 FROM tw.docks d2 WHERE d2.id = :dockId AND d2.isDeleted = false) AND tw.status <> 'DELETED' GROUP BY tw.id HAVING COUNT(d) = 1 """) List<TW> findByDockIdAndValidDockCountOne(@Param("dockId") Long dockId);
LEFT JOIN tw.docks d ON d.isDeleted = false只关联未删除的Dock;EXISTS子句确保当前TimeWindow确实关联了指定的未删除Dock;GROUP BY tw.id按TimeWindow分组后,COUNT(d)就是该TimeWindow下未删除的Dock数量,通过HAVING判断是否等于1。
补充说明
- 原查询中的
LEFT JOIN因为后续WHERE d.id = :dockId的限制,实际会被优化为INNER JOIN,所以直接用INNER JOIN语义更清晰; - 两种写法都不需要依赖原生SQL,完全符合JPQL规范,Hibernate可以正常解析执行。
内容的提问来源于stack exchange,提问作者Matexon
相关产品推荐
相关产品推荐

