Сбросить NHibernate, в то же время разрешая откат транзакции - PullRequest
5 голосов
/ 19 ноября 2009

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

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

Что я могу с этим поделать?

UPDATE

Все еще любопытно, как это сделать - я не верю, что ни один из приведенных ответов касается проблемы. Мне нужно вызвать Flush (). Вопрос в том, как откатить данные, которые были сброшены?

Ответы [ 3 ]

4 голосов
/ 11 апреля 2011

отметьте это: Принудительное выполнение запроса без очистки / фиксации

У меня, похоже, была та же проблема, я сбрасывал, а затем выполнял откат, но некоторые данные оставались в базе данных. Однако в моем коде были некоторые части, которые вызывали бы коммит, который нельзя откатить. Рассмотрите фрагмент кода принятых ответов как правильное использование для транзакций, сбросов, откатов и фиксаций и примите во внимание, что этот шаблон может быть расширен ...

в одной единице работы (т. Е. Мы рассматриваем Запрос в веб-приложении как одну единицу работы, и все, что происходит в этом запросе, существует в одной транзакции, для которой зафиксирован onEndRequest):

  1. Вы звоните _sessionFactory.OpenSession(), _session.BeginTransaction(), _session.CommitTransaction() и _session.CloseSession() только один раз.

  2. вы можете вызывать _session.Flush() и _session.RollBackTransaction() столько раз, сколько захотите, но Flush () автоматически вызывается при коммите автоматически. Вы можете вызвать Flush, когда вам нужно сделать запрос и убедиться, что извлеченные данные не будут устаревшими.

  3. Обратите внимание, что после фиксации транзакции все операции после нее не выполняются. Вместо этого NHibernate создаст необходимую транзакцию под капотом (http://www.nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions), в которой точка у вас уже есть проблемы с отслеживанием согласованности и, возможно, логической целостности

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

  5. Что еще лучше, так это попробовать Nested транзакции, которые якобы допускают частичные коммиты; Вы можете откатить «корневую» транзакцию, и все изменения будут отменены. Я действительно не тестировал эту функцию .NET и SQL Server, хотя вложенная транзакция в самой базе данных оставляет желать лучшего, и я не знаю, как именно ADO.NET использует эту функцию.

пункты с 1 по 4 были протестированы со всеми версиями NHibernate, начиная с 1.2.

3 голосов
/ 13 июля 2010

Ради форматирования я позволю себе обновить ответ tolism7 здесь.

  1. используйте using и забудьте о транзакции. Dispose () - transaction будет автоматически иметь значение Dispose 'd в конце блока использования.
  2. throw - не выбрасывайте ex, потому что это означает выброс вашей трассировки стека (см. этот пост , где говорится: «Когда .NET Framework выполняет этот оператор: throw ex; он выбрасывает все информация в стеке над текущей функцией. ")

.

public void CommitChanges()
{
    using (var transaction = Session.BeginTransaction())  // <-- open scope
        try
        {
            // do something
            transaction.Commit();
        }
        catch (HibernateException)
        {
            transaction.Rollback();
            _session.Close();
            _session.Dispose();

            throw;  // <-- this way the stacktrace stays intact!
        }
}

A VB.NET-версию этого фрагмента кода можно найти здесь .

2 голосов
/ 19 ноября 2009

При использовании транзакций с NHibernate старайтесь избегать использования Session.Flush () и вместо этого используйте транзакцию.Commit (), которую он вызывает session.flush () для внутреннего использования.

Если во время Commit () произошла ошибка, и транзакцию необходимо откатить, это можно исправить следующим образом.

public static void CommitChanges()
{
    ITransaction transaction = Session.BeginTransaction();

    try
    {
        transaction.Commit();
    }
    catch (HibernateException ex)
    {
        transaction.Rollback();
        //close and dispose session here
        throw ex;
    }
    finally
    {
        transaction.Dispose();
    }
}

Теперь, если ручной вызов flush () или вызов commit () проходит успешно, нет способа откатить транзакцию с использованием механизмов NHibernate. Особенно при вызове транзакции.Commit () команда AdoTransaction, созданная NHibernate, затем удаляется сразу после завершения Commit (), поэтому вы не можете получить к ней доступ для отката.

Приведенный выше пример кода позволяет отследить ошибки, возникающие во время фиксации, а затем откатить транзакцию, которая уже началась.

Теперь вместо вызова транзакции.Commit () в приведенном выше примере вы вызываете session.Flush () в моих тестах никакие данные не сохраняются в базе данных, так как транзакция никогда не фиксируется.

Я понятия не имею, как выглядит ваш код, но если вы вызываете в шаблоне, как показано в примере кода выше, то транзакция.com.com () вместо Session.Flush () должна дать вам способ достичь того, что вы хотите.

...