Проблема NHibernate TransactionScope с Oracle 11g

Следующий фрагмент кода отлично работает с SQL Server 2008 (SP1), но с Oracle 11g при вызове session.BeginTransaction() выдает исключение с сообщением "Соединение уже является частью локальной или распределенной транзакции" (трассировка стека показана ниже), Использование "NHibernate.Driver.OracleDataClientDriver".

Кто-нибудь еще сталкивался с этим?

using (var scope = new TransactionScope())
{
   using (var session = sessionFactory.OpenSession())
   using (var transaction = session.BeginTransaction())
   {
      // do what you need to do with the session
      transaction.Commit();
    }
    scope.Complete();
}
     Исключение в: в NHibernate.Transaction.AdoTransaction.Begin(IsolationLevel изоляция Level)
           в NHibernate.Transaction.AdoTransaction.Begin()
           в NHibernate.AdoNet.ConnectionManager.BeginTransaction()
           в NHibernate.Impl.SessionImpl.BeginTransaction()
           в MetraTech.BusinessEntity.DataAccess.Persistence.StandardRepository.SaveInstances(List`1& dataObjects) в S:\MetraTech\BusinessEntity\DataAccess\Persistence\StandardRepository.cs: строка 3103

        Внутреннее сообщение об ошибке было: Соединение уже является частью локальной или распределенной транзакции
        Внутреннее исключение по адресу: в Oracle.DataAccess.Client.OracleConnection.BeginTransaction(IsolationLevel изоляция Level)
           в Oracle.DataAccess.Client.OracleConnection.BeginDbTransaction(IsolationLevel изоляция Level)
           в System.Data.Common.DbConnection.System.Data.IDbConnection.BeginTransaction()
           в NHibernate.Transaction.AdoTransaction.Begin(IsolationLevel изоляция Level)

4 ответа

Проблема с использованием только области транзакции описана здесь: NHibernate FlushMode Auto не очищается перед поиском

Похоже, что nhibernate (v3.1 с оракул диалект и 11g дБ w/opd.net v2.112.1.2) требует своих собственных транзакций, чтобы избежать проблемы сброса, но я не смог получить объем транзакции для работы с nhibernate сделки.

Я не могу заставить его работать:(это может быть дефект в nhibernate или odp.net, не уверен...

обнаружил ту же проблему здесь: NHibernate 3.0: TransactionScope и Auto-Flushing

ИСПРАВЛЕНО: найдено решение! поставив "enlist=dynamic;" в мою строку соединения оракула проблема была решена. Мне удалось использовать как транзакцию nhibernate (чтобы исправить проблему сброса), так и объем транзакции, например, так:

        ISessionFactory sessionFactory = CreateSessionFactory();

        using (TransactionScope ts = new TransactionScope())
        {
            using (ISession session = sessionFactory.OpenSession())
            using (ITransaction tx = session.BeginTransaction())
            {
                //do stuff here

                tx.Commit();

            }
            ts.Complete();
        }

Я проверил свои файлы журналов и нашел это: 2011-06-27 14:03:59,852 [10] DEBUG NHibernate.Impl.AbstractSessionImpl - зачислен в транзакцию DTC: Сериализуемый

до того, как какой-либо SQL был выполнен в соединении. Я проведу модульное тестирование, чтобы подтвердить правильность выполнения. Я не слишком уверен, что сериализуемый говорит мне, хотя

Ответ Брэда с использованием внешнего TransactionScope и внутренней транзакции NHibernate с enlist=dynamic, похоже, не работает должным образом. Хорошо, данные передаются.

Но если вы опустите scope.Complete() или создадите исключение после tx.Commit(), данные все равно будут зафиксированы (для Oracle)! Однако по какой-то причине это работает для SQL-Server.

Транзакции NHibernate заботятся об автоматической очистке, но в конце они вызывают основную транзакцию ADO.NET. В то время как многие источники рекомендуют использовать вышеупомянутый шаблон в качестве наилучшей практики для решения проблемы автоматического сброса NHibernate, источники, обсуждающие нативный ADO.NET, говорят об обратном: НЕ используйте TransactionScope и внутренние транзакции вместе, не для Oracle и не для SQL-Server. (См. Этот вопрос и мой ответ)

Мой вывод: не объединяйте транзакции TransactionScope и NHibernate. Чтобы использовать TransactionScope, пропустите транзакции NHibernate и обработайте сброс вручную (см. Также документ NHibernate Flush).

Из поваренной книги NHibernate

Помните, что NHibernate требует транзакции NHibernate при взаимодействии с базой данных. TransactionScope не является заменой. Как показано на следующем рисунке, TransactionScope должен полностью окружать сеанс и транзакцию NHibernate. Вызов TransactionScope.Complete() должен произойти после завершения сеанса. Любой другой заказ, скорее всего, приведет к неприятным сбоям в работе, таким как утечки соединения.

Мое мнение также заключается в том, что он должен работать вместе с TransactionScope, но это не так, ни в 3.3.xx, ни в версии 4.0.0.400.

Приведенный выше рецепт может работать, но нужно проверить его с помощью вложенного TrancactionScope, с внутренним TransactionScope, для которого определен Transaction.Suppress (при использовании SQL) и т. Д.

Один вопрос, почему вы выполняете внутреннюю сессию.BeginTransaction - начиная с версии 2.1 GA NHibernate автоматически регистрируется в контекстах TransactionScope, поэтому больше нет причин делать свою собственную.

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