JPQL:複合キーを使用してモデル化された多対多の関係を持つエンティティのクエリ

I.ドムシチコフ:

複合キーを使用して多対多を構築する方法のこの記事を読みましたエンティティは

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
}

ここで、特定のコースIDを持つ学生を取得したいとします。

私のJPQはどのように見えますか?

select s from Student s join fetch s.ratings r where r.id.courseId=:courserId

または

select s from Student s join fetch s.ratings r where r.course.id=:courserId

それともまったく違うのでしょうか?

K.ニコラス:

この種のJPAクエリでは、SQLを注意深くチェックする必要があります。おそらく、予想以上に多くのことが起こっているからです。

ManyToMany属性ratingとの関係を適切に設定すると、2番目のクエリは機能しますが、問題が発生し、パフォーマンスが低下する可能性があります。

学生だけを取得するための正しいクエリは

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)

RESTサービスを作成している場合、これはJSONフォーマットにも影響します。最初のインスタンスでは、1つのエントリを持つCourseRatingsの複数の配列があり、2番目のインスタンスでは、評価と学生のエントリを持つCourseRatingsの配列が1つだけあります。基本的に、コースの部分的なリストを持つ学生の部分的なリストは、学生の完全なリストを持つコースと同様に、データベースの正確な表現ではありません。この時点では、SQLサーバーでどちらが効率的かはわかりませんが、コース数は学生よりも少ないはずです。したがって、コースのすべての学生がコースを希望する場合は、おそらくこの方法のほうが良いでしょう。

JPAを使用する場合は、SQLを確認し、ユースケースを慎重にテストする必要があります。多くの学生がいて、学生ごとにいくつかのコースがあるため、パフォーマンスやメモリのオーバーヘッドは検討に値します。また、fetch最初にクエリで使用していなかった場合、結果がさらに奇妙になる可能性があることにも注意してください。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

1対多の関係を持つエンティティのシリアル化中に循環参照が検出されました

分類Dev

1つのエンティティが複合主キーを持っている場合のEntityFrameworkCoreの多対多の関係

分類Dev

1つのエンティティが複合主キーを持っている場合のEntityFrameworkCoreの多対多の関係

分類Dev

エンティティが1対多および多対多の関係を持つdynamodbのデータモデリング

分類Dev

カウント条件が満たされている多対多の関係を持つテーブルをクエリする方法

分類Dev

Entity Framework Code Firstを使用して、2つのエンティティ間に複数の1対多の関係を持たせる方法

分類Dev

多対多およびエンティティ間の関係を使用したCloudFirestoreスキーマの設計

分類Dev

双方向の関係を持つネストされたエンティティ(1対多)を永続化します

分類Dev

EF Core 5で、最初にクエリを実行せずに、外部キーIDのみを設定して、多対多の関係を持つエンティティを挿入するにはどうすればよいですか?

分類Dev

1対多の関係を持つエンティティを保存します

分類Dev

自動マッパーを使用して、多対多の関係を持つDTOを関係テーブルを持つEFコアエンティティにマップするにはどうすればよいですか?

分類Dev

多対多の関係を持つエンティティからオブジェクトを削除します

分類Dev

多対多の関係を持つルームデータベース:フィルタリングされたデータのクエリで単一のエントリを返します

分類Dev

1 対多の関係を持つ Django テーブルの関連フィールドのクエリ

分類Dev

SymfonyDoctrineクエリビルダーは多対1の関係を持つエンティティを検索します

分類Dev

SpringデータJPA-多対多の休止関係がリンクエンティティテーブルにnullを挿入しています

分類Dev

エンティティへのリンクなしで作成されたEFの多対多の関係

分類Dev

多対多の関係を持つJPQLクエリ

分類Dev

AutoMapperを使用して、関係テーブルの情報を多対多の関係テーブルのエンティティモデルクラスにマッピングする方法

分類Dev

JPA:JPQL、eclipselink、および複数のダウンキャストを使用して結合された継承を持つ多態性エンティティを選択します

分類Dev

java.lang.StackOverflowError多対多の関係を持つエンティティを更新する場合

