如何用Hibernate CriteriaBuilder实现无外键的IN子查询
使用CriteriaBuilder实现子查询IN条件查询
实体类定义
@Entity public class Thing1 { @Column long id; @Column String someReference; } @Entity public class Thing2 { @EmbeddedId Thing2PK id; @Embeddable public static class Thing2PK implements Serializable { @Column private String name; @Column(name = "client_id") private String account; @Column String possibleReference; } }
需求SQL
需要构建如下原生SQL对应的Criteria查询:
SELECT * FROM thing1 WHERE someReference IN ( SELECT possibleReference FROM thing2 WHERE name = :name)
问题
尝试使用criteriaBuilder.in时,发现它需要值集合或带@JoinColumn的关联查询,当前场景无法满足,该如何实现?
解决方案
可以通过**子查询(Subquery)**来实现这个IN条件,具体代码如下:
// 获取CriteriaBuilder CriteriaBuilder cb = entityManager.getCriteriaBuilder(); // 1. 构建主查询:查询Thing1的所有数据 CriteriaQuery<Thing1> mainQuery = cb.createQuery(Thing1.class); Root<Thing1> thing1Root = mainQuery.from(Thing1.class); mainQuery.select(thing1Root); // 2. 构建子查询:从Thing2中查询符合条件的possibleReference Subquery<String> subQuery = mainQuery.subquery(String.class); Root<Thing2> thing2Root = subQuery.from(Thing2.class); subQuery.select(thing2Root.get("id").get("possibleReference")); // 关联嵌入式ID中的字段 subQuery.where(cb.equal(thing2Root.get("id").get("name"), cb.parameter(String.class, "name"))); // 3. 主查询添加IN条件:someReference在子查询结果中 mainQuery.where(cb.in(thing1Root.get("someReference")).value(subQuery)); // 执行查询 TypedQuery<Thing1> query = entityManager.createQuery(mainQuery); query.setParameter("name", "目标名称"); List<Thing1> resultList = query.getResultList();
关键说明
- 子查询的返回类型要和主查询中用来匹配的字段类型一致(这里都是String)
- 访问嵌入式ID的字段时,需要通过
root.get("id")先获取嵌入式ID对象,再进一步获取其中的属性(如name、possibleReference) - 如果使用JPA元模型(Metamodel),可以替换字符串字段名为强类型的属性,比如
Thing2_.id.get(Thing2PK_.possibleReference),避免硬编码错误
内容的提问来源于stack exchange,提问作者RobHay
相关产品推荐
相关产品推荐

