NHibernate всегда увлажняет много-к-одному

Я испытываю что-то странное при использовании NHibernate. Я открыл кодовую базу, которую не написал, а того, кто сделал, больше нет. Поэтому я думаю, что я ищу больше советов по отладке, чем что-либо еще.

Я использую провайдера NHIbernate 3.4 Linq для запроса объекта, который имеет отношение "многие к одному" с другим объектом.

То, что я вижу, это то, что я никогда не получаю доступ к свойству, которое представляет отношение "многие к одному", оно всегда гидратировано. Просматривая запросы через профилировщик NHibernate, я могу видеть, что свойство загружается с отложенной загрузкой. Устанавливая точки останова с помощью моего отладчика, я вижу, что свойство никогда не доступно.

При использовании профилировщика NHibernate я вижу, что это происходит, когда я загружаю список родительских объектов, но не в том же запросе.

Я понятия не имею, почему это происходит, но это приводит к проблеме N+1.

Объекты определены в файлах hbm.xml.

Итак, что я прошу, так это ввод туда, где я должен начать копать. Я чувствую, что уже перепробовал все, что могу придумать.

1 ответ

Решение

Я бы почти наверняка сказал, что проблема не в NHibernate, она в стороне от использования (мы оба согласились бы, я бы сказал)

Итак, что мы должны иметь (неявное или явное) в качестве отправной точки - это ленивый параметр:

// class level
// by default lazy is turned on
<class name="Entity" ... lazy="true" ... >
   ...

// reference many-to-one level, also by default lazy
<many-to-one name="Entity" lazy="proxy" ... />

Чтобы избежать N+1, мы должны быть уверены, что мы используем пакетную выборку с batch-size настройки, смотрите больше здесь

// class/entity level
// ATTENTION - this is not implicit, we have to define that
<class name="Entity" ... lazy="true" ... batch-size="25" >
  ...

// collection level
// ATTENTION - this is not implicit, we have to define that
<bag name="Entities" ... batch-size="25">
...

Имея это на своем месте, теперь NHibernate сам никогда не будет загружать больше, чем нужно. Итак, что может быть типичным случаем использования, когда необходимо загрузить ссылку?

При переопределении:

public override bool Equals(object obj)
{
}
public override int GetHashCode()
{
}

Эти методы должны быть (иногда - для составного идентификатора, даже должны быть) переопределены, чтобы обеспечить бизнес-уникальный ключ. Убедитесь, что любое из упомянутых значений не используется для такого сравнения (например, комбинация Country и Office уникальна для некоторого OtherEntity)

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

Это на удивление самый частый источник "принудительной" загрузки. Итак, очистите ваших наблюдателей...

Наконец, предложение - создать модульный тест для загрузки только корневого объекта. Чистая сессия в конце. Наблюдайте (с помощью профилировщика), если был какой-то удар по БД. Вы можете легче проверить, в чем причина...

Другие вопросы по тегам