Hibernate は複数のバッグをフェッチすることを許可しません。これはデカルト積を生成するためです。また、Hibernate 用語でバッグと呼ばれる順序付けられていないリストの場合、基になるコレクションにそれらの重複した行がなくても、重複するエントリが発生します。そのため、Hibernate は、JPQL クエリがコンパイルされるときに、この状況を単純に防ぎます。
Set
これで、コレクションに の代わりにを使用するように指示する多くの回答、ブログ投稿、ビデオ、またはその他のリソースが見つかりますList
。
それはひどいアドバイスです。そうしないでください!
Sets
の代わりに使用Lists
するとMultipleBagFetchException
消えますが、デカルト積は引き続き存在します。
正しい修正
JOIN FETCH
単一の JPQL または Criteria API クエリで複数を使用する代わりに:
List<Post> posts = entityManager
.createQuery(
"select p " +
"from Post p " +
"left join fetch p.comments " +
"left join fetch p.tags " +
"where p.id between :minId and :maxId", Post.class)
.setParameter("minId", 1L)
.setParameter("maxId", 50L)
.getResultList();
次のトリックを実行できます。
List<Post> posts = entityManager
.createQuery(
"select distinct p " +
"from Post p " +
"left join fetch p.comments " +
"where p.id between :minId and :maxId ", Post.class)
.setParameter("minId", 1L)
.setParameter("maxId", 50L)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();
posts = entityManager
.createQuery(
"select distinct p " +
"from Post p " +
"left join fetch p.tags t " +
"where p in :posts ", Post.class)
.setParameter("posts", posts)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();
を使用して最大で 1 つのコレクションをフェッチする限り、JOIN FETCH
問題ありません。複数のクエリを使用することで、他のコレクションではなく最初のコレクションがセカンダリ クエリを使用してフェッチされるため、デカルト積を回避できます。