Как сделать так, чтобы сессия NHibernate открывалась при начале запроса к веб-приложению и закрывалась, когда запрос обработан (паттерн OpenSessionInView). NHibernate работает в связке со Spring.NET.
Как привязать сессию NHibernate к запросу (ASP.NET) используя Spring.NET
Лучший ответ:
Нужно объявить в Web.config модуль OpenSessionInViewModule:
<httpModules>
<!-- ... -->
<add name="OpenSessionInView" type="Spring.Data.NHibernate.Support.OpenSessionInViewModule, Spring.Data.NHibernateXXX"/>
<!-- ... -->
</httpModules>
Вместо NHibernateXXX пишется актуальная версия NHibernate (например, Spring.Data.NHibernate20 для версии 2.0). Следует помнить, что сессия, которая открывается в начале запроса настроена только на чтение (FlushMode.NEVER) и если попытаться выполнить код типа:
public virtual void UpdateOrInsert(Entity entity)
{
HibernateTemplate.SaveOrUpdate(entity);
}
то получим исключение:
Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition
Есть два выхода из этой ситуации:
Установить FlushMode равное AUTO. Но так лучше не делать, потому что в этом случае результаты будут коммититься в базу уже после того, как пользователю вернулся ответ. То есть пользователя невозможно будет уведомить о результате операции.
Обернуть вызов метода DAO в транзакцию. Это можно сделать на уровне слоя доступа к данным или на уровне сервисов, декларативно или программно. Легче всего пометить метод репозитория атрибутом Transaction
:
[Transaction(ReadOnly = false)]
public virtual void UpdateOrInsert(Entity entity)
{
HibernateTemplate.SaveOrUpdate(entity);
}
Чтобы этот вариант заработал нужно включить строку импорта aop-объектов для автоматического распознования объектов с транзакциями:
<tx:attribute-driven transaction-manager="transactionManager"/>
или написать этот xml вручную:
<!-- The rest of the config file is common no matter how many objects you add -->
<!-- that you would like to have declarative tx management applied to -->
<object id="autoProxyCreator" type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator, Spring.Aop">
</object>
<object id="transactionAdvisor" type="Spring.Transaction.Interceptor.TransactionAttributeSourceAdvisor, Spring.Data">
<property name="TransactionInterceptor" ref="transactionInterceptor"/>
</object>
<!-- Transaction Interceptor -->
<object id="transactionInterceptor" type="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data">
<property name="TransactionManager" ref="transactionManager"/>
<property name="TransactionAttributeSource" ref="attributeTransactionAttributeSource"/>
</object>
<object id="attributeTransactionAttributeSource" type="Spring.Transaction.Interceptor.AttributesTransactionAttributeSource, Spring.Data">
</object>