2 に答える
熱心な読み込みとフェッチ結合には違いがあります。一括読み込みとは、データが同じクエリ内で読み込まれるという意味ではありません。追加のクエリによってではありますが、すぐにロードされることを意味します。
条件は常に SQL クエリに変換されます。結合を指定すると、SQL での結合になります。SQL の性質上、これによりルート エンティティのデータも乗算され、得られる効果につながります。(同じインスタンスを複数回取得するため、ルート エンティティはメモリ内で乗算されないことに注意してください。)
それにはいくつかの解決策があります:
- 使用する
distinct(true)
- 個別のルート エンティティ トランスフォーマー (
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
) を使用します。 - 子プロパティでフィルタリングする必要がない場合は、結合を避けてください
- 子プロパティでフィルタリングする必要がある場合は、サブクエリ (
DetachedCriteria
) でフィルタリングします。 - バッチサイズを使用して N+1 問題を最適化する
distinct(true)
CriteriaQueryを呼び出してみましたか?
161ページのJPA2仕様には、次のように記載されています。
DISTINCTキーワードは、クエリ結果から重複する値を削除する必要があることを指定するために使用されます。
DISTINCTが指定されていない場合、重複する値は削除されません。
javadocにも次のように書かれています。
重複するクエリ結果を削除するかどうかを指定します。真の値を指定すると、重複が削除されます。値がfalseの場合、重複が保持されます。個別が指定されていない場合は、重複した結果を保持する必要があります。
アソシエーションが熱心にロードされるときに個別が必要ない理由は、おそらく、アソシエーションがフェッチ結合を使用してロードされるのではなく、追加のクエリを使用してロードされるためです。