Проблема запроса Nhibernate N + 1 - PullRequest
1 голос
/ 30 октября 2009

Мне нужна помощь с NHibernate. Я использую 2.1, но уже пробовал это на 3, с теми же результатами. Любая помощь наиболее ценится!

При выполнении запроса ICriteria с использованием NHibernate он выполняет оба запроса, а затем для каждого результата в запросе выполняет другой запрос, чтобы выбрать связанный объект, который уже возвращается в исходном наборе результатов, так как я использую нетерпеливую загрузку. , Это, конечно, приводит к мрачным результатам. Используя приведенный ниже файл сопоставления, запрос, сгенерированный Nhibernate, в точности соответствует приведенному ниже:

exec sp_executesql N'SELECT top 20 this_.ContactCode as ContactC1_48_1_, this_.IsActive as IsActive48_1_, contact2_.ContactCode as ContactC1_47_0_, contact2_.ContactFullName as ContactF2_47_0_ FROM Clients this_ left outer join Contacts contact2_ on this_.ContactCode=contact2_.ContactCode WHERE this_.ContactCode like @p0 and this_.IsActive = @p1 ORDER BY this_.ContactCode asc',N'@p0 nvarchar(7),@p1 bit',@p0=N'DAL001%',@p1=1

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

exec sp_executesql N'SELECT contact0_.ContactCode as ContactC1_47_0_, contact0_.ContactFullName as ContactF2_47_0_ FROM Contacts contact0_ WHERE contact0_.ContactCode=@p0',N'@p0 nvarchar(6)',@p0=N'DAL001'

Ленивая загрузка отключена. Код ICriteria выглядит следующим образом:

            ICriteria clientsFromContactCodeQuery = session.CreateCriteria<Client>()
                .Add(Restrictions.Like("ContactCode", id + "%"))
                .Add(Restrictions.Eq("IsActive", true))
                .AddOrder(Order.Asc("ContactCode"))
                .SetMaxResults(maxResultCount);

            var clientsFromContactCodeList = clientsFromContactCodeQuery.List();

У меня есть простой файл отображения nhibernate:

  <class name="Contact" table="Contacts" lazy="false">
    <id name="ContactCode">
      <generator class="assigned" />
    </id>

    <property name="ContactFullName" />
  </class>

  <class name="Client" table="Clients" lazy="false">
    <id name="ContactCode">
      <generator class="assigned" />
    </id>

    <property name="IsActive" />

    <one-to-one
            name="Contact"
            class="Contact"
            lazy="false"
            fetch="join"
    />

  </class>

Ответы [ 3 ]

2 голосов
/ 30 октября 2009

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

from Client c 
  left join fetch c.Contact 
where 
  c.ContactCode like :id 
and 
  c.IsActive eq true

Я не знаю порядок по синтаксису на макушке, и HQL, возможно, придется немного подправить, но это ядро ​​решения.

0 голосов
/ 30 октября 2009

Самое странное, что после различных изменений в запросе, от hql до icriteria, ничего не получалось. Однако я заметил некоторые данные, где N + 1 запросы не генерировались. Оказывается, что первичные ключи в таблице контактов и клиентов имеют ПРОСТРАНСТВА в конце, что при удалении решило проблему!

Очень странно, но спасибо за помощь.

0 голосов
/ 30 октября 2009

Попробуйте установить для свойства max_fetch_depth значение 2 или 3, если это не так Не уверен, что это работает с отношениями один-к-одному.

<property name="max_fetch_depth">3</property>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...