Наше приложение имеет концепцию истории и концепцию теги . К истории может быть применено множество тегов, а тег может быть применен ко многим историям, что делает отношения многие ко многим. Две таблицы, истории и теги соединены с третьим, StoriesToTags .
Соответствующие части файлов сопоставления:
Вот отображение из Story в Tag :
<class name="Story" table="Stories">
...
<set fetch="subselect" name="Tags" table="StoriesToTags">
<key>
<column name="StoryId" />
</key>
<many-to-many class="Tag">
<column name="TagId" />
</many-to-many>
</set>
</class>
И обратная зависимость от Метка до История :
<class name="Tag" table="Tags">
...
<set fetch="subselect" inverse="true" name="Stories" table="StoriesToTags">
<key>
<column name="TagId" />
</key>
<many-to-many class="Story">
<column name="StoryId" />
</many-to-many>
</set>
</class>
Как видите, мы используем стратегию выборки subselect , чтобы избежать проблемы запроса N + 1. Все отлично работает, пока вы не попытаетесь отобразить результат с помощью LINQ:
IQueryable<Story> stories = GetStories(...).TakePage(pageNumber, pageSize);
После выполнения этого запроса NHibernate удаляет отношения (записи в StoriesToTags ) для всех историй, которые не были загружены в запросе. Кажется, что это происходит только в том случае, если теги загружены специально (то есть подзапуск срабатывает). Отношения не удаляются, если мы переключаемся на присоединение или выбор стратегии выборки, но это приводит к выполнению N + 1 запросов.
Мое лучшее предположение заключается в том, что NHibernate считает, что теги были осиротевшими, но мы не установили каскадов в коллекциях. Кроме того, насколько я могу судить, установка каскада не имеет никакого эффекта.
Этот процесс прекрасно работал под NHibernate 2.x и NHibernate.Linq. Мы не видели проблемы с удалением, пока не перешли на NHibernate 3.x, в который встроена поддержка LINQ. Я не уверен, что это что-то меняет, но для этого мы используем SQL Server с ключами идентификации.
Есть мысли? Сначала я думал, что делаю что-то безумно глупое, но я пробовал в основном каждую перестановку сопоставления, и мы не можем устранить эту проблему.
Редактировать: Еще одна интересная информация. Если вы позвоните session.IsDirty()
до закрытия сеанса, проблема не возникнет. Я подозреваю, что это потому, что изменения коллекции не сохраняются между сбросами, но я не могу достаточно хорошо расшифровать источник NHibernate, чтобы знать наверняка.