HQL如何对实体关联集合的每一项执行自定义条件过滤
HQL集合属性自定义断言过滤实现方案
HQL没有你虚构的ANY_OF、CONFORMS_TO这类专门的断言匹配语法,你需要的「对集合元素应用自定义条件过滤实体」的需求,可以通过关联集合JOIN+WHERE条件的方式实现,这是HQL处理集合属性过滤的标准语法。
你需求的场景是「只要集合内存在至少一个符合条件的元素,就匹配对应的PainTracker实体」,可以用如下写法实现:
public List<PainTracker> getTrackersInCurrentlyActive() { // DISTINCT用于避免一个PainTracker匹配到多个符合条件的TimePeriod时返回重复结果 String query = "SELECT DISTINCT tracker FROM PainTracker AS tracker " + "JOIN tracker.timePeriods AS tp " + "WHERE tp.startTime < :currentTime AND tp.endTime > :currentTime"; TypedQuery<PainTracker> q = entityManager.createQuery(query, PainTracker.class); q.setParameter("currentTime", new Date()); return q.getResultList(); }
实现原理
- 语句中的
JOIN tracker.timePeriods AS tp会将PainTracker实体和它关联的TimePeriod集合做连接,每个PainTracker会对应其集合内的每一条TimePeriod记录 - 后续的WHERE条件会对关联的TimePeriod属性做过滤,仅保留匹配到符合条件的TimePeriod的PainTracker记录
- 如果你需要的是「集合所有元素都符合条件」的反向过滤逻辑,可以用
NOT EXISTS子查询实现,示例如下:
// 示例:查询所有TimePeriod都未开始的PainTracker String query = "SELECT tracker FROM PainTracker tracker " + "WHERE NOT EXISTS (" + " SELECT 1 FROM TimePeriod tp " + " WHERE tp MEMBER OF tracker.timePeriods " + " AND tp.startTime < :currentTime" + ")";
关于ANY操作符的说明
你之前查阅的ANY操作符仅适用于「单个值和子查询返回的单列结果集做比较」的场景,比如WHERE age > ANY (SELECT age FROM student),不支持对集合元素应用多条件判断,因此这类集合自定义过滤场景优先使用JOIN方案。
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

