直奔主题了,不那么啰嗦。
一下分三个步骤说明,分别为 dbContext,repository,uow三点
在说之前,先说下O# 因为最近发现还有人在问,其实很好理解,简要说下理解步骤(O#的整体框架和上面的截图类似->_->我就是仿照的o#搭建的好不好)
如果对respository+uow熟练的人 ,一下就能看懂
看图一,图中的Core.Data.Entity
说实话,我也偷懒了,以下是 IRepository和IUnitofWork的定义
IRepository:
/// <summary> /// 实现仓储模型的数据标准操作 /// </summary> public interface IRepository<TEntity> : IDependency { #region 属性 /// <summary> /// 获取 当前单元操作对象 /// </summary> IUnitOfWork UnitOfWork { get; } /// <summary> /// 获取当前实体查询数据集,数据将使用不跟踪变化的方式来查询 /// </summary> IQueryable<TEntity> Entites { get; } #endregion #region 方法 /// <summary> /// 插入实体 /// </summary> /// <param name="entity">实体对象</param> /// <returns>操作影响的行数</returns> int Insert(TEntity entity, bool save = true); /// <summary> /// 批量插入实体 /// </summary> /// <param name="entities">实体对象集合</param> /// <returns>操作影响的行数</returns> int Insert(IEnumerable<TEntity> entities, bool save = true); /// <summary> /// 删除实体 /// </summary> /// <param name="entity">实体对象</param> /// <returns>操作影响的行数</returns> int Delete(TEntity entity, bool save = true); /// <summary> /// 删除指定编号的实体 /// </summary> /// <param name="key">实体主键</param> /// <returns>操作影响的行数</returns> int Delete(object key, bool save = true); /// <summary> /// 删除所有符合特定条件的实体 /// </summary> /// <param name="predicate">查询条件谓语表达式</param> /// <returns>操作影响的行数</returns> int Delete(Expression<Func<TEntity, bool>> predicate, bool save = true); /// <summary> /// 批量删除实体 /// </summary> /// <param name="entities">实体对象集合</param> /// <returns>操作影响的行数</returns> int Delete(IEnumerable<TEntity> entities, bool save = true); /// <summary> /// 更新指定主键的对象 /// </summary> /// <param name="key"></param> /// <returns></returns> int Update(object key, bool save = true); /// <summary> /// 更新实体对象 /// </summary> /// <param name="entity">更新后的实体对象</param> /// <returns>操作影响的行数</returns> int Update(TEntity entity, bool save = true); /// <summary> /// 批量更新数据 /// </summary> /// <param name="entites">对象集合</param> /// <returns></returns> int Update(IEnumerable<TEntity> entites, bool save = true); ///// <summary> ///// 检查实体是否存在 ///// </summary> ///// <param name="predicate">查询条件谓语表达式</param> ///// <param name="id">编辑的实体标识</param> ///// <returns>是否存在</returns> //bool CheckExists(Expression<Func<TEntity, bool>> predicate, object id); /// <summary> /// 查找指定主键的实体 /// </summary> /// <param name="key">实体主键</param> /// <returns>符合主键的实体,不存在时返回null</returns> TEntity GetByKey(object key); /// <summary> /// 查询指定条件的实体 /// </summary> /// <param name="predicate">查询表达式</param> /// <returns>符合条件的实体集合</returns> IEnumerable<TEntity> GetByPredicate(Expression<Func<TEntity, bool>> predicate); /// <summary> /// 获取贪婪加载导航属性的查询数据集 /// </summary> /// <param name="path">属性表达式,表示要贪婪加载的导航属性</param> /// <returns>查询数据集</returns> IQueryable<TEntity> GetInclude<TProperty>(Expression<Func<TEntity, TProperty>> path); /// <summary> /// 获取贪婪加载多个导航属性的查询数据集 /// </summary> /// <param name="paths">要贪婪加载的导航属性名称数组</param> /// <returns>查询数据集</returns> IQueryable<TEntity> GetIncludes(params string[] paths); /// <summary> /// 创建一个原始 SQL 查询,该查询将返回此集中的实体。 /// 默认情况下,上下文会跟踪返回的实体;可通过对返回的 DbRawSqlQuery 调用 AsNoTracking 来更改此设置。 请注意返回实体的类型始终是此集的类型,而不会是派生的类型。 如果查询的一个或多个表可能包含其他实体类型的数据,则必须编写适当的 SQL 查询以确保只返回适当类型的实体。 与接受 SQL 的任何 API 一样,对任何用户输入进行参数化以便避免 SQL 注入攻击是十分重要的。 您可以在 SQL 查询字符串中包含参数占位符,然后将参数值作为附加参数提供。 您提供的任何参数值都将自动转换为 DbParameter。 context.Set(typeof(Blog)).SqlQuery("SELECT * FROM dbo.Posts WHERE Author = @p0", userSuppliedAuthor); 或者,您还可以构造一个 DbParameter 并将它提供给 SqlQuery。 这允许您在 SQL 查询字符串中使用命名参数。 context.Set(typeof(Blog)).SqlQuery("SELECT * FROM dbo.Posts WHERE Author = @author", new SqlParameter("@author", userSuppliedAuthor)); /// </summary> /// <param name="trackEnabled">是否跟踪返回实体</param> /// <param name="sql">SQL 查询字符串。</param> /// <param name="parameters">要应用于 SQL 查询字符串的参数。 如果使用输出参数,则它们的值在完全读取结果之前不可用。 这是由于 DbDataReader 的基础行为而导致的,有关详细信息,请参见 http://go.microsoft.com/fwlink/?LinkID=398589。</param> /// <returns></returns> IEnumerable<TEntity> SqlQuery(string sql, bool trackEnabled = true, params object[] parameters); /// <summary> /// 分页数据查询 /// </summary> /// <param name="pageCondition">分页和排序条件</param> /// <param name="predicate">数据过滤条件 表达式</param> /// <returns>分页后的数据集合</returns> IQueryable<TEntity> Get(PageCondition pageCondition, Expression<Func<TEntity, bool>> predicate, out int totalRow); #endregion }
IUnitOfWork:
/// <summary> /// /// </summary> public interface IUnitOfWork: IDependency, IDisposable { #region 方法 /// <summary> /// 命令提交 /// </summary> /// <returns>提交操作结果</returns> int SaveChanges(bool save); DbContext DbContext { get; } #endregion }
此处之所以这么定义(只有两个对象),看上一篇关于 repository和uow的关系
对应的repository和uow的实现
repository:
/// <summary> /// 仓储 /// </summary> public class Repository<TEntity> : IRepository<TEntity> where TEntity : class { #region Fields private readonly IUnitOfWork _unitOfWork; private readonly DbSet<TEntity> _dbSet; #endregion #region ctor /// <summary> /// 初始化一个<see cref="Repository{TEntity}"/>类型的新实例 /// </summary> public Repository(IUnitOfWork unitOfWork) { this._unitOfWork = unitOfWork; this._dbSet = _unitOfWork.DbContext.Set<TEntity>(); } #endregion #region 属性 /// <summary> /// 获取 当前实体类型的查询数据集,数据将使用不跟踪变化的方式来查询 /// </summary> public IQueryable<TEntity> Entites { get { return _dbSet.AsNoTracking(); } } /// <summary> /// 获取 当前单元操作对象 /// </summary> public IUnitOfWork UnitOfWork { get { return _unitOfWork; } } #endregion #region 方法 ///// <summary> ///// 判断指定表达式条件 的对象是否存在 ///// </summary> ///// <param name="predicate"></param> ///// <param name="id"></param> ///// <returns></returns> //public bool CheckExists(Expression<Func<TEntity, bool>> predicate, object id) //{ // var entity = _dbSet.Where(predicate).Select(m => ) //} /// <summary> /// 删除所有符合特定条件的实体 /// </summary> /// <param name="predicate">查询条件谓语表达式</param> /// <returns>操作影响的行数</returns> public int Delete(Expression<Func<TEntity, bool>> predicate, bool save = true) { var entities = _dbSet.Where(predicate).AsEnumerable(); if (null != entities && entities.Count() > 0) { _dbSet.RemoveRange(entities); } return _unitOfWork.SaveChanges(save); } /// <summary> /// 批量删除实体 /// </summary> /// <param name="entities">实体对象集合</param> /// <returns>操作影响的行数</returns> public int Delete(IEnumerable<TEntity> entities, bool save = true) { if (null != entities && entities.Count() > 0) { _dbSet.RemoveRange(entities); } return _unitOfWork.SaveChanges(save); } public int Delete(object key, bool save = true) { var entity = _dbSet.Find(key); _dbSet.Remove(entity); return _unitOfWork.SaveChanges(save); } public int Delete(TEntity entity, bool save = true) { _dbSet.Remove(entity); return _unitOfWork.SaveChanges(save); } public TEntity GetByKey(object key) { return _dbSet.Find(key); } public IEnumerable<TEntity> GetByPredicate(Expression<Func<TEntity, bool>> predicate) { return _dbSet.Where(predicate).AsEnumerable(); } public IQueryable<TEntity> GetInclude<TProperty>(Expression<Func<TEntity, TProperty>> path) { return _dbSet.Include(path); } public IQueryable<TEntity> GetIncludes(params string[] paths) { IQueryable<TEntity> sources = null; foreach (var path in paths) { sources = _dbSet.Include(path); } return sources; } public int Insert(IEnumerable<TEntity> entities, bool save = true) { _dbSet.AddRange(entities); return _unitOfWork.SaveChanges(save); } public int Insert(TEntity entity, bool save = true) { _dbSet.Add(entity); return _unitOfWork.SaveChanges(save); } public IEnumerable<TEntity> SqlQuery(string sql, bool trackEnabled = true, params object[] parameters) { return trackEnabled ? _dbSet.SqlQuery(sql, parameters) : _dbSet.SqlQuery(sql, parameters).AsNoTracking(); } public int Update(object key, bool save = true) { var entity = _dbSet.Find(key); return Update(entity, save); } public int Update(TEntity entity, bool save = true) { DbContext context = ((DbContext)_unitOfWork); DbSet<TEntity> dbSet = context.Set<TEntity>(); try { DbEntityEntry<TEntity> entry = context.Entry(entity); if (entry.State == EntityState.Detached) { dbSet.Attach(entity); entry.State = EntityState.Modified; } } catch (InvalidOperationException ex) { throw new Exception(ex.Message); } return _unitOfWork.SaveChanges(save); } public int Update(IEnumerable<TEntity> entites, bool save = true) { DbContext context = ((DbContext)_unitOfWork); DbSet<TEntity> dbSet = context.Set<TEntity>(); foreach (var entity in entites) { try { DbEntityEntry<TEntity> entry = context.Entry(entity); if (entry.State == EntityState.Detached) { dbSet.Attach(entity); entry.State = EntityState.Modified; } } catch (InvalidOperationException ex) { throw new Exception(ex.Message); } } return _unitOfWork.SaveChanges(save); } public IQueryable<TEntity> Get(PageCondition pageCondition, Expression<Func<TEntity, bool>> predicate, out int totalRow) { int totalCount = 0; IQueryable<TEntity> source = _dbSet.Where(predicate); if (pageCondition.SortConditions == null || pageCondition.SortConditions.Length == 0) { source = source.OrderBy("Id"); } else { int count = 0; IOrderedQueryable<TEntity> orderSource = null; foreach (SortCondition sortCondition in pageCondition.SortConditions) { orderSource = count == 0 ? CollectionPropertySorter<TEntity>.OrderBy(source, sortCondition.SortField, sortCondition.ListSortDirection) : CollectionPropertySorter<TEntity>.ThenBy(orderSource, sortCondition.SortField, sortCondition.ListSortDirection); count++; } source = orderSource; totalCount = source.Count(); } int pageIndex = pageCondition.PageIndex, pageSize = pageCondition.PageSize; source = source != null ? source.Skip((pageIndex - 1) * pageSize).Take(pageSize) : Enumerable.Empty<TEntity>().AsQueryable(); //IQueryable<TResult> query = source.Select(selector); //return GetKey(query.Expression); totalRow = totalCount; return source; } #endregion }
uow:
/// <summary> /// 工作单元实现 /// </summary> public class UnitOfWork : IUnitOfWork { private bool _disposed; private DbContext _dbContext; public UnitOfWork() { this._dbContext = DbContext; } /// <summary> /// 数据提交操作 /// </summary> /// <returns></returns> public int SaveChanges(bool save) { if (save) { try { try { return _dbContext.SaveChanges(); } catch (DbEntityValidationException dbex) { throw; } } catch (Exception ex) { throw; } } return 0; } public DbContext DbContext { get { //CallContext:是线程内部唯一的独用的数据槽(一块内存空间) //传递DbContext进去获取实例的信息,在这里进行强制转换。 DbContext dbContext = CallContext.GetData("DbContext") as DbContext; if (dbContext == null) //线程在数据槽里面没有此上下文 { dbContext = new InnovatorContext(); //如果不存在上下文的话,创建一个EF上下文 //我们在创建一个,放到数据槽中去 CallContext.SetData("DbContext", dbContext); } return dbContext; } } public virtual void Dispose(bool disposing) { if (!this._disposed) if (disposing) this._dbContext.Dispose(); this._disposed = true; } public void Dispose() { Dispose(true); } }
脚本中涉及到的 SortDirection源自O#的干货中的实现,具体参见 o#
至此,该内容已完毕,以上实现院子处处有,再说闲的多余了。