求助:基于Criteria Query筛选选修指定教室课程的学生
Criteria Query实现:查询选修指定教室课程的学生
以下是对应你提供的JPQL的Criteria Query实现方案,包含基础版和类型安全版两种方式:
基础实现(使用属性名称字符串)
import jakarta.persistence.criteria.*; import java.util.List; public List<Student> findStudentsInRoom(String roomName) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Student> cq = cb.createQuery(Student.class); // 定义查询根实体为Student Root<Student> student = cq.from(Student.class); // 关联Student与Course(内连接,对应JPQL的INNER JOIN) Join<Student, Course> course = student.join("courses", JoinType.INNER); // 关联Course与Room(内连接) Join<Course, Room> room = course.join("room", JoinType.INNER); // 添加去重,对应JPQL中的DISTINCT cq.select(student).distinct(true); // 设置查询条件:教室名称匹配指定值 Predicate roomNameMatch = cb.equal(room.get("name"), roomName); cq.where(roomNameMatch); return em.createQuery(cq).getResultList(); }
类型安全实现(使用JPA Metamodel)
如果你的项目配置了JPA Metamodel生成(比如通过Hibernate或EclipseLink的注解处理器),可以用类型安全的方式避免属性名硬编码的拼写错误:
import jakarta.persistence.criteria.*; import java.util.List; // 导入自动生成的Metamodel类 import your.package.metamodel.Student_; import your.package.metamodel.Course_; import your.package.metamodel.Room_; public List<Student> findStudentsInRoom(String roomName) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Student> cq = cb.createQuery(Student.class); Root<Student> student = cq.from(Student.class); Join<Student, Course> course = student.join(Student_.courses, JoinType.INNER); Join<Course, Room> room = course.join(Course_.room, JoinType.INNER); cq.select(student).distinct(true); cq.where(cb.equal(room.get(Room_.name), roomName)); return em.createQuery(cq).getResultList(); }
关键说明
- 两种实现都完全对应你提供的JPQL逻辑:内连接Student、Course、Room,按教室名称过滤,返回去重后的学生列表
JoinType.INNER是默认值,可以省略,显式写出是为了和JPQL的INNER JOIN对应更清晰- 去重通过
distinct(true)实现,避免同一个学生因选修多门该教室的课程被重复返回
内容的提问来源于stack exchange,提问作者Gabor
相关产品推荐
相关产品推荐

