Реализую какую-то школьную логику. У меня есть Студенческая сущность, у которой есть список сданных экзаменов:
@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-запрос для этого.
@PaulWasilewski, я опубликовал свою попытку создать эту логику, надеюсь, она будет вам полезна




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