首先,重构的想法来源于以下文章:Correct use of Repository and Unit Of Work patterns in ASP.NET MVC,因为我发现在我的框架中,对UnitOfWork使用了错误的设计方法,同时感谢一下文章:Generically Implementing the Unit of Work & Repository Pattern with Entity Framework in MVC & Simplifying Entity Graphs,我的重构设计参考了它。 下面来说说我的具体重构方式。 在原来的代码中,我的Repository<T>泛型继承自IRepository<T>并且在增删改查代码中做了如下处理: 1: public virtual void Insert(T entity) 2: { 3: try 4: { 5: if (entity == null) 6: throw new ArgumentException("实体类为空"); 7: DbSet.Add(entity); 8: context.SaveChanges(); 9: } 10: catch (DbEntityValidationException dbex) 11: { 12: var msg = string.Empty; 13: foreach(var validationErrors in dbex.EntityValidationErrors) 14: foreach(var validateionError in validationErrors.ValidationErrors) 15: msg+=string.Format("Property:{0} Error:{1}",validateionError.PropertyName,validateionError.ErrorMessage); 16: 17: var fail = new Exception(msg,dbex); 18: throw fail; 19: } 20: } 最关键的地方是,我添加了“Context.SaveChanges”方法,这就直接导致UnitOfWork的规则失效。UnitOfWork出现的本身是为了提供事务提交支持。这样直接在Repository中提交,直接导致UnitOfWork功能废弃。 还有个地方就是在前台,通过Autofac注册完毕后,我是这么用的: 1: public BookService(IUnitOfWork unitOfWork 2: , IBook bookRepository 3: , IBookType bookTypeRepository 4: , IBookPlace bookPlaceRepository 5: , ICacheManager cacheManager 6: , ILoggerService logger 7: ) 8: { 9: this.unitOfWork = unitOfWork; 10: this.bookRepository = bookRepository; 11: this.bookTypeRepository = bookTypeRepository; 12: this.bookPlaceRepository = bookPlaceRepository; 13: this.cacheManager = cacheManager; 14: this.logger = logger; 15: } 16: 17: private readonly IUnitOfWork unitOfWork; 18: private readonly IBook bookRepository; 19: private readonly IBookType bookTypeRepository; 20: private readonly IBookPlace bookPlaceRepository; 21: private readonly ICacheManager cacheManager; 22: private readonly ILoggerService logger; 这样做的话,当以后我们有表删除或者新增的时候,我们不得不维护这样的列表。这完全不符合OO设计原则。 但是如果引入UnitOfWork的话,内部利用Hashtable等实现对Respository的指向,那么在界面我们只要这样写就可以了: 1: public BookService( 2: IUnitOfWork unitOfWork 3: , ICacheManager cacheManager 4: , ILoggerService logger 5: ) 6: { 7: this.unitOfWork = unitOfWork; 8: this.cacheManager = cacheManager; 9: this.logger = logger; 10: } 11: 12: private readonly IUnitOfWork unitOfWork; 13: private readonly ICacheManager cacheManager; 14: private readonly ILoggerService logger; 使用的时候,直接这样实例化就行了: 1: var bookPlaceRepository = unitOfWork.Repository<BookPlace>(); 这样做完全不用顾虑有新表的添加删除了。代码根本就不用动。 所以,综上两点,UnitOfWork的引入为了解决以下问题: 1.提供全局事务支持。 2.提供对Repository模型的指向。以便于松耦合绑定。 下面是代码重构部分: IUnitOfWork接口部分: 1: using System; 2: using TinyFrame.Data.DataRepository; 3: using TinyFrame.Data.DomainModel; 4: 5: namespace TinyFrame.Unitofwork 6: { 7: public interface IUnitOfWork 8: { 9: void Commit(); 10: IRepository<T> Repository<T>() where T : class; 11: 12: void Dispose(bool disposing); 13: void Dispose(); 14: } 15: } 实现部分比较简单,利用Hashtable来保存对Repository的指向: 1: using System; 2: using System.Data.Entity; 3: using TinyFrame.Data.DataRepository; 4: using TinyFrame.Data.DomainModel; 5: using TinyFrame.Data.DataContext; 6: using System.Collections; 7: 8: namespace TinyFrame.Unitofwork 9: { 10: public class UnitOfWork : IUnitOfWork 11: { 12: public UnitOfWork(IDbContext dbContext) 13: { 14: this.dbContext = dbContext; 15: } 16: 17: private readonly IDbContext dbContext; 18: private bool disposed; 19: private Hashtable repositorys; 20: 21: public void Commit() 22: { 23: dbContext.SaveChanges(); 24: } 25: 26: public IRepository<T> Repository<T>() where T:class 27: { 28: if (repositorys == null) 29: repositorys = new Hashtable(); 30: 31: var type = typeof(T).Name; 32: 33: if (!repositorys.ContainsKey(type)) 34: { 35: var repositoryType = typeof(Repository<>); 36: var repositoryInstance = Activator.CreateInstance(repositoryType.MakeGenericType(typeof(T)), dbContext); 37: repositorys.Add(type, repositoryInstance); 38: } 39: return (IRepository<T>)repositorys[type]; 40: } 41: 42: #region Dispose method 43: public virtual void Dispose(bool disposing) 44: { 45: if (!disposed) 46: if (disposing) 47: dbContext.Dispose(); 48: disposed = true; 49: } 50: 51: public void Dispose() 52: { 53: Dispose(true); 54: GC.SuppressFinalize(this); 55: } 56: #endregion 57: } 58: } 第17行,保持对DbContext的引用,以便于进行提交操作。 第26行,Repository<T>泛型方法,以便于动态返回仓储模型。
需要注意的是,在Repository<T>的实现中,不要再增删改查里面再添加 DbContext.SaveChanges方法,首先是没意义,其次是完全不符合Repository和UnitOfWork的做法。 最后附图一张,表明我对Repository和UnitOfWork的理解:
本章源码下载: |
|
来自: ThinkTank_引擎 > 《TinyFrame》