如何使用Criteria Query对无关联实体执行左外连接,实现旧SQL转JPA
无关联实体左外连接的Criteria Query实现方案
注:本实现仅支持JPA 2.1及以上版本,低版本JPA未提供无关联实体连接的标准支持,需使用原生SQL实现。
实现逻辑
原有SQL的核心是根据参数动态选择左关联A/B表,关联条件为两边id相等,由于Phone和A、B无实体关联映射,需要手动在join的on子句中指定关联规则。
完整代码示例
// 注入EntityManager实例 @PersistenceContext private EntityManager entityManager; public List<Object[]> getPhoneRelateData(boolean isA) { // 1. 构造Criteria基础对象 CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); // 定义返回值为Object数组,对应4个查询字段 CriteriaQuery<Object[]> criteriaQuery = criteriaBuilder.createQuery(Object[].class); // 以Phone作为查询根节点 Root<Phone> phoneRoot = criteriaQuery.from(Phone.class); // 2. 动态关联A/B实体,指定左外连接类型 Join<?, ?> relateJoin; if (isA) { relateJoin = phoneRoot.join(A.class, JoinType.LEFT); } else { relateJoin = phoneRoot.join(B.class, JoinType.LEFT); } // 手动指定关联条件,对应原SQL的id匹配逻辑 relateJoin.on(criteriaBuilder.equal(relateJoin.get("id"), phoneRoot.get("id"))); // 3. 指定查询返回字段 criteriaQuery.multiselect( phoneRoot.get("name"), phoneRoot.get("id"), relateJoin.get("name"), relateJoin.get("id") ); // 4. 执行查询返回结果 return entityManager.createQuery(criteriaQuery).getResultList(); }
补充说明
- 原有SQL将关联条件写在
where子句的写法存在逻辑问题:左外连接的关联条件放在where中会过滤关联表无匹配的行,实际等价于内连接。本实现将关联条件放在on子句中,完全符合左外连接语义,Phone表的全部数据都会保留,关联表无匹配时对应字段返回null。 - 代码中
get("属性名")的参数需要和对应实体类的属性名保持一致,无需和数据库列名匹配,JPA会自动根据实体的字段映射规则转换。 - 如果需要封装为自定义DTO返回,可将
CriteriaQuery的泛型改为对应DTO类,同时将multiselect替换为criteriaBuilder.construct(你的DTO类.class, 字段1, 字段2, 字段3, 字段4)即可。
内容的提问来源于stack exchange,提问作者Vidhya Raj Kaniyarakkal
相关产品推荐
相关产品推荐

