首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >JPQL:使用组合键建模的具有多对多关系的查询实体

JPQL:使用组合键建模的具有多对多关系的查询实体
EN

Stack Overflow用户
提问于 2019-06-26 03:00:23
回答 1查看 159关注 0票数 1

我阅读了有关如何使用组合键构建多对多的this article。这些实体是

代码语言:javascript
复制
class Student {

    // ...

    @OneToMany(mappedBy = "student")
    Set<CourseRating> ratings;

    // ...
} 

class Course {

    // ...

    @OneToMany(mappedBy = "course")
    Set<CourseRating> ratings;

    // ...
}

@Entity
class CourseRating {

    @EmbeddedId
    CourseRatingKey id;

    @ManyToOne
    @MapsId("student_id")
    @JoinColumn(name = "student_id")
    Student student;

    @ManyToOne
    @MapsId("course_id")
    @JoinColumn(name = "course_id")
    Course course;

    int rating;

    // standard constructors, getters, and setters
}

@Embeddable
class CourseRatingKey implements Serializable {

    @Column(name = "student_id")
    Long studentId;

    @Column(name = "course_id")
    Long courseId;

    // standard constructors, getters, and setters
    // hashcode and equals implementation
}

现在,让我们假设,我想要得到具有特定courseId的学生。

那么我的JPQ看起来会是什么样子:

代码语言:javascript
复制
select s from Student s join fetch s.ratings r where r.id.courseId=:courserId

代码语言:javascript
复制
select s from Student s join fetch s.ratings r where r.course.id=:courserId

或者它将是完全不同的?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-26 08:06:44

对于这类JPA查询,您应该仔细检查SQL,因为其中可能发生了比您意识到的更多的事情。

您在设置带有属性ratingManyToMany关系方面做得很好,您的第二个查询将会工作,但很容易导致问题和可能的性能问题。

对于仅获取学生的情况,正确的查询可能是

代码语言:javascript
复制
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()));

这就给出了日志

代码语言:javascript
复制
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将生成一个额外的查询来获取课程信息,因为它没有被预取。你可以通过自己预取它来解决这个问题。

代码语言:javascript
复制
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()));

这就给出了日志

代码语言:javascript
复制
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)]

有一个问题是,你的学生只有部分课程评分。如果您尝试更新某个学生的评分,我认为您会导致其他课程评分丢失。对于你的用例来说可能不是问题,但你也可以通过学生列表获得课程:

代码语言:javascript
复制
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));

这将给出相同的结果,但查询略有不同,您可以更新学生的评分,而不会影响其他课程。

代码语言:javascript
复制
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)

如果您正在创建REST服务,这也会影响JSON格式化。在第一个实例中,您有一个包含一个条目的多个CourseRatings数组,而在第二个实例中,您只有一个包含评分和学生条目的CourseRatings数组。基本上,学生的部分列表和课程的部分列表并不能准确地表示您的数据库,而作为一门课程,它的学生列表是完整的。在这一点上,我不确定哪一个在SQL服务器上更有效,但是课程应该比学生少得多,所以如果你想让所有学生都上一门课程,这种方式可能更好。

对于JPA,您应该仔细检查SQL并测试用例。由于有很多学生,每个学生有几门课程,因此性能或内存开销可能值得考虑。还要注意,如果您一开始就没有在查询中使用fetch,那么结果可能会变得更加奇怪。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56760483

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档