Nhibernate: кто отвечает за управление транзакциями в не веб-приложениях - PullRequest
8 голосов
/ 26 июля 2011

В веб-приложении единица работы отвечает за управление транзакциями.

А как насчет приложения для Windows?

Насколько я знаю, хранилище является связующим звеном между моим уровнем доступа к данным и моим бизнес-уровнем. Он скрывает всю информацию о доступе к данным от моего бизнес-уровня.

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

Но я читал, что использование методов Commit / RollBack в хранилище нарушает намерения хранилища.

Я спрашиваю себя, кто отвечает за управление транзакциями в не веб-приложении и как скрыть информацию о транзакциях / Nhibernate от бизнес-уровня?

Ответы [ 2 ]

4 голосов
/ 29 июля 2011

Общий ответ: «Тот, кто создает экземпляр ISession, должен его утилизировать. Если транзакция не была зафиксирована, это фактически откат».

Я добился успеха, используя шаблон командыопределить операцию, которую я хочу выполнить на единицу работы.Скажем, у нас есть Person сущность, и одна из вещей, которую мы можем сделать, это изменить имя человека.Давайте начнем с сущности:

public class Person
{
    public virtual int Id { get; private set; }
    public virtual string Name { get; private set; }

    public virtual void ChangeName(string newName)
    {
        if (string.IsNullOrWhiteSpace(newName))
        {
            throw new DomainException("Name cannot be empty");
        }

        if (newName.Length > 20)
        {
            throw new DomainException("Name cannot exceed 20 characters");
        }

        this.Name = newName;
    }
}

Определите простую команду POCO следующим образом:

public class ChangeNameCommand : IDomainCommand
{
    public ChangeNameCommand(int personId, string newName)
    {
        this.PersonId = personId;
        this.NewName = newName;
    }

    public int PersonId { get; set; }
    public string NewName { get; set; }
}

... и обработчик для команды:

public class ChangeNameCommandHandler : IHandle<ChangeNameCommand>
{
    ISession session;

    public ChangeNameCommandHandler(ISession session)
    {
        // You could demand an IPersonRepository instead of using the session directly.
        this.session = session;
    }

    public void Handle(ChangeNameCommand command)
    {
        var person = session.Load<Person>(command.PersonId);
        person.ChangeName(command.NewName);
    }
}

Цель состоит в том, чтобы код, существующий вне области Session / Work, мог делать что-то вроде этого:

public class SomeClass
{
    ICommandInvoker invoker;

    public SomeClass(ICommandInvoker invoker)
    {
        this.invoker = invoker;
    }

    public void DoSomething()
    {
        var command = new ChangeNameCommand(1, "asdf");
        invoker.Invoke(command);
    }
}

Вызов команды подразумевает «выполнить эту команду на единицу работы».Вот что мы хотим сделать, когда вызываем команду:

  1. Начать вложенную область IoC (область «Единица работы»)
  2. Запустить сеанс IS и транзакцию (этовероятно подразумевается как часть шага 3)
  3. Разрешить IHandle<ChangeNameCommand> из области действия IoC
  4. Передать команду обработчику (домен выполняет свою работу)
  5. Подтвердитьтранзакция
  6. Завершение области действия IoC (единица работы)

Итак, вот пример использования Autofac в качестве контейнера IoC:

public class UnitOfWorkInvoker : ICommandInvoker
{
    Autofac.ILifetimeScope scope;

    public UnitOfWorkInvoker(Autofac.ILifetimeScope scope)
    {
        this.scope = scope;
    }

    public void Invoke<TCommand>(TCommand command) where TCommand : IDomainCommand
    {
        using (var workScope = scope.BeginLifetimeScope("UnitOfWork")) // step 1
        {
            var handler = workScope.Resolve<IHandle<TCommand>>(); // step 3 (implies step 2)
            handler.Handle(command); // step 4

            var session = workScope.Resolve<NHibernate.ISession>();
            session.Transaction.Commit(); // step 5

        } // step 6 - When the "workScope" is disposed, Autofac will dispose the ISession.
          // If an exception was thrown before the commit, the transaction is rolled back.
    }
}

Примечание: UnitOfWorkInvoker, который я показал здесь, нарушает SRP - это UnitOfWorkFactory, UnitOfWork и Invoker все в одном.В моей реальной реализации я разбил их.

1 голос
/ 27 июля 2011

Когда я использую репозитории, они содержатся в единице работы. Единица работы отслеживает изменения в репозиториях и управляет управлением транзакциями.

Почему было бы целесообразно использовать единицу работы для управления транзакциями в веб-приложении, а не в Windows-приложении? Если это приложение N-уровня, ваш бизнес-уровень будет на самом деле разделен между обоими.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...