说说IUnitOfWork~我的IUnitOfWork+Repository架构
第一讲 认识IUnitOfWork,为什么要出现IUnitOfWork接口第二讲 Linq to Sql与EntityFrameworks中的SubmtChanges()发生了什么事第三讲 方法完整性与统一提交不冲突第四讲 DbContext对象的创建应该向BLL层公开第五讲 我的IUnitOfWork+Repository架构
这个系统的文章在写完这篇后将拉下眉目,一共5讲的IUnitOfWork带给我们的是性能,原子化操作,等多方法的改进,下面我把我的IUnitOfWork+Repository模式大体的说一下,并代上核心代码:
底层接口UnitOfWork.Data.Core
这是一个接口规范的项目层,它由CURD操作规范和UnitOfWork规范组成
namespace UnitOfWork.Data.Core { /// <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 IUnitOfWork<T> : IUnitOfWork where T : class { } }
namespace UnitOfWork.Data.Core { public interface IRepository<TEntity> where TEntity : class { /// <summary> /// 添加实体并提交到数据服务器 /// </summary> /// <param name="item">Item to add to repository</param> void Insert(TEntity item); /// <summary> /// 移除实体并提交到数据服务器 /// 如果表存在约束,需要先删除子表信息 /// </summary> /// <param name="item">Item to delete</param> void Delete(TEntity item); /// <summary> /// 修改实体并提交到数据服务器 /// </summary> /// <param name="item"></param> void Update(TEntity item); /// <summary> /// Get all elements of type {T} in repository /// </summary> /// <returns>List of selected elements</returns> IQueryable<TEntity> GetModel(); /// <summary> /// 根据主键得到实体 /// </summary> /// <param name="id"></param> /// <returns></returns> TEntity Find(params object[] id); } }
namespace UnitOfWork.Data.Core { /// <summary> /// 扩展的Repository操作规范 /// </summary> public interface IExtensionRepository<TEntity> where TEntity : class { /// <summary> /// 添加集合 /// </summary> /// <param name="item"></param> void Insert(IEnumerable<TEntity> item); /// <summary> /// 修改集合 /// </summary> /// <param name="item"></param> void Update(IEnumerable<TEntity> item); /// <summary> /// 删除集合 /// </summary> /// <param name="item"></param> void Delete(IEnumerable<TEntity> item); /// <summary> /// 扩展更新方法,只对EF支持 /// </summary> /// <param name="entity"></param> void Update(System.Linq.Expressions.Expression<Action<TEntity>> entity); } }
namespace UnitOfWork.Data.Core { /// <summary> /// 完整的数据操作接口 /// </summary> public interface ICompleteRepository<T> : IRepository<T>, IExtensionRepository<T> where T : class { } }
而在DATA层需要去实现这些接口,我们以EF为例,去实现这样接口:
namespace EntityFrameworks.Data.Core { using UnitOfWork.Data.Core; using System.Data.Entity.Infrastructure; public class DbContextRepository<TEntity> : ICompleteRepository<TEntity> where TEntity : class { protected DbContext _db { get; private set; } IUnitOfWork iUnitWork; public DbContextRepository(IUnitOfWork db) { iUnitWork = db; _db = (DbContext)db; } #region IRepository<T> 成员 public virtual void Insert(TEntity item) { _db.Entry<TEntity>(item); _db.Set<TEntity>().Add(item); this.SaveChanges(); } public virtual void Delete(TEntity item) { _db.Set<TEntity>().Attach(item); _db.Set<TEntity>().Remove(item); this.SaveChanges(); } public virtual void Update(TEntity item) { _db.Set<TEntity>().Attach(item); _db.Entry(item).State = EntityState.Modified; this.SaveChanges(); } public void Update(Expression<Action<TEntity>> entity) { TEntity newEntity = typeof(TEntity).GetConstructor(Type.EmptyTypes).Invoke(null) as TEntity;//建立指定类型的实例 List<string> propertyNameList = new List<string>(); MemberInitExpression param = entity.Body as MemberInitExpression; foreach (var item in param.Bindings) { string propertyName = item.Member.Name; object propertyValue; var memberAssignment = item as MemberAssignment; if (memberAssignment.Expression.NodeType == ExpressionType.Constant) { propertyValue = (memberAssignment.Expression as ConstantExpression).Value; } else { propertyValue = Expression.Lambda(memberAssignment.Expression, null).Compile().DynamicInvoke(); } typeof(TEntity).GetProperty(propertyName).SetValue(newEntity, propertyValue, null); propertyNameList.Add(propertyName); } _db.Set<TEntity>().Attach(newEntity); _db.Configuration.ValidateOnSaveEnabled = false; var ObjectStateEntry = ((IObjectContextAdapter)_db).ObjectContext.ObjectStateManager.GetObjectStateEntry(newEntity); propertyNameList.ForEach(x => ObjectStateEntry.SetModifiedProperty(x.Trim())); this.SaveChanges(); // ((IObjectContextAdapter)_db).ObjectContext.Detach(newEntity); } public IQueryable<TEntity> GetModel() { // return _db.Set<TEntity>().AsNoTracking(); return _db.Set<TEntity>(); } #endregion #region IExtensionRepository<T> 成员 public virtual void Insert(IEnumerable<TEntity> item) { item.ToList().ForEach(i => { this.Insert(i);//不提交 }); } public virtual void Delete(IEnumerable<TEntity> item) { item.ToList().ForEach(i => { this.Delete(i); }); } public virtual void Update(IEnumerable<TEntity> item) { item.ToList().ForEach(i => { this.Update(i); }); } public TEntity Find(params object[] id) { return _db.Set<TEntity>().Find(id); } #endregion #region Protected Methods /// <summary> /// 根据工作单元的IsNotSubmit的属性,去判断是否提交到数据库 /// 一般地,在多个repository类型进行组合时,这个IsNotSubmit都会设为true,即不马上提交, /// 而对于单个repository操作来说,它的值不需要设置,使用默认的false,将直接提交到数据库,这也保证了操作的原子性。 /// </summary> protected void SaveChanges() { if (!iUnitWork.IsNotSubmit) iUnitWork.Save(); } /// <summary> /// 计数更新,与SaveChange()是两个SQL链接,走分布式事务 /// 子类可以根据自己的逻辑,去复写 /// tableName:表名 /// param:索引0为主键名,1表主键值,2为要计数的字段,3为增量 /// </summary> /// <param name="tableName">表名</param> /// <param name="param">参数列表,索引0为主键名,1表主键值,2为要计数的字段,3为增量</param> protected virtual void UpdateForCount(string tableName, params object[] param) { string sql = "update [" + tableName + "] set [{2}]=ISNULL([{2}],0)+{3} where [{0}]={1}"; List<object> listParasm = new List<object> { param[0], param[1], param[2], param[3], }; _db.Database.ExecuteSqlCommand(string.Format(sql, listParasm.ToArray())); } #endregion } }
在Entity实体模型层,需要去继承IUnitOfWork这个接口,并去实现它:
public partial class backgroundEntities : IUnitOfWork { #region IUnitOfWork 成员 public void Save() { this.SaveChanges(); } public bool IsNotSubmit { get; set; } #endregion }
最后在BLL层来完成业务的组成及基础操作的实现
namespace BLL { public abstract class BLLBase { protected IUnitOfWork IUnitOfWork { get; private set; } public BLLBase() : this(null) { } public BLLBase(IUnitOfWork iUnitOfWork) { IUnitOfWork = iUnitOfWork; } protected ICompleteRepository<T> LoadRepository<T>() where T : class { return IUnitOfWork == null ? new TestBase<T>() : new TestBase<T>(IUnitOfWork); } } }
在BLL层具体业务实现中,去继承BLLBase,并将数据上下文以参数的形式传递过去:
public class OrderManager : BLLBase { public OrderManager() : base(new TestDataContext()) { } public void GeneratorOrder(Order_Info order) { GeneratorOrder(order, null); } public void GeneratorOrder(Order_Info order, Product product) { #region BLLBase中直接调用公用方法 IUnitOfWork.IsNotSubmit = true; new OrderRepository(IUnitOfWork).Insert(order);//DAL层具体的Repository实现类 if (product != null) LoadRepository<Product>().Insert(product);//BLLBase提供的单纯CURD操作 IUnitOfWork.SaveChanges(); #endregion } }
在WEB层直接调用BLL的具体业务即可!
到此,我们的UnitOfWork系列就讲完了,各位,晚安了!