Вам следует тщательно проверять SQL для такого рода запросов JPA, потому что там, вероятно, происходит больше, чем вы думаете.
Вы проделали большую работу по настройке отношения ManyToMany
с атрибутом rating
, и ваш второй запрос будет работать, но может легко вызвать проблемы и возможные проблемы с производительностью.
Для того, чтобы получить только студентов, правильный запрос может быть
em.createQuery("select s from Student s join fetch s.ratings r where r.course.id = 1", Student.class).getResultList().forEach(s->System.out.println(s + ":" + s.getRatings()));
Это дает журналы
Hibernate: select student0_.id as id1_2_0_, ratings1_.course_id as course_i1_1_1_, ratings1_.student_id as student_2_1_1_, ratings1_.rating as rating3_1_1_, ratings1_.student_id as student_2_1_0__, ratings1_.course_id as course_i1_1_0__ from Student student0_ inner join CourseRating ratings1_ on student0_.id=ratings1_.student_id where ratings1_.course_id=1
Hibernate: select course0_.id as id1_0_0_ from Course course0_ where course0_.id=?
Student(id=1):[CourseRating(id=model.CourseRatingKey@dd5, student=Student(id=1), course=Course(id=1), rating=11)]
Student(id=2):[CourseRating(id=model.CourseRatingKey@e10, student=Student(id=2), course=Course(id=1), rating=21)]
JPA сгенерирует дополнительный запрос для получения информации о курсе, поскольку он не был предварительно выбран. Вы можете решить это, предварительно загрузив его самостоятельно.
em.createQuery("select s from Student s join fetch s.ratings r join fetch r.course c where c.id = 1", Student.class).getResultList().forEach(s->System.out.println(s + ":" + s.getRatings()));
и это дает журналы
Hibernate: select student0_.id as id1_2_0_, ratings1_.course_id as course_i1_1_1_, ratings1_.student_id as student_2_1_1_, course2_.id as id1_0_2_, ratings1_.rating as rating3_1_1_, ratings1_.student_id as student_2_1_0__, ratings1_.course_id as course_i1_1_0__ from Student student0_ inner join CourseRating ratings1_ on student0_.id=ratings1_.student_id inner join Course course2_ on ratings1_.course_id=course2_.id where course2_.id=1
Student(id=1):[CourseRating(id=model.CourseRatingKey@dd5, student=Student(id=1), course=Course(id=1), rating=11)]
Student(id=2):[CourseRating(id=model.CourseRatingKey@e10, student=Student(id=2), course=Course(id=1), rating=21)]
Существует проблема в том, что у вас есть студенты с только частичным набором оценок курса. Если вы попытаетесь обновить оценку для студента, я думаю, что вы потеряете оценки других курсов. Возможно, это не проблема для вашего варианта использования, но вы также можете получить курс со списком студентов:
em.createQuery("select distinct c from Course c join fetch c.ratings r join fetch r.student where c.id = 1", Course.class).getSingleResult().getRatings().forEach(r->System.out.println(r.getStudent() + ":" + r));
И это даст те же результаты с немного другим запросом, и вы можете обновить рейтинг студента, не затрагивая другие курсы.
Hibernate: select distinct course0_.id as id1_0_0_, ratings1_.course_id as course_i1_1_1_, ratings1_.student_id as student_2_1_1_, student2_.id as id1_2_2_, ratings1_.rating as rating3_1_1_, ratings1_.course_id as course_i1_1_0__, ratings1_.student_id as student_2_1_0__ from Course course0_ inner join CourseRating ratings1_ on course0_.id=ratings1_.course_id inner join Student student2_ on ratings1_.student_id=student2_.id where course0_.id=1
Student(id=2):CourseRating(id=model.CourseRatingKey@e10, student=Student(id=2), course=Course(id=1), rating=21)
Student(id=1):CourseRating(id=model.CourseRatingKey@dd5, student=Student(id=1), course=Course(id=1), rating=11)
Это также может повлиять на форматирование JSON, если вы создаете службу REST. В первом случае у вас есть несколько массивов CourseRatings с одной записью, а во втором случае у вас есть только один массив CourseRatings с оценкой и записями студентов. По сути, неполный список Студентов, каждый из которых имеет частичный список Курсов, не является точным представлением вашей базы данных, в отличие от Курса с полным списком его Студентов. На данный момент я не уверен, какой из них более эффективен на сервере SQL, но курсов должно быть намного меньше, чем студентов, поэтому, если вы хотите, чтобы все студенты прошли курс, возможно, так будет лучше.
С JPA вы должны проверить SQL и тщательно протестировать ваши варианты использования. Так как на одного студента много студентов и несколько курсов, то стоит подумать о производительности или затратах памяти. Также обратите внимание, что результаты могут стать еще более странными, если вы не использовали fetch
в своих запросах для начала.