Как улучшить производительность Nhibernate для разбитых на страницы запросов по графу объектов - PullRequest
0 голосов
/ 28 марта 2012

NHibernate может загрузить весь объект и связанные объекты за один удар по дб через подсказки в отображении, если вы не используете разбитый на страницы запрос.Однако, если вы используете пейджинг, он делает большое количество вызовов в БД.

Например, у меня есть объект Invoice и объект InvoiceLine, так что счет-фактура имеет счет-фактуру Listлиний.Свободное отображение Invoice:

HasMany(x => x.Lines)
    .Table("InvoiceLine")
    .KeyColumn("InvoiceId")
    .Fetch.Join()
    .Not.LazyLoad();

Опция Not.LazyLoad прекрасно работает для загрузки всего графа объектов в одном обращении к базе данных при загрузке одного счета-фактуры ... но если я хочу выполнить запрос с разбивкой по страницамкак

_invoiceQuery.Skip(200).Take(100);

Затем NHibernate сначала загружает все 100 счетов-фактур за одно нажатие ... и затем еще 100 раз обращается к базе данных для строк счетов-фактур каждого счета-фактуры по одному.

Есть ли способ уменьшить это до 2 попаданий, например

  1. Загрузить счета
  2. Загрузить ВСЕ строки счетов-фактур для счетов в (1)?

Я попытался вручную форсировать проблему, загрузив список требуемых идентификаторов счетов-фактур в запрос, а затем используя

_invoiceQuery.Where(x => requiredIds.Contains(x.Id));

, но кажется, что NHibernate имеет ту же проблему при уменьшении ограничения Contains в SQL.

... или я должен признать, что мне нужно использовать другой инструмент?

1 Ответ

0 голосов
/ 28 марта 2012

По моему опыту, NHibernate не очень хорош при использовании постраничных списков с активной загрузкой.Имейте в виду, что в конечном итоге ваши запросы выполняются как TSQL, возвращая набор строк объединенных данных.Теперь NHibernate способен преобразовывать эти данные обратно в корневые объекты и связанные с ними дочерние элементы.Проблема в том, как NHibernate мог знать, пока после не вернул из БД, сколько строк ему нужно указать в предложении TOP для получения необходимого количества корневых сущностей?

Аналогичным образом рассмотрим ситуацию принудительного объединения с использованием Session.QueryOver и Left.JoinAlias.Вы можете указать количество строк для извлечения, но это просто: строк , а не сущностей

Как правило, я буду решать вашу ситуацию аналогично тому, каку вас есть - с помощью двух запросов.Можете ли вы опубликовать немного больше кода?Вот несколько способов сделать это:

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

  2. Создайте начальный запрос, возвращающий указанные 100 счетов (lazyload invoicelines), затем в отдельном обращении извлекайте invoicelines, где invoiceID содержится в идентификаторах первого списка.Вы должны иметь возможность дважды обратиться к базе данных и объединить родительские / дочерние объекты в коде позади.Будьте немного осторожны с объединенными вручную сущностями, хотя - если вы намереваетесь сделать какой-либо CRUD, возможно, стоит сначала получить отдельную сущность из базы данных

Если вы просто заинтересованы всообщая о представлении данных (то есть об отсутствии операций CUD), возможно, вместо этого стоит рассмотреть сопоставление с пользовательским представлением БД

...