2010-11-06 2 views
1

Каков правильный способ ссылки на объекты, которые уже сохранялись в другом сеансе, но оставались неизменными в памяти после закрытия сеанса?Правильное обращение с переходными объектами в NHibernate

После того, как NH сохраняет объект за один сеанс, и этот сеанс закрыт, мне нужно снова его получить в новом сеансе, чтобы ссылаться на него в некоторых других переходных объектах. Или я могу позвонить Session.Lock в новый экземпляр сеанса и сообщить NH, что этот объект не является временным. Этот элемент никогда не должен меняться во время жизни приложения.

Каким будет предпочтительный способ использования? Есть ли другой способ сделать это?

[Редактировать]

Дополнительная проблема состоит в том, что я использую Repository паттерн, а не с помощью NH непосредственно в моем бизнес-уровне. Это означает, что мне также нужно иметь способ абстрагировать этот вызов с Session.Lock, то есть иметь метод, аналогичный Session.Lock в моем интерфейсе репозитория. Это немного вонючий ИМХО.

+0

Почему вы сохраняете объекты в памяти после закрытия сессии? Мне никогда не приходилось это делать. – Paco

+0

@Paco: Я создаю много новых объектов, которые ссылаются на существующие, уже сохранившиеся объекты. – Groo

+0

Я имею в виду, почему вы храните их в памяти вместо того, чтобы извлекать их из базы данных? Разве это не приведет к повреждению базы данных при сбое транзакции? – Paco

ответ

2

относительно первый вопрос. Если вы просто собираетесь читать сущность, вам не нужно ничего делать. Даже присвоение его в качестве поля для другого объекта не потребует блокировки записи. Единственная причина, по которой вам нужно позвонить ISession.Lock, - это когда вы хотите мутировать, а затем сохранять объект.

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

Если сущность по-прежнему создает проблемы в этих условиях, вы можете добавить Load в свой репозиторий. Вы можете подключить его к ISession.Load. То, что Load делает, создает пустой прокси для объекта без попадания в базу данных. Этот объект является частью сеанса, на который загружен объект, и может использоваться для назначения свойствам других объектов. Преимущество такого подхода состоит в том, что он намного чище, и его легко издеваться над модульным тестированием.

относительно второй вопрос. Да, вы правы, что пахнет интеграцией ISession.Lock в репозиторий. Опять же, когда вам не нужно мутировать сущность, вам не нужно беспокоиться об этом. Но, когда вы, ну, вы действительно должны думать о простое повторное загрузку объекта из репозитория и работу над ним. Я знаю, что это не так оптимально, как может быть, но это экономит вам очень странный код, особенно в ваших модульных тестах.

Последнее изделие. Я понимаю, что вы говорите об объекте, который будет жить в течение длительного времени (возможно, полной продолжительности работы приложения). У вас есть примерно три категории жизни: 1. навсегда, 2. длинные и 3. короткие. Причина, по которой я упоминаю об этом, заключается в том, что не один раз проблемы с сущностями, которые имеют «длительный» жизненный цикл, действительно могут оставаться подключенными к сеансу, который имеет одинаковое время жизни. Нет проблем, если сеанс будет активным, скажем, 5 или 10 минут (время ввода данных пользователем в форму). Это само по себе сэкономит большинству людей много неприятностей.

Еще одно примечание: посмотрите на NHibernateUtil и NHibernateProxyHelper. Эти классы могут помочь вам принудительно загрузить объекты и дочерние коллекции.

+0

Спасибо. Этот объект ** является ** долговечным (через всю жизнь приложения), и большинство новых объектов, которые будут сохранены, должны ссылаться на этот объект. Итак, всякий раз, когда я создаю новый сеанс для сохранения этих новых объектов, мне нужно сообщить NH, что этот объект уже сохранен - ​​в противном случае он жалуется, что это временный объект. – Groo

+0

Альтернативой является добавление методов 'Load' в ваши репозитории, в свою очередь, вызывать' Load' в сеансе. Затем вы можете загрузить объект в текущем сеансе по его идентификатору. Дело в 'Load' заключается в том, что оно не попадает в базу данных, а создает прокси только с идентификатором. Таким образом вы можете повторно извлечь объект, не извлекая его. При модульном тестировании это намного проще и чище подделать. Обновлен ответ. –

+0

Хорошо, кажется, я делал что-то неправильно, потому что вы правы: если я не изменяю сущность, и я назначаю ее другой сущности, мне не нужно ничего делать. – Groo

3

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

+0

Спасибо, это и аккуратная идея. У вас есть рекомендация, по которой я должен использовать поставщик кеша 2-го уровня? – Groo

+0

Если вы используете SQL Server, я бы начал с SysCache2, потому что он поддерживает SqlDependencies. Не то, чтобы я когда-либо нуждался в этой функции. –

+0

Прошло некоторое время с момента последней реакции, но я просто хотел бы сказать, что SysCache2 является удивительным, но также и то, что кэширование второго уровня - довольно неясно, когда дело доходит до документации. Один большой совет: если вы настроили VS правильно, вы можете отлаживать NH, который действительно может быть просвещен, если вы не знаете, что происходит: http://www.symbolsource.org/Public/Home/VisualStudio –

Смежные вопросы