NHibernate: допустимо ли вызывать Session.Flush () перед совершением транзакции? - PullRequest
8 голосов
/ 29 марта 2011

Мне нужно выполнить две операции внутри единицы работы NHibernate: транзакционную (сохранение сущности) и нетранзакционную.

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

  • Операции будут зафиксированы, только если две подоперации выполнены успешно;
  • Если сохранение объекта завершится неудачно, нетранзакционная операция не будет выполнена;
  • Если нетранзакционный сбой, сохранение объекта будет отменено.

Проблема: с кодом, подобным следующему, NHibernate не будет выполнять фактическую вставку sql до вызова транзакции.Commit () (которая вызывает session.Flush () внутри):

        using (var transaction = session.BeginTransaction())
        {
            session.Save(entity);
            NotTransactionalOperationBasedOn(entity);

            transaction.Commit(); // the actual sql insert will be executed here
        }

С таким кодом, если Sql Insert не удается, слишком поздно: NotTransactionalOperation был выполнен. Чтобы выполнить фактическую вставку SQL перед выполнением NotTransactionalOperation, я должен вызвать сессию explicity .Flush () прямо перед сессией.

        using (var transaction = session.BeginTransaction())
        {
            session.Save(entity);
            session.Flush(); // the actual sql insert will be executed here

            NotTransactionalOperationBasedOn(entity);

            transaction.Commit(); 
        }

Код работает, но ... считается ли целесообразным вызывать session.Flush () перед совершением транзакции? Если нет, есть ли лучшие способы достичь того же результата?

Ответы [ 2 ]

3 голосов
/ 29 марта 2011

Очистка означает, что NHibernate будет следить за тем, чтобы все изменения сохранялись в БД.То есть он будет следить за выполнением всех необходимых операторов SQL.Когда транзакция завершается неудачно и, таким образом, откатывается, все эти изменения будут отменены.Таким образом, я не вижу в этом проблемы (вы должны помнить, однако, что ваша сущность может быть не в допустимом состоянии, поскольку транзакция не удалась).

Но ... я не вижупроблема на самом деле: в случае сбоя нетранзакционной процедуры, в чем проблема?Поскольку процедура не транзакционная, я думаю, она не влияет на информацию, которая хранится в базе данных?Или, что делает этот код?

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

Когда сбой не удается сохранить, я думаю, выУбедитесь, что не только транзакция откатывается, но и исключение будет сгенерировано в стеке, пока не встретится обработчик ошибок, что, вероятно, означает, что ваш нетранзакционный код также не будет выполнен:

using( var transaction = session.BeginTransaction() ) 
{
      repository.Save (entity); 

      transaction.Commit();   // error, exception is thrown.
}

NonTransactionalCode (entity); // this line will not be executed, since the exception will be thrown up the stack until a suitable catch block is encountered.
1 голос
/ 29 марта 2011

Это необычно, но если вы хотите сделать что-то вне единицы работы, которая зависит от того, что сделано внутри, это совершенно справедливо. Однако возникает вопрос: почему операция выполняется вне единицы работы, если она зависит от чего-то внутри? Если он полностью зависит от порядка, то перед выполнением нетранзакционной операции вы должны рассмотреть сброс и принятие. Если нетрансферная операция определяет, будет ли совершаться вся вещь (например, может быть, она выдает исключение), то она должна быть частью единицы работы.

Опция non-trans, кроме того, вероятно, не должна зависеть от данных, находящихся в БД, если только она не зависит от кода уровня данных, такого как триггеры (хотя мне нравятся триггеры, их, как правило, следует избегать по нескольким причинам, Не в последнюю очередь это тенденция к запутанным операциям сохранения, подобным этой. Как правило, вы должны хранить свою бизнес-логику на уровне приложений, кроме как в качестве окончательного варианта. Если объект был сохранен в сеансе, тогда данные доступны везде, где есть этот сеанс, и этот сеанс должен быть настолько широким, насколько это необходимо (или рассмотрим общий «родительский» сеанс с дочерними элементами, которые имеют доступ к родительскому элементу в все времена).

...