c# - Nhibernate:谁负责非 web 应用程序中的事务管理

标签 c# nhibernate transactions data-access-layer data-access

在 Web 应用程序中,一个工作单元负责事务管理。

但是 Windows 应用程序呢?

据我所知,存储库是我的数据访问层和业务层之间的连接器。 它从我的业务层隐藏了所有数据访问内容。

使用这个事实让我想到将所有事务内容放入存储库中。

但我读到在存储库上使用 Commit/RollBack 方法违反了存储库的意图。

我问自己谁负责非 Web 应用程序中的事务管理,以及如何从业务层隐藏事务/Nhibernate 内容?

最佳答案

一般的回答是“谁实例化 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. 开始一个 ISession 和 Transaction(这可能是第 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一体。在我的实际实现中,我将它们分解。

关于c# - Nhibernate:谁负责非 web 应用程序中的事务管理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6835795/

相关文章:

c# - StringSegment 类的目的是什么?

mysql - 在 MySQLWorkbench 中使用事务执行存储过程总是自动提交?

mongodb - 'majority committed data' 和 'the snapshot of majority committed data' 有什么区别

asp.net - 构建 nhibernate 的标准

c# - 开始事务时出现 SqlServer.Management.SMO.Server 错误

c# - ASP.NET MVC 在方法而不是参数上绑定(bind)属性

c# - 在 WPF 自定义控件上多次应用 DropShadowEffect

c# - LINQPad 和未处理的异常

nhibernate - 是否可以在 NHibernate (>3.0) Linq 的同一查询中调用 IQueryable.To Future() 和 IQueryable.Fetch()?

.net - NHibernate:覆盖 Equals 和 GetHashCode 的原因