Когда совершать транзакцию NHibernate? - PullRequest
1 голос
/ 30 июня 2011

Хотя я очень знаком с Webforms и Linq, я новичок в ASP.NET MVC и NHibernate World.Я работал над проектом, используя examples Боба Крэйвенса.Мое приложение в основном для чтения и непоследовательных записей, поэтому обычно я не использую транзакции.Но для реализации модели «Единица работы» все мои исследования, включая блог Айенде , говорят, что я должен.

У меня проблема в следующем:

  • Ninjectсоздает сессию и открывает транзакцию.
  • Ninject внедряет репозитории в сервисы, а сервисы в контроллеры.
  • Я делаю некоторые изменения в свойствах и дочерних объектах и ​​сохраняю их в сводном корне.Это вызывает Transaction.Commit (работает нормально, как и ожидалось)
  • В другом методе позже в контроллере я пытаюсь сохранить отдельный объект
  • Второй вызов завершается неудачно, поскольку транзакция больше не активна.

Я подумываю добавить в UnitOfWork bool "CommitNeeded", который будет установлен моим методом Save () и условно вызвать Commit () в UnitOfWork.Dispose ().Это хорошая идея?

Должен ли я удалить инфраструктуру транзакций?Должен ли я изменить свой Commit () на Flush ()?

Буду признателен за любой совет, который поможет исправить мой анти-шаблон.


В ответ на комментарии- Думаю, я не против, если они случаются вместе или раздельно.Происходят две вещи.Первый изменяет объект «Клиент», а затем сохраняет его.Второй создает запись в журнале, которая затем вызывает тот же метод «Сохранить».

var Customer = ServiceLayer.GetCustomer(...);
Transmogrify(Customer, Customer.Children, Widgets, ...);
ServiceLayer.Save(Customer)

ServiceLayer.RecordEvent(Customer, "Customer was frobbed")

, где LogEvent выглядит как

public void RecordEvent(Customer customer, int eventTypeId, string description)
{
    ...

    Save(customer);
}

Метод RecordEvent имеет свое собственное «сохранение», потому что этовызывается с других контроллеров, которые не изменяют данные.Я считаю, что вызов Save не относится ни к одному из этих мест.Вопрос в том, где?Метод Dispose () уровня обслуживания?или фильтр, как предложили другие пользователи?

Ответы [ 2 ]

5 голосов
/ 30 июня 2011

Используя ASP.NET MVC, я использую фильтр действий для привязки области транзакции к жизненному циклу выполнения действия контроллера.Это прекрасно работает большую часть времени, но вы должны быть осторожны, чтобы не держать транзакции открытыми слишком долго.

public class UnitOfWorkActionFilter : ActionFilterAttribute
{
    public IUnitOfWork UnitOfWork { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        UnitOfWork.Start();
        base.OnActionExecuting(filterContext);
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Exception == null)
        {
            UnitOfWork.Commit();
        }
        else
        {
            UnitOfWork.Rollback();
        }
        UnitOfWork.Dispose();
        base.OnActionExecuted(filterContext);
    }
}

В моем случае я использую инъекцию свойства через пользовательский ControllerActionInvoker, чтобы получить IUnitOfWork зависимость в ActionFilterAttribute.

1 голос
/ 30 июня 2011

Я использую для этого модуль http. Я получаю транзакцию в начале http-запроса и прекращаю ее в конце http-запроса:

 public class UnitOfWorkModule : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.BeginRequest += context_BeginRequest;
            context.EndRequest += context_EndRequest;
        }

        private void context_BeginRequest(object sender, EventArgs e)
        {
            IUnitOfWork instance = UnitOfWorkFactory.GetDefault();
            instance.Begin();
        }

        private void context_EndRequest(object sender, EventArgs e)
        {
            IUnitOfWork instance = UnitOfWorkFactory.GetDefault();
            try
            {
                instance.Commit();
            }
            catch
            {
                instance.RollBack();
            }
            finally
            {
                instance.Dispose();
            }
        }
    }

Моя фабрика единиц работы - это просто инициализация Func при регистрации типов в контейнере IoC:

public class UnitOfWorkFactory  
{
        public static Func<IUnitOfWork> GetDefault;
    }

Инициализация (для моего случая StructureMap):

UnitOfWorkFactory.GetDefault = () => container.GetInstance<IUnitOfWork>();

И тогда вы регистрируете вас в UnitOfWorkModule web.config

<httpModules>
      <add name="UnitOfWorkModule" type="UI.UnitOfWorkModule, UI" />
    </httpModules>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...