2014-01-07 1 views
2

Мне нужно загрузить список очень больших объектов с таким количеством детей и детей детей. Каков наилучший подход?Как легко загружать ассоциации без дублирования в NHibernate?

Я использую базу данных Oracle 11g и я написал ниже метод, но это приводит к декартову произведению (дублированные) Результаты:

public IList<ARNomination> GetByEventId(long eventId) 
     { 
      var session = this._sessionFactory.Session; 

      var nominationQuery = session.Query<ARNomination>().Where(n => n.Event.Id == eventId); 

      using (var trans = session.Transaction) 
      { 
       trans.Begin(); 

       // this will load the Contacts in one statement 
       nominationQuery 
        .FetchMany(n => n.Contacts) 
        .ToFuture(); 

       // this will load the CustomAttributes in one statement 
       nominationQuery 
        .FetchMany(n => n.CustomAttributes) 
        .ToFuture(); 

       // this will load the nominations but joins those two tables in one statement which results in cartesian product 
       nominationQuery 
        .FetchMany(n => n.CustomAttributes) 
        .FetchMany(n => n.Contacts) 
        .ToFuture(); 

       trans.Commit(); 
      } 

      return nominationQuery.ToList(); 
     } 
+0

Возможный дубликат [Как получить отличный результат с NHibernate и QueryOver API?] (HTTP: //stackoverflow.com/questions/4615675/how-to-get-a-distinct-result-with-nhibernate-and-queryover-api) – Sly

ответ

8

Получение Коллекции является сложной операцией. Он имеет много побочных эффектов (как вы поняли, когда есть дополнительные коллекции). Но даже при извлечении одной коллекции мы загружаем много дублированных строк.

В общем, для сбора коллекций я бы предложил использовать пакетную обработку. Это выполнит больше SQL-запросов ... но не так много, и что более важно, вы можете сделать подкачку в корневом списке ARNomination.

См. 19.1.5. Using batch fetching, вы можете найти более подробную информацию.

Вы должны пометить свои коллекции и/или объекты атрибутом batch-szie="25".

XML:

<bag name="Contacts" ... batch-size="25"> 
... 

свободно:

HasMany(x => x.Contacts) 
    ... 
    .BatchSize(25) 

Пожалуйста, проверьте несколько аргументов здесь:

+0

Мне нужно будет загрузить список очень больших объектов с таким количеством детей и детей детей. Каков наилучший подход? –

+0

Я рассказываю вам по моему опыту ... Я пробовал много способов ... но лучше всего просто использовать дозирование. Давайте подумаем об этом следующим образом: при пакетной обработке мы будем иметь все объекты light * (я имею в виду ссылки на списки и сущности лениво) *. Но как только нам понадобится список suchch ... сущность ... со многими связанными наборами atc .. 'batch-size' будет уменьшать количество запросов sql, в то время как мы все еще запрашиваем один * простой * объект. Я пробовал другие способы, выборки, не-ленивые ... и т. Д., Но в конце это ломает всю гибкость. Мы используем размер партии при отображении везде ...и у нас есть гибкость;) –

+0

Спасибо, у вас есть полный пример с дозированием с Fluent NHibernate? –

1

Я согласен с @ RadimKöhler, как только вы захотите загрузить более одной коллекции, тогда декартовый продукт всегда встречается. Для выбора подходящего размера партии я бы выбрал это так же, как и page size, поскольку он просто чувствует себя хорошо ... (нет доказательств, почему)

Существует еще один метод, который, по вашему мнению, лучше подходит и то есть прочитать этот блог post by Ayende, который покажет вам, как вы можете отправлять два будущих запроса одновременно, пытаясь загружать несколько коллекций, которые нужно выполнять для каждой коллекции.

Однако в зависимости от того маршрута вы берете, я предлагаю бросать профилировщика на результаты, чтобы увидеть, который работает лучше для вас ...

+0

Хорошая ссылка на сообщение Айенде. Размер страницы, я согласен, касается профилирования ... точно –