Может ли NHibernate решить N+1 без использования пакетной обработки или Criteria API для отношений Заказ -> Клиент?
Я читал и смотрел вокруг, чтобы найти этот ответ в черно-белом.
Давайте поговорим о знакомых
Customer
а такжеOrder
проблема. Допустим, я загружаю 100 заказов, и каждый заказ связан с одним и только одним клиентом.
Используя Fluent NHibernate, я буду использовать References()
связать мой Order
в Customer
и я определю мой Not.LazyLoad()
а также Fetch.Join()
также.
Теперь я думаю гипотетически, NHibernate может просто объединить эти две таблицы и будет довольно легко гидрировать сущности. Однако в моих тестах я всегда вижу скорее N+1 запросов (на самом деле, возможно, только уникальные идентификаторы). Я могу поделиться своим кодом и таблицами, но это может утомить вас, поэтому
- Можно ли преодолеть N+1 для заказа-> клиента (один-> один или, вернее, много-> один)? Или я должен использовать пакетный или Criteria API?
- Если это возможно, не могли бы вы указать мне на свободный пример NHibernate?
4 ответа
Часто есть жалоба, что fetch="join" не работает. Это потому, что это не рассматривается HQL. Вы можете объявить это в HQL.
Я использовал fetch="join", надеясь улучшить производительность, но во многих случаях перестал ее использовать. Проблема заключалась в том, что при соединении со многими таблицами SQL-сервер мог работать с максимальным количеством столбцов. В некоторых случаях вам вообще не нужны данные, и поэтому не очень полезно указывать их глобально в файле отображения.
Поэтому я бы порекомендовал
- либо используйте явное извлечение соединения в HQL, потому что там вы знаете, действительно ли используются данные.
- или для любого другого случая, пакеты являются отличным решением, потому что они прозрачны (ваш код не должен знать), используют ленивую загрузку и одновременно уменьшают проблему N+1.
Привет
Есть два способа решения вашей проблемы
а) Использование критерия запроса Это будет выглядеть примерно так
Session.CreateQuery(typeof(Order))
.Add(<Restrictions if any>)
.SetFetchMode("Customer",FetchMode.Eager)
.List<Order>();
б) Использование HQL
Session.CreateQuery("select o from Order inner join fetch o.Customer where <conditionifany>").List<Order>();
Надеюсь это поможет..
Я бы не смотрел на отображение так же, как на фактические запросы, которые вы делаете. Я оставляю ВСЕ мои сопоставления как LazyLoad по умолчанию и перезаписываю при необходимости.
Я использую Criteria API для запросов и использую CreateAlias для объединения других таблиц по мере необходимости. NHProf настоятельно рекомендуется найти и устранить подобные ситуации.
Какой API запросов вы используете?
Если это HQL, вы можете использовать join fetch
чтобы получить ассоциацию с нетерпением.
Для LINQ и QueryOver используйте .Fetch()