Критерии стремления к сборке с объединением выборки, чтобы избежать выбора n + 1

Допустим, Предмет и Ставка - это сущности: Предмет имеет много Ставок. Они отображаются в 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();                        

person Camilo Silva    schedule 08.10.2012    source источник
comment
stackoverflow.com/questions/617145/ Я думаю, его спрашивали раньше ....   -  person Hayati Guvence    schedule 09.10.2012


Ответы (4)


Этот критерий запроса кажется правильным:

  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();
person Yogendra Singh    schedule 08.10.2012

Это объяснение того, почему добавление ограничения для коллекции, присоединенной к выборке, приводит к тому, что коллекция не была инициализирована (обратите внимание, что тот же запрос без ограничения вызывает активную выборку для коллекции):

"Если у вас есть отношение 1: n между таблицами A и B, и вы добавляете ограничение к B и хотите быстро получить A и B, то возникает вопрос, что произойдет, когда вы захотите перейти от A к B. видеть только те данные в B, которые соответствуют ограничению, или вы должны видеть все B, которые связаны с A? " подробнее здесь ...

Однако, используя 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();

Это связанные сообщения: Запрос гибернации не возвращает полный объект.

person Camilo Silva    schedule 09.10.2012

Я думаю, что вам нужен критерий, который использует подзапрос, существующий для другого критерия. Аналогичный ответ находится здесь: 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"))));
person Jeff Sheets    schedule 02.04.2013

Попробуйте этот код. Это решило мою проблему.

List<Item> items = session.createCriteria(Item.class)
                .setFetchMode("bids", FetchMode.SELECT)
                .createAlias("bids", "b")
                .add(Restrictions.gt("b.amount", 100))
                .list();
person Barış Özdemir    schedule 12.03.2018