首页 > 解决方案 > 使用 Criteria API 的复杂请求

问题描述

我正在实施某种学校逻辑。我有学生实体女巫有他通过的考试清单:

 @Entity
 @Getter
 @Setter
 public class Student {

     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     @Column(name = "student_id")
     private Long id;

     @Column("name")
     private String name;

     @OneToMany(mappedBy = "student", cascade = CascadeType.ALL)
     private List<Exam> exams;
 }

考试本身具有标记值和 prePost 标识符(考试可以在上课之前或之后)

 @Entity
 @Getter
 @Setter
 public class Exam {

     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     @Column(name = "exam_id")
     private Long id;

     @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "student_id")
     private Student student;

     @Column("prePost")
     private String prePost;

     @Column("mark")
     private int mark;
 }

应该实施的要点之一是按姓名和他们通过的考试搜索学生。在前端有三个过滤器:学生姓名和考试标记。好吧,我正在为这个逻辑使用 Criteria API。这里的主要思想是创建一组规范,然后调用 StudentRepository 方法:

 List<Student> findAll(Specification<Student> spec);

其中 spec 是所有创建的 Specification 对象的结合结果。

好吧,我在通过考试实施搜索时遇到了困难。让我借助元语言中的 if-else 语句来解释正确的逻辑。

 if(student has at least one Post Exam) {
     for(Exam exam : student.exams) {
         if(exam.mark == selectedMark && exam.prePost == POST){
              *Current student is suitable*
         }
     }
 } else {
     for(Exam exam : student.exams) {
         if(exam.mark == selectedMark && exam.prePost == PRE){
              *Current student is suitable*
         }
     }
 }

这是在女巫的帮助下我尝试实现此逻辑的代码

   private Specification<Student> participantByExam(final Integer mark) {
    return Objects.nonNull(mark) ? (root, query, cb) -> {

        final Subquery<Exam> subquery = query.subquery(Exam.class);
        final Root<Exam> examRoot = subquery.from(Exam.class);

        final Expression<Object> expression = cb.selectCase()
                .when(cb.equal(root.join(Student_.exams).get(Exam.prePost), POST), cb.literal(POST))
                .otherwise(cb.literal(PRE));

        final Predicate predicate = cb.and(
                cb.equal(examRoot.get(Exam_.student), root),
                cb.equal(examRoot.get(Exam_.mark), mark),
                cb.equal(examRoot.get(Exam_.prePost), expression)
        );

        query.distinct(true);
        subquery
                .select(root.join(Student_.exams))
                .where(predicate);

        return cb.exists(subquery);

    } : null;
}

我在这里遇到的问题是不正确地使用连词:与有后期测试的学生和对他们的一个结果有一定分数的学生有连词。但我想接收具有一定分数的后考试的学生。

你能以某种方式帮助我这样复杂的请求逻辑吗?或者也许为此编写正确的 SQL 请求。

标签: javaspringjpaspring-data-jpacriteria-api

解决方案


推荐阅读