Стремитесь загружать дочерние коллекции с помощью Future и HQL - PullRequest
1 голос
/ 15 декабря 2011

Я пытаюсь загрузить дочернюю коллекцию дочерней сущности, которую выбираю. Я пытаюсь имитировать таким образом , делая в основном два будущих запроса и затем перечисляя один из них. Это должно привести к двум запросам к базе данных:

var idd = session.CreateQuery("from ItemDeliveryDetail idd " + 
                              "join fetch idd.ItemDelivery " +
                              "left join fetch idd.SupplierInvoice " +
                              "where idd.Id = 21931828")
                 .Future<ItemDeliveryDetail>();

var spc = session.CreateQuery("from SpecialCondition spc " +
                              "where spc.ItemDelivery " +
                              "in (select idd.ItemDelivery " +
                                  "from ItemDeliveryDetail idd " +
                                  "where idd.Id = 21931828)")
                 .Future<SpecialCondition>();

var result = idd.ToList();

Последняя строка действительно приводит к двум запросам к базе данных. Запросы - именно то, что я ожидаю (они довольно длинные, и я не думаю, что они имеют отношение к вопросу, но если вы хотите их видеть, я вставил их здесь ).

Проблема в том, что результаты этих двух запросов не объединены, т. Е. Следующее перечисление будет все еще запрашивать базу данных для SpecialCondition s каждого ItemDelivery:

foreach (var itemDeliveryDetail in result)
{
    foreach (var specialCondition in itemDeliveryDetail.ItemDelivery
                                                       .SpecialConditions)
    {
        // Do something
    }
}

Как это исправить?

Ответы [ 3 ]

1 голос
/ 15 декабря 2011

Ваш второй запрос не загружает коллекции ItemDelivery.SpecialConditions; только неиспользованный список специальных условий.

Я согласен с Rippo в том, что использование batch-size обычно чище и эффективнее, , даже если это приводит к одной или двум дополнительным поездкам .

Тем не менее, ваш второй запрос должен быть:

var spc = session.CreateQuery("from ItemDelivery id " +
                              "join fetch id.SpecialCondition "
                              "where id in (select idd.ItemDelivery " +
                                           "from ItemDeliveryDetail idd " +
                                           "where idd.Id = 21931828)"
             .Future<ItemDelivery>();
1 голос
/ 15 декабря 2011

Один быстрый выигрыш может заключаться в добавлении batch-size=50 к отображению сумок между ItemDelivery и SpecialConditions.

Однако я предлагаю вам прочитать этот блог " Горячая загрузка ассоциаций объектовэффективно с сообщением NHibernate"от Ayende, поскольку оно может дать вам ответ, который вы ищете.

Вы столкнулись с классической проблемой выбора n + 1 здесь.Я предпочел бы иметь 1 или, может быть, еще 2 поездки в базу данных, а не большой cartesian product набор результатов.Я уверен, что это будет самый эффективный маршрут.

0 голосов
/ 15 декабря 2011

Вам нужно использовать один и тот же базовый запрос дважды, что, по моему мнению, является вашей проблемой.

var idd = session.CreateQuery("from ItemDeliveryDetail idd " + 
                          "join fetch idd.ItemDelivery " +
                          "left join fetch idd.SupplierInvoice " +
                          "where idd.Id = 21931828")
             .Future<ItemDeliveryDetail>();

var spc = session.CreateQuery("from ItemDeliveryDetail idd " + 
                          "join fetch idd.ItemDelivery id " +
                          "join fetch id.SpecialCondition spc " +
                         "where idd.Id = 21931828")
             .Future<ItemDeliveryDetail>();

var result = idd.ToList();

Да, я понимаю, что это может привести к декартовому произведению для вас, но я успешно справился с этой техникой.

...