直奔主題了,不那么啰嗦。
一下分三個步驟說明,分別為 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#
至此,該內容已完畢,以上實現院子處處有,再說閑的多余了。