第一讲 认识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系列就讲完了,各位,晚安了!
本文转自博客园张占岭(仓储大叔)的博客,原文链接:说说IUnitOfWork~我的IUnitOfWork+Repository架构,如需转载请自行联系原博主。