如何将指定SQL查询转换为基于CriteriaBuilder的Hibernate CriteriaQuery
JPA CriteriaBuilder 实现对应SQL查询方案
实现前提
- 已正确引入JPA相关依赖,可正常获取
EntityManager实例 - 涉及的
User、Teacher、Book实体类已完成JPA字段映射
完整实现代码
场景1:实体类已配置关联注解
如果User实体已通过JPA注解配置了和Teacher、Book的关联关系,直接使用如下代码:
import javax.persistence.EntityManager; import javax.persistence.criteria.*; import java.util.ArrayList; import java.util.List; public List<User> queryUserList(Long collegeId, String subCode, String lang) { // 获取CriteriaBuilder实例 CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); // 定义查询返回类型为User CriteriaQuery<User> criteriaQuery = criteriaBuilder.createQuery(User.class); Root<User> userRoot = criteriaQuery.from(User.class); // 内连接关联Teacher表 对应SQL里的INNER JOIN Teacher t ON t.emp_id = u.emp_id Join<User, Teacher> teacherJoin = userRoot.join("empId", JoinType.INNER); // 内连接关联User关联的Book表 Join<User, Book> bookJoin = userRoot.join("book", JoinType.INNER); // 组装查询条件 List<Predicate> conditionList = new ArrayList<>(); // 对应u.college_id=:college_id conditionList.add(criteriaBuilder.equal(userRoot.get("collegeId"), collegeId)); // 对应u.Book.sub_code=:sub_code conditionList.add(criteriaBuilder.equal(bookJoin.get("subCode"), subCode)); // 对应t.lang=:lang conditionList.add(criteriaBuilder.equal(teacherJoin.get("lang"), lang)); // 组装查询语句 criteriaQuery.select(userRoot) .where(conditionList.toArray(new Predicate[0])); // 执行查询返回结果 return entityManager.createQuery(criteriaQuery).getResultList(); }
场景2:实体类未配置关联注解
如果User和Teacher是独立实体,没有配置关联注解,手动指定关联条件即可:
import javax.persistence.EntityManager; import javax.persistence.criteria.*; import java.util.ArrayList; import java.util.List; public List<User> queryUserList(Long collegeId, String subCode, String lang) { CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery<User> criteriaQuery = criteriaBuilder.createQuery(User.class); // 同时加载两个根实体 Root<User> userRoot = criteriaQuery.from(User.class); Root<Teacher> teacherRoot = criteriaQuery.from(Teacher.class); Join<User, Book> bookJoin = userRoot.join("book", JoinType.INNER); List<Predicate> conditionList = new ArrayList<>(); // 手动指定关联条件 对应ON t.emp_id = u.emp_id conditionList.add(criteriaBuilder.equal(userRoot.get("empId"), teacherRoot.get("empId"))); // 其余查询条件和场景1一致 conditionList.add(criteriaBuilder.equal(userRoot.get("collegeId"), collegeId)); conditionList.add(criteriaBuilder.equal(bookJoin.get("subCode"), subCode)); conditionList.add(criteriaBuilder.equal(teacherRoot.get("lang"), lang)); criteriaQuery.select(userRoot) .where(conditionList.toArray(new Predicate[0])); return entityManager.createQuery(criteriaQuery).getResultList(); }
注意事项
- 所有
get("字段名")方法传入的是Java实体类的属性名,不是数据库表的列名,需和你自己实体类的定义保持一致 - 推荐使用JPA静态元模型替换硬编码的字段名,比如将
userRoot.get("collegeId")改成userRoot.get(User_.collegeId),可在编译期就校验字段正确性 - 如果需要返回多表全部字段而非仅User实体,只需要将
CriteriaQuery的泛型改为Object[],在select方法中传入需要返回的所有字段即可
内容的提问来源于stack exchange,提问作者Ganesh Prajapati
相关产品推荐
相关产品推荐

