Roo*_*ian 8 c# nhibernate data-access transactions data-access-layer
在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;
}
}
Run Code Online (Sandbox Code Playgroud)
定义一个简单的 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; }
}
Run Code Online (Sandbox Code Playgroud)
...以及命令的处理程序:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
目标是存在于会话/工作范围之外的代码可以执行如下操作:
public class SomeClass
{
ICommandInvoker invoker;
public SomeClass(ICommandInvoker invoker)
{
this.invoker = invoker;
}
public void DoSomething()
{
var command = new ChangeNameCommand(1, "asdf");
invoker.Invoke(command);
}
}
Run Code Online (Sandbox Code Playgroud)
该命令的调用意味着“在工作单元上执行此命令”。这就是我们调用命令时希望发生的情况:
IHandle<ChangeNameCommand>从 IoC 范围解析 an下面是一个使用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.
}
}
Run Code Online (Sandbox Code Playgroud)
注意:UnitOfWorkInvoker我在这里展示的 违反了SRP - 它是 a UnitOfWorkFactory、 aUnitOfWork和 aInvoker多合一的。在我的实际实现中,我把它们分解了。
| 归档时间: |
|
| 查看次数: |
1529 次 |
| 最近记录: |