5

Hibernate を使用して、テーブルから約 1 億行を取得しようとしています。内部に料金のコレクションを含む永続エンティティ Item があります (別の永続エンティティ)。結果を反復処理してすべてのオブジェクトの料金にアクセスすることを考えると、n+1 の問題を回避するために熱心に料金を取得したいと考えています。

また、これを Provider という別のテーブルに結合したいことにも言及する必要があります (1 対 1 のマッピングですが、外部キーはありません)。私は試した:

String query = "select new " + Order.class.getName() 
           + "(i, p) from Item i left join fetch i.fees f, Provider p where "
           + "p.factoryId=i.factoryId and p.factoryRef=i.factoryRef";

return session.createQuery(query).scroll();

私の Order クラスには、Provider フィールドと Item フィールドが含まれています。次のエラーが表示されます。

原因: org.hibernate.QueryException: クエリは結合フェッチを指定しましたが、フェッチされた関連付けの所有者が選択リストに存在しませんでした

私はアイテム(熱心に取り出された料金で)とプロバイダーを含む注文のスクロール可能なリストになりたいと思います。

4

2 に答える 2

1

からのこのコードSelectClauseはあなたに問題を引き起こします:

if ( !fromElementsForLoad.contains( origin ) ) {
                        throw new QueryException(
                                "query specified join fetching, but the owner " +
                                "of the fetched association was not present in the select list " +
                                "[" + fromElement.getDisplayText() + "]"
                        );

ご覧のとおり、fetch キーワードが指定されると、hibernate は fetch 装飾フィールドの親を要求したかどうかを確認します。fromElementsForLoad.contains( origin )

彼らはおそらく、パフォーマンスを大幅に犠牲にする冗長な結合を行うことからあなたを守るためにそれを行ったのでしょう. アソシエーションを使用しない場合は、アソシエーションを取得する理由がないため、これは良いことです。

あなたの場合Item.class、 new でラップするOrder.classと、クエリで装飾されたフェッチフィールドの親を使用しているという事実が隠されていると思います。

現時点ではデバッグ能力がないため、これを検証できません。SelectClause.class からこの正確な行を試してデバッグし、fromElementsForLoadコレクションが保持する要素を確認してください。

n+1 の問題を回避したい場合は、クエリの後に Order.class を初期化することをお勧めします。Item と Provider のみを選択できます。

これを検証できない場合は、来週適切なコンピューターにアクセスして、回答を拡大します.

于 2012-08-11T10:04:56.037 に答える
0

を削除してleft join fetch i.fees f、マッピングで熱心なフェッチを実行してみてください。

于 2012-08-11T06:11:45.200 に答える