说说IUnitOfWork~方法完整性与统一提交不冲突
在一个方法中,它一般会做一件事情,这样的方法在功能上比较清晰,在职责上也很单一(这里的单一是褒义的,呵呵),而它所做的这件事,从头到尾会把它做完,不会做到一半的功能,这属于功能上的不完整,这不是我们推荐的。
项目中的代码:
完整的提交方法:
protected virtual void SaveChanges() { if (!iUnitWork.IsNotSubmit) iUnitWork.Save(); }
完整的插入方法:
public virtual void Add(TEntity item) { _db.Entry<TEntity>(item); _db.Set<TEntity>().Add(item); this.SaveChanges(); }
上面代码是EF实现的插入,很完善,将实现添加到实体集合,并使用SaveChanges()提交到数据库,一个完善的数据插入流程完成,但一个问题来了如果我们的
业务操作不只是插入一张表,还有更新另一张表,怎么去实现呢?
public virtual void Modify(TEntity item) { _db.Set<TEntity>().Attach(item); _db.Entry(item).State = EntityState.Modified; this.SaveChanges(); }
上面为完整的更新动作是上面的代码,现在有一个假设:
UserRepository类有方法Add,ProductRepository类有方法Modify,这时,这两个方法进行组织,代码可能是这样:
...code
userRepository.Add(user);
userRepository.Modify(product);
...code
事实上,上面的代码所执行的过程为:先插入用户表,提交到SQL数据库,再更新产品表,再提交到SQL数据库,这时由于提交两次,SQL端会产生两个连接池,而如果两个方法使用了TransactionScope事务块,并且SQL服务器与WWW服务器在不同的电脑上,会触发多于的分布式事务(这是可以避免的),而我们知道,windows的MSDTC(分布式事务)服务是最不靠谱的。
如何解决这种情况呢,难道方法不该完整吗?
什么事情都有解决的办法,方法的完整性在系统设计上是没有问题的,但有时,对于一个工作单元中有多个方法时,我们需要把这种完整性升级,将多个方法提升为一个整体,即多个方法的完整性问题,解决这个问题的关键在于,你的数据上下文是否为一个,你的submitChanges方法是否为一个。
IUnitWork崭新的接口规范
/// <summary> /// 工作单元 /// 提供一个保存方法,它可以对调用层公开,为了减少连库次数 /// </summary> public interface IUnitOfWork { /// <summary> /// 将操作提交到数据库, /// </summary> void Save(); /// <summary> /// 是否不提交到数据库,这只是在具体的repository类中的SaveChanges方法里用到的 /// 默认为false,即默认为提交到数据库 /// </summary> /// <returns></returns> bool IsNotSubmit { get; set; } } /// <summary> /// 工作单元 /// 对泛型类型的支持 /// </summary> /// <typeparam name="T"></typeparam> public interface IUnitWork<T> : IUnitOfWork where T : class { }
看了上面的接口,不用我说,大家也知道其中的含义了,Save()为数据上下文提交,而IsNotSubmit表示是否要提交到数据库,我们都知道bool类型对象的默认
值不false,所以,默认情况下,Add,Modify这些方法的提交动作都是true,即被提交到数据库。
我们优化这时上面add与modify的方法如下:
Domain.Core.IUnitOfWork _iUnitWork = new backgroundEntities(); _iUnitWork.IsNotSubmit=true; userRepository(user); productRepository(product); _iUnitWork.Save();
OK, 上面的代码所产生的效果就是,将两条SQL语句发到SQL端 ,使用一个SQL连接池,不产生MSDTC服务。