mvc5 + ef6 + autofac搭建項目(repository+uow)(一)


直奔主題了,不那么啰嗦。

一下分三個步驟說明,分別為 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#

至此,該內容已完畢,以上實現院子處處有,再說閑的多余了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM