【问题标题】:Generate a “where in” statement using the Criteria API in Hibernate在 Hibernate 中使用 Criteria API 生成“where in”语句
【发布时间】:2018-04-28 00:05:26
【问题描述】:

我制定了以下规范,表示根据学生的年龄和教室的教师姓名查询学生的谓词结构(一个学生可以有一个或多个教室)

public class StudentSpecification implements Specification<Student> {


  private final Integer age;

  public StudentSpecification(Integer age){
    this.age = age;
  }

  @Override
  public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
      List<Predicate> predicates = new ArrayList<>();

      predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.<Integert>get(age), Integer.valueOf(v)));

      SetJoin<Student, ClassRoom> classRooms = root.join(Student_.classRooms);

      predicates.add(criteriaBuilder.equal(classRooms.get(ClassRoom_.teacher), "Marta"));
      predicates.add(criteriaBuilder.equal(classRooms.get(ClassRoom_.teacher), "Fowler"));

      return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
  }
}

这是一个数据示例:

Student
_____________________________________________
ID     CLASSROOM_ID     NAME         AGE
2      120              Pascal       22 
8      120              Bryan        21


ClassRoom
_____________________________________________
ID     CLASSROOM_ID     TEACHER
1      120              Marta
2      120              McAllister
2      120              Fowler

规范不返回任何内容。

当我看到生成的语句时,我明白为什么它不起作用了:

 where 
  classRooms.teacher=?
  and classRooms.teacher=? 

我期待的是这样的:

where  
  students0.classroom_id in (
    select classrooms0.classroom_id where
    classRooms.teacher=?
  )
  and students0.classroom_id in (
    select classrooms0.classroom_id where
    classRooms.teacher=?
  )

问题:在我的情况下,如何使用 Criteria API 进行查询?

【问题讨论】:

    标签: java spring hibernate spring-data spring-data-jpa


    【解决方案1】:

    如果您需要坚持使用 Criteria API,您将需要 Subquery 来实现您想要的。否则,与 Criteria API 的冗长相比,为了可读性,HQL 可能是更好的选择。

    这个想法是生成单独的查询并通过谓词进行手动连接。所以不需要Join 或SetJoin。

    首先,请注意您的代码中存在一些错误。最明显的一个是您用来到达age 字段的路径。您应该使用生成的元模型而不是硬编码的字符串。

    predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get(Student_.age), age));
    

    而不是:

    predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.<Integert>get(age), Integer.valueOf(v)));
    

    那么,这里是完整的解决方案:

    public static Specification<Student> withTeacherAndName(){
      return new Specification<Student>() {
    
        @Override
        public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery,
            CriteriaBuilder criteriaBuilder) {
    
          List<Predicate> predicates = new ArrayList<>();
          predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get(Student_.age), 20));
    
    
          Subquery<String> sq1 = criteriaQuery.subquery(String.class);
          Root<Classroom> classroomRoot = sq1.from(Classroom.class);
          sq1.select(classroomRoot.get(Classroom_.classroomId));
          sq1.where(criteriaBuilder.equal(classroomRoot.get(Classroom_.teacher), "Marta"));
    
          Subquery<String> sq2 = criteriaQuery.subquery(String.class);
          Root<Classroom> classroomRoot2 = sq2.from(Classroom.class);
          sq2.select(classroomRoot2.get(Classroom_.classroomId));
          sq2.where(criteriaBuilder.equal(classroomRoot2.get(Classroom_.teacher), "Fowler"));
    
          criteriaQuery.where(criteriaBuilder.equal(root.get(Student_.classroomId), sq1));
          criteriaQuery.where(criteriaBuilder.equal(root.get(Student_.classroomId), sq2));
    
          return criteriaBuilder.and(predicates.toArray(new Predicate[]{}));
        }
      };
    }
    

    所以基本上你正在为每个条件创建一个子查询。 代码需要重构(例如循环)。

    【讨论】:

      【解决方案2】:

      如果您想要 in 子句而不是 equals 子句,请使用它:

      predicates.add(criteriaBuilder.in(classRooms.get(ClassRoom_.teacher), "Marta"));
      predicates.add(criteriaBuilder.in(classRooms.get(ClassRoom_.teacher), "Fowler"));
      

      见https://docs.oracle.com/javaee/6/api/javax/persistence/criteria/CriteriaBuilder.html#in(javax.persistence.criteria.Expression)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-08-02
        • 2015-07-26
        • 2014-10-03
        • 2012-12-24
        • 2017-01-20
        • 2019-04-01
        相关资源
        最近更新 更多