Сложный запрос с 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;
 }

Одним из пунктов, который следует реализовать, является поиск студентов по имени и экзаменам, которые они сдали. Ну, в интерфейсе есть три фильтра: имя студента и оценка за экзамен. Я использую API критериев для этой логики. Основная идея здесь - создать набор спецификаций, а затем вызвать метод StudentRepository:

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

где spec - результат соединения всех созданных объектов спецификации.

Что ж, у меня проблемы с поиском по экзаменам. Позвольте мне объяснить правильную логику с помощью оператора 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;
}

Проблема, с которой я столкнулся, заключается в неправильном использовании конъюнкции: существует конъюнкция со студентами, у которых есть Post-тесты, и со студентами, у которых есть определенная оценка за один из их результатов. Но я хочу принять студентов, которые сдадут почтовые экзамены с определенной отметкой.

Не могли бы вы как-нибудь помочь мне с такой сложной логикой запроса? Или, может быть, напишите правильный SQL-запрос для этого.

Это не сайт для выполнения домашней работы :(

Paul Wasilewski 18.06.2018 21:02

@PaulWasilewski, я опубликовал свою попытку создать эту логику, надеюсь, она будет вам полезна

Andrey Redkovskiy 19.06.2018 09:55
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
51
0

Другие вопросы по теме