這個系統的文章在寫完這篇后將拉下眉目,一共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系列就講完了,各位,晚安了!