⼯作单元(UnitOfWork)模式(1)
在开始UnitOfWork模式之前有必要回顾下我们⽿熟能详的Data Access Object(DAO)模式,即数据访问对象。DAO是⼀种简单的模式,我们构建应⽤的时候经常会使⽤到它,它的功能就是将DAL元素从应⽤程序中分离出来,在经典的三层架构中,我们会将数据持久化⼯作单独分离出来,封装成DAL层。但是,DAO并没有隐藏它⾯对是⼀张张数据表,⽽且通常情况我们会为数据库中的每⼀张表创建⼀个DAO类,想必⼤家对这种⽅式的极度的不爽了。
由于DAO模式与数据表是⼀对⼀匹配的关系,因此DAO模式很好的配合了Active Record和Transaction Script业务模式,尤其是Table Module。正因为这种与数据表⼀对⼀匹配关系,使我对DAO模式深恶痛绝。
Unit Of Work模式,即⼯作单元,它是⼀种数据访问模式。它是⽤来维护⼀个由已经被业务修改(如增加、删除和更新等)的业务对象组成的列表。它负责协调这些业务对象的持久化⼯作及并发问题。那它是怎么来维护的⼀系列业务对象组成的列表持久化⼯作的呢?通过事务。Unit Of Work模式会记录所有对象模型修改过的信息,在提交的时候,⼀次性修改,并把结果同步到数据库。这个过程通常被封装在事务中。所以在DAL中采⽤Unit Of Work模式好处就在于能够确保数据的完整性,如果在持有⼀系列业务对象(同属于⼀个事务)的过程中出现问题,就可以将所有的修改回滚,以确保数据始终处于有效状态,不会出现脏数据。
在这⾥我们,使⽤⼀个简单的银⾏领域对两个帐号之间的转账进⾏举例
⾸先如图进⾏分层搭建基础框架
总共分为四层依次是: ---> 引⽤关系
UnitOfWork.Console --->UnitOfWork.Infrastructure、UnitOfWork.Model、UnitOfWork.Repository
UnitOfWork.Infrastructure
UnitOfWork.Model --->UnitOfWork.Infrastructure
UnitOfWork.Repository --->UnitOfWork.Model、UnitOfWork.Infrastructure
这不是经典的领域驱动架构,因为业务简单就进⾏简单搭建。
UnitOfWork.Infrastructure
⾸先,在UnitOfWork.Infrastructure建了⼀个Domain⽂件夹,⾥⾯只建了⼀个IAggregateRoot接⼝,Unit Of Work操作的实体必须是实现IAggregateRoot接⼝的。
/// <summary>
/// 标识接⼝,定义聚合根
/// </summary>
public class IAggregateRoot
{
}
建⽴UnitOfWork⽂件夹,在⾥⾯添加⼀个IUnitOfWorkRepository接⼝
public interface IUnitOfWorkRepository
{
//新增
void PersistCreationOf(IAggregateRoot entity);
//更新
void PersistUpdateOf(IAggregateRoot entity);
//删除
void PersistDeletionOf(IAggregateRoot entity);
}
我们再向UnitOfWork⽂件夹中添加⼀个IUnitOfWork接⼝,IUnitOfWork接⼝在注册更新、新增和删除时,需要IUnitOfWorkRepository,这样再提交Commit,UnitOfWork可以将真正持久化的⼯作委托给适合的具体实现对象,其实就是将持久化⼯作交给了IUnitOfWorkRepository 的实现类,我们稍后看看IUnitOfWork的实现类你就清楚了。
public interface IUnitOfWork
{
/// <summary>
/// 更新
/// </summary>
repository文件夹可以删除吗/// <param name="entity"></param>
/
// <param name="unitofWorkRepository"></param>
void RegisterUpdate(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
/// <summary>
/// 新增
/// </summary>
/// <param name="entity"></param>
/// <param name="unitofWorkRepository"></param>
void RegisterAdd(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
/// <summary>
/// 删除
/// </summary>
/
// <param name="entity"></param>
/// <param name="unitofWorkRepository"></param>
void RegisterRemoved(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
/// <summary>
/// 提交
/// </summary>
void Commit();
}
顺便说⼀句,在UnitOfWork.Infrastructure中还建⽴了Common和Logging⽂件夹,Infrastructure意为基础设施层,我们可以将通⽤的组件放到这⾥⾯,⽐如⽇志组件,邮件组件等。
好了,回顾下,我们在UnitOfWork.Infrastructure中其实什么业务都没有处理,只定义了三个接⼝。
UnitOfWork.Model
接下来,说说这层⼲了什么事吧!这⼀层主要是处理两个账户之间转账的业务。
向UnitOfWork.Model中添加⼀个Account类,实现IAggregateRoot接⼝,表⽰它是⼀个聚合根,可以被Unit Of Work操作。
/// <summary>
/// 账户类,表⽰Account是聚合根
/// </summary>
public class Account : IAggregateRoot
{
public Account(decimal balance)
{
Balance = balance;
}
/// <summary>
/// 账户余额
/// </summary>
public decimal Balance { get; set; }
}
为了持久化Account类,我们添加⼀个仅包含了⽰例有关的的Repository接⼝,即IAccountRepository,只是简单的⽰例。
/// <summary>
/// 定义持久化操作
/// </summary>
public interface IAccountRepository
{
/// <summary>
/// 更新
/// </summary>
/// <param name="account"></param>
void Save(Account account);
/// <summary>
/// 新增
/// </summary>
/// <param name="account"></param>
void Add(Account account);
/// <summary>
/
// 删除
/// </summary>
/// <param name="account"></param>
void Remove(Account account);
}
为了完成转账的业务,我们需要创建⼀个服务类来协调两个账户之间的转账⼯作,如AccountService类,在AccountService类中,通过构造函数初始化了IAccountRepository和IUnitOfWork。在完成转账后,它们都调⽤了账户Repository进⾏持久化。最后,通过Unit Of Work 的Commit来确保该笔交易的完成。
public class AccountService
{
private IAccountRepository _accountRepository;
private IUnitOfWork _unitOfWork;
public AccountService(IAccountRepository accountRepository, IUnitOfWork unitOfWork)
{
_accountRepository = accountRepository;
_unitOfWork = unitOfWork;
}
/// <summary>
/// 转账
/// </summary>
/// <param name="from"></param>
/// <param name="to"></param>
/
// <param name="amount"></param>
public void Transfer(Account from, Account to, decimal amount)
{
if (from.Balance >= amount)
{
from.Balance -= amount;
to.Balance += amount;
_accountRepository.Save(from);
_accountRepository.Save(to);
_unitOfWork.Commit();
}
}
}
总结下,在UnitOfWork.Model中我们定义的⼀个Account类,定义了⼀个持久化Account类的接⼝,以及转账业务的完成。下⾯我们要进⼊UnitOfWork.Repository探究Repository和Unit Of Work之间是怎么交互的?
UnitOfWork.Repository
在UnitOfWork.Repository,添加了⼀个NHUnitOfWork类,实现了UnitOfWork.Infrastructure.UnitOfWork中的IUnitOfWork接⼝,为什么定义到这⾥。因为在项⽬开发中你可能有NHbernator的Repository和EF的Repository。还记得我在讲解IUnitOfWork接⼝时,曾说过这样⼀句话“IUnitOfWork将持久化⼯作交给了IUnitOfWorkRepository的实现类”,在这⾥你就会到答案了。
public class NHUnitOfWork : IUnitOfWork
{
private Dictionary<IAggregateRoot, IUnitOfWorkRepository> addedEntities;
private Dictionary<IAggregateRoot, IUnitOfWorkRepository> changedEntities;
private Dictionary<IAggregateRoot, IUnitOfWorkRepository> deletedEntities;
public NHUnitOfWork()
{
addedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>();
changedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>();
deletedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>();
}
public void RegisterUpdate(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository)
{
if (!changedEntities.ContainsKey(entity))
{
changedEntities.Add(entity, unitofWorkRepository);
}
}
public void RegisterAdd(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository)
{
if (!addedEntities.ContainsKey(entity))
{
addedEntities.Add(entity, unitofWorkRepository);
};
}
public void RegisterRemoved(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository)
{
if (!deletedEntities.ContainsKey(entity))
{
deletedEntities.Add(entity, unitofWorkRepository);
}
}
public void Commit()
{
using (TransactionScope scope = new TransactionScope())
{
foreach (IAggregateRoot entity in this.addedEntities.Keys)
{
this.addedEntities[entity].PersistCreationOf(entity);
}
foreach (IAggregateRoot entity in this.changedEntities.Keys)
{
this.changedEntities[entity].PersistUpdateOf(entity);
}
foreach (IAggregateRoot entity in this.deletedEntities.Keys)
{
this.deletedEntities[entity].PersistDeletionOf(entity);
}
scope.Complete();
}
}
接下来,再添加⼀个AccountRepository类,这个类实现了两个接⼝,IAccountRepository和IUnitOfWorkRepository接⼝。IAccountRepository中的⽅法就是简单得将⼯作交给了Unit Of Work,传⼊待持久化的实体及Repository(实现了IUnitOfWorkRepository)引⽤。最后Unit Of Work 引⽤Repository的IUnitOfWorkRepository契约来完成真正的持久化⼯作。
public class AccountRepository : IAccountRepository,IUnitOfWorkRepository
{
private IUnitOfWork _unitOfWork;
public AccountRepository(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public void Save(Account account)
{
_unitOfWork.RegisterUpdate(account, this);
}
public void Add(Account account)
{
_unitOfWork.RegisterAdd(account, this);
}
public void Remove(Account account)
{
_unitOfWork.RegisterRemoved(account, this);
}
public void PersistUpdateOf(IAggregateRoot entity)
{
// ADO code to update 真正的SQL实现
}
public void PersistCreationOf(IAggregateRoot entity)
{
// ADO code to Add 真正的SQL实现
}
public void PersistDeletionOf(IAggregateRoot entity)
{
// ADO code to delete 真正的SQL实现
}
}
总结下,UnitOfWork.Repository这⾥才是真正纠结的地⽅。⾸先,Unit Of Work加载实体对象(Accont)和实体对应的Repository对象(AccountRepository);然后通过Unit Of Work的Commit⽅法,循环转调Repository对象(AccountRepository)的持久化⽅法,进⾏实体对象(Accont)的持久化⼯作。多调试就明⽩了。
UnitOfWork.Console
接下来,就是最后的控制台程序了。
class Program
{
static void Main(string[] args)
{
Account a = new Account(1000);
System.Console.WriteLine("现在张三,存有{0}", a.Balance);
Account b = new Account(200);
System.Console.WriteLine("现在李四,存有{0}", b.Balance);
System.Console.WriteLine("张三准备转500元给李四,转战开始了......");
//声明要使⽤的UnitOfWork
IUnitOfWork nhUnitOfWork = new NHUnitOfWork();
/
/声明要使⽤的Repository
IAccountRepository accountRepository = new AccountRepository(nhUnitOfWork); AccountService service = new AccountService(accountRepository, nhUnitOfWork); service.Transfer(a,b,500);
System.Console.WriteLine("转账结束");
System.Console.WriteLine("张三当前余额:{0}",a.Balance);
System.Console.WriteLine("李四当前余额:{0}",b.Balance);
System.Console.ReadKey();
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论