Как добиться загрузки ассоциаций без дублирования в 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();
}
2 ответа
Получение коллекций - сложная операция. У него много побочных эффектов (как вы поняли, когда собрано больше коллекций). Но даже при получении одной коллекции мы загружаем много дублированных строк.
В общем, для загрузки коллекций я бы предложил использовать пакетную обработку. Это выполнит больше запросов SQL... но не так много, и, что более важно, вы можете сделать пейджинг в корневом списке ARNomination
,
Смотри: 19.1.5. Используя пакетную загрузку, вы можете найти более подробную информацию.
Вы должны пометить свои коллекции и / или объекты с атрибутом batch-szie="25"
,
XML:
<bag name="Contacts" ... batch-size="25">
...
свободно:
HasMany(x => x.Contacts)
...
.BatchSize(25)
Пожалуйста, проверьте несколько аргументов здесь:
Я согласен с @RadimKöhler, как только вы захотите загрузить более одной коллекции, тогда всегда возникает декартово произведение. Для выбора подходящего размера партии я бы выбрал такой же, как page size
как он чувствует себя хорошо... (нет доказательств, почему, хотя)
Есть еще один метод, который вам может показаться более подходящим, - прочитать это сообщение в блоге Ayende, в котором показано, как можно отправлять два будущих запроса одновременно, чтобы быстро загружать несколько коллекций. Задачей души является загрузка каждой коллекции отдельно.,
Независимо от того, какой путь вы выберете, я предлагаю добавить профилировщик результатов, чтобы увидеть, какой из них лучше для вас...