13

Item と Bid がエンティティであるとしましょう。Item には多くの入札があります。それらは、典型的な親子関係でHibernateにマッピングされます。

<class name="Item" table="ITEM">
  ...
  <set name="bids" inverse="true">
    <key column="ITEM_ID"/>
    <one-to-many class="Bid"/>
  </set>
</class>

このクエリの実行後に各アイテムの入札にアクセスしようとするときに n+1 選択を回避するにはどうすればよいですか?

List<Item> items = session.createCriteria(Item.class)
                        .createAlias("bids", "b").
                        .add(Restrictions.gt("b.amount", 100)).
                        .list();

入札には熱心なフェッチが必要ですが、コレクションにはさらに制限があります( b.amount > 100)

私は次のことを試みましたが失敗しました:

List<Item> items = session.createCriteria(Item.class)
                        .setFetchMode("bids", FetchMode.JOIN).
                        .createAlias("bids", "b").
                        .add(Restrictions.gt("b.amount", 100)).
                        .list();                        

List<Item> items = session.createCriteria(Item.class)
                        .createCriteria("bids")
                        .add(Restrictions.gt("amount", 100)).
                        .list();                        
4

4 に答える 4

11

この基準クエリは正しいようです:

  List<Item> items = session.createCriteria(Item.class)
                    .setFetchMode("bids", FetchMode.JOIN)
                    .createAlias("bids", "b")
                    .add(Restrictions.gt("b.amount", 100))
                    .list();

FetchMode.JOIN問題を解決するためのものn+1です。いくつか定義しましたか default_batch_fetch_size| batch-size逆に影響を与えるマッピングまたは構成のどこか?

そうでない場合は、以下の HQL を試してみて、これで問題が解決することを確認できますか?

 Query query = 
      session.createQuery("from Item it left join it.bids b where b.amount=:bids");
 query.setParamter(bids, 100);
 List<Item> items = query.list();
于 2012-10-08T22:25:50.610 に答える
6

これは、フェッチ結合されたコレクションに制限を追加するとコレクションが初期化されない理由の説明です (制限のない同じクエリがコレクションの熱心なフェッチを生成することに注意してください)。

「テーブル A と B の間に 1:n の関係があり、B に制限を追加して、A と B を熱心に取得したい場合、問題は、A から B に移動したいときに何が起こるかということです。制限に一致する B のデータのみを表示しますか?それとも、A に関連するすべての B を表示する必要がありますか?」ここでもっと見る...

ただし、条件の代わりに HQL を使用して、入札コレクションを部分的にフェッチします。

List<Item> items = session.createQuery(
          "from Item i left join fetch i.bids b where b.amount > :amount")
          .setParameter("amount", 100)
          .list();

私には矛盾しているように見えますが、これがどのように機能するかです

ちなみに、親とそのすべての子のリストが必要であるが、特定の制限を満たす子を持つ親のみが必要な場合は、これを使用できます。

List<Item> items = session.createQuery(
          "from Item i left join fetch i.bids b " +
          "where not exists (from Bid b where b.item = i and b.amount <= :amount)")
          .setParameter("amount", 100)
          .list();

これは関連記事です: Hibernate query not return full object .

于 2012-10-09T15:15:28.070 に答える
2

必要なのは、別の基準でサブクエリが存在する基準を使用することだと思います。同様の回答がここにあります: https://stackoverflow.com/a/15768089/1469525

DetachedCriteria criteria = session.createCriteria(Item.class, "i");
criteria.setFetchMode("bids", FetchMode.JOIN);

DetachedCriteria bidCriteria = DetachedCriteria.forClass(Bid.class, "b");
bidCriteria.add(Restrictions.gt("amount", 100));
bidCriteria.add(Restrictions.eqProperty("b.itemId", "i.id"));
criteria.add(Subqueries.exists(bidCriteria.setProjection(Projections.property("b.id"))));
于 2013-04-02T15:44:49.100 に答える