如何使用CriteriaBuilder实现双外键OR条件的LEFT JOIN关联查询
错误原因分析
- 调用join方法时使用了实体预先定义的
Table1_.parent关联属性,该属性本身会默认生成table2.parent_id = t1.id的关联逻辑,后续自定义的on条件会被原有关联逻辑覆盖,无法实现OR效果 - 代码存在变量名错误:刚定义
Root<Table1> table1就调用table2.join,应该改为table1.join - on条件的匹配逻辑写反:应该是Table2的
parent_id/child_id匹配Table1的id,不是反过来
正确实现代码
// 需先初始化CriteriaBuilder、CriteriaQuery实例 CriteriaBuilder cb = entityManager.getCriteriaBuilder(); // 如果你需要返回Table1+Table2的全部字段,可以定义返回类型为Object[],如果只返回Table1就写Table1.class CriteriaQuery<Object[]> cq = cb.createQuery(Object[].class); Root<Table1> table1Root = cq.from(Table1.class); // 不使用预定义的关联关系,直接关联Table2实体,指定左连接类型 Join<Table1, Table2> table2Join = table1Root.join(Table2.class, JoinType.LEFT); // 自定义ON子句的OR关联条件 table2Join.on( cb.or( cb.equal(table2Join.get(Table2_.parentId), table1Root.get(Table1_.id)), cb.equal(table2Join.get(Table2_.childId), table1Root.get(Table1_.id)) ) ); // 追加WHERE条件匹配title cq.where(cb.equal(table2Join.get(Table2_.title), title)); // 选择返回的字段,这里对应SELECT *的逻辑,返回两个表的全部字段 cq.multiselect(table1Root, table2Join); // 执行查询 List<Object[]> result = entityManager.createQuery(cq).getResultList();
补充说明
- 如果没有生成JPA静态元模型,把
Table2_.parentId、Table1_.id这类元模型属性替换为字符串形式的字段名即可,例如table2Join.get("parentId") - 你给出的原生SQL中,LEFT JOIN后在WHERE子句过滤Table2的title字段,实际执行效果等价于INNER JOIN,会过滤掉没有匹配到Table2记录的Table1数据。如果需要保留无匹配的Table1记录,需要把title的过滤条件放到ON子句中,不要放在WHERE里。
内容的提问来源于stack exchange,提问作者Kuchka Moguchaya
相关产品推荐
相关产品推荐