分類Dev

双方向の関係を持つ、同じエンティティの多対多のコレクション

分類Dev

自分自身への多対多のリンクを持つリンクされたエンティティを取得しますか?

分類Dev

コードファーストを使用したエンティティフレームワークの複数の多対多の関係

分類Dev

自己多対多の関係を使用してEFのエンティティにDTOをマッパー

分類Dev

Doctrineは、結合テーブルを使用して1対多の単方向で1つのエンティティをクエリします

分類Dev

多対多のフィールドと中間テーブルを持つモデルのdjangoクエリセットでの不要な結合

分類Dev

複数のフィルターを使用した1対多の関係に対するSQLクエリ

分類Dev

MVC 5スキャフォールディングは、多対多の関係の選択リストを追加できませんか?(足場を追加-エンティティフレームワークを使用して、ビューを備えたMVC 5コントローラー)

Related 関連記事

  1. 1

    1対多の関係を持つエンティティのシリアル化中に循環参照が検出されました

  2. 2

    1つのエンティティが複合主キーを持っている場合のEntityFrameworkCoreの多対多の関係

  3. 3

    1つのエンティティが複合主キーを持っている場合のEntityFrameworkCoreの多対多の関係

  4. 4

    エンティティが1対多および多対多の関係を持つdynamodbのデータモデリング

  5. 5

    カウント条件が満たされている多対多の関係を持つテーブルをクエリする方法

  6. 6

    Entity Framework Code Firstを使用して、2つのエンティティ間に複数の1対多の関係を持たせる方法

  7. 7

    多対多およびエンティティ間の関係を使用したCloudFirestoreスキーマの設計

  8. 8

    双方向の関係を持つネストされたエンティティ(1対多)を永続化します

  9. 9

    EF Core 5で、最初にクエリを実行せずに、外部キーIDのみを設定して、多対多の関係を持つエンティティを挿入するにはどうすればよいですか?

  10. 10

    1対多の関係を持つエンティティを保存します

  11. 11

    自動マッパーを使用して、多対多の関係を持つDTOを関係テーブルを持つEFコアエンティティにマップするにはどうすればよいですか?

  12. 12

    多対多の関係を持つエンティティからオブジェクトを削除します

  13. 13

    多対多の関係を持つルームデータベース:フィルタリングされたデータのクエリで単一のエントリを返します

  14. 14

    1 対多の関係を持つ Django テーブルの関連フィールドのクエリ

  15. 15

    SymfonyDoctrineクエリビルダーは多対1の関係を持つエンティティを検索します

  16. 16

    SpringデータJPA-多対多の休止関係がリンクエンティティテーブルにnullを挿入しています

  17. 17

    エンティティへのリンクなしで作成されたEFの多対多の関係

  18. 18

    多対多の関係を持つJPQLクエリ

  19. 19

    AutoMapperを使用して、関係テーブルの情報を多対多の関係テーブルのエンティティモデルクラスにマッピングする方法

  20. 20

    JPA:JPQL、eclipselink、および複数のダウンキャストを使用して結合された継承を持つ多態性エンティティを選択します

  21. 21

    java.lang.StackOverflowError多対多の関係を持つエンティティを更新する場合

  22. 22

    双方向の関係を持つ、同じエンティティの多対多のコレクション

  23. 23

    自分自身への多対多のリンクを持つリンクされたエンティティを取得しますか?

  24. 24

    コードファーストを使用したエンティティフレームワークの複数の多対多の関係

  25. 25

    自己多対多の関係を使用してEFのエンティティにDTOをマッパー

  26. 26

    Doctrineは、結合テーブルを使用して1対多の単方向で1つのエンティティをクエリします

  27. 27

    多対多のフィールドと中間テーブルを持つモデルのdjangoクエリセットでの不要な結合

  28. 28

    複数のフィルターを使用した1対多の関係に対するSQLクエリ

  29. 29

    MVC 5スキャフォールディングは、多対多の関係の選択リストを追加できませんか?(足場を追加-エンティティフレームワークを使用して、ビューを備えたMVC 5コントローラー)

ホットタグ

アーカイブ