第一節:框架基礎架構構建(CoreMvc+EFCore+AutoFac)


一. 結構介紹

1. 分層建項目

 新建:YpfCore.AdminWeb、YpfCore.Data、YpfCore.DTO、YpfCore.IService、YpfCore.Service、YpfCore.Utils,每層的作用如下:

 A. YpfCore.AdminWeb層:UI層,存放一些頁面和進行一些基本的業務邏輯,供客戶端調用。

 B. YpfCore.Data層:數據層,存放數據庫實體映射類和相關配置類、EF上下文類。

 C. YpfCore.DTO層:數據傳輸對象層,存放一些業務邏輯實體,供UI層調用。

 D. YpfCore.IService層:業務接口層。

 E. YpfCore.Service層:業務層。

 F. YpfCore.Utils層:幫助類層

(后續補充 YpfCore.WebApi層,用於前后端分離的接口編寫)。

2. 項目結構圖

 

二. 搭建步驟

1.  數據層構建

 (1).通過Nuget給YpfCore.Data層安裝EFCore相關的程序集,如下:

  【Microsoft.EntityFrameworkCore】【Microsoft.EntityFrameworkCore.SqlServer】【Microsoft.EntityFrameworkCore.Design】【Microsoft.EntityFrameworkCore.Tools】        

PS: 這里安裝的是 3.1.8 版本,此處搭建適宜SQLServer為例演示,MySQL相關集成后續擴展封裝章節會體現。

 (2).通過下面指令映射數據庫實體文件,這里采用注解即DataAnnotations進行關系格式映射。

  【Scaffold-DbContext "Server=47.92.xxx.xxx;Database=CoreFrameDB;User ID=CoreFrameDB;Password=123456;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Entity -Context CoreFrameDBContext -UseDatabaseNames -DataAnnotations】

 (3). 為了便於后續業務代碼的編寫,這里我們添加日志,用於打印Linq 轉變成的 SQL語句。

 通過Nuget安裝日志程序集:【Microsoft.Extensions.Logging】【Microsoft.Extensions.Logging.Debug】,修改EFCore上下問中的代碼如下:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
   optionsBuilder.UseLoggerFactory(LoggerFactory.Create(build =>
   {
       build.AddDebug();
   }));
}

2. 業務接口層構建

 (1). 給YpfCore.IService層添加對YpfCore.Data層的引用,同時通過Nuget安裝如下程序集:

 【Microsoft.EntityFrameworkCore】【System.Data.SqlClient】

 (2). 新增IBaseService 和 ISupport接口,IBaseService用於定義EFCore上下文對DB操作的方法約束,ISupport為了標記后續哪些子類Service可以被注入到YpfCore.AdminWeb層。

IBaseService代碼分享

 public interface IBaseService
    {
        /****************************************下面進行方法的封裝(同步)***********************************************/
        //1. 直接提交數據庫

        #region 01-數據源
        IQueryable<T> Entities<T>() where T : class;

        IQueryable<T> EntitiesNoTrack<T>() where T : class;

        #endregion

        #region 02-新增
        int Add<T>(T model) where T : class;

        #endregion

        #region 03-刪除
        /// <summary>
        /// 刪除
        /// </summary>
        /// <param name="model">需要刪除的實體</param>
        /// <returns></returns>
        int Del<T>(T model) where T : class;

        #endregion

        #region 04-根據條件刪除(支持批量刪除)
        /// <summary>
        /// 根據條件刪除(支持批量刪除)
        /// </summary>
        /// <param name="delWhere">傳入Lambda表達式(生成表達式目錄樹)</param>
        /// <returns></returns>
        int DelBy<T>(Expression<Func<T, bool>> delWhere) where T : class;

        #endregion

        #region 05-單實體修改
        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="model">修改后的實體</param>
        /// <returns></returns>
        int Modify<T>(T model) where T : class;

        #endregion

        #region 06-批量修改(非lambda)
        /// <summary>
        /// 批量修改(非lambda)
        /// </summary>
        /// <param name="model">要修改實體中 修改后的屬性 </param>
        /// <param name="whereLambda">查詢實體的條件</param>
        /// <param name="proNames">lambda的形式表示要修改的實體屬性名</param>
        /// <returns></returns>
        int ModifyBy<T>(T model, Expression<Func<T, bool>> whereLambda, params string[] proNames) where T : class;

        #endregion

        #region 07-根據條件查詢
        /// <summary>
        /// 根據條件查詢
        /// </summary>
        /// <param name="whereLambda">查詢條件(lambda表達式的形式生成表達式目錄樹)</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        List<T> GetListBy<T>(Expression<Func<T, bool>> whereLambda, bool isTrack = true) where T : class;

        #endregion

        #region 08-根據條件排序和查詢
        /// <summary>
        /// 根據條件排序和查詢
        /// </summary>
        /// <typeparam name="Tkey">排序字段類型</typeparam>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="orderLambda">排序條件</param>
        /// <param name="isAsc">升序or降序</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        List<T> GetListBy<T, Tkey>(Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true, bool isTrack = true) where T : class;

        #endregion

        #region 09-分頁查詢(根據Lambda排序)
        /// <summary>
        /// 根據條件排序和查詢
        /// </summary>
        /// <typeparam name="Tkey">排序字段類型</typeparam>
        /// <param name="pageIndex">頁碼</param>
        /// <param name="pageSize">頁容量</param>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="orderLambda">排序條件</param>
        /// <param name="isAsc">升序or降序</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        List<T> GetPageList<T, Tkey>(int pageIndex, int pageSize, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true, bool isTrack = true) where T : class;

        #endregion

        #region 10-分頁查詢(根據名稱排序)
        /// <summary>
        /// 分頁查詢輸出總行數(根據名稱排序)
        /// </summary>
        /// <param name="pageIndex">頁碼</param>
        /// <param name="rowCount">輸出的總數量</param>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="sortName">排序名稱</param>
        /// <param name="sortDirection">asc 或 desc</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        List<T> GetPageListByName<T>(int pageIndex, int pageSize, Expression<Func<T, bool>> whereLambda, string sortName, string sortDirection, bool isTrack = true) where T : class;

        #endregion

        #region 11-分頁查詢輸出總行數(根據Lambda排序)
        /// <summary>
        /// 根據條件排序和查詢
        /// </summary>
        /// <typeparam name="Tkey">排序字段類型</typeparam>
        /// <param name="pageIndex">頁碼</param>
        /// <param name="pageSize">頁容量</param>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="orderLambda">排序條件</param>
        /// <param name="isAsc">升序or降序</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        List<T> GetPageList<T, Tkey>(int pageIndex, int pageSize, out int rowCount, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true, bool isTrack = true) where T : class;

        #endregion

        #region 12-分頁查詢輸出總行數(根據名稱排序)
        /// <summary>
        /// 分頁查詢輸出總行數(根據名稱排序)
        /// </summary>
        /// <param name="pageIndex">頁碼</param>
        /// <param name="pageSize">頁容量</param>
        /// <param name="rowCount">輸出的總數量</param>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="sortName">排序名稱</param>
        /// <param name="sortDirection">asc 或 desc</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        List<T> GetPageListByName<T>(int pageIndex, int pageSize, out int rowCount, Expression<Func<T, bool>> whereLambda, string sortName, string sortDirection, bool isTrack = true) where T : class;

        #endregion





        //2. SaveChange剝離出來,處理事務

        #region 01-批量處理SaveChange()
        /// <summary>
        /// 事務批量處理
        /// </summary>
        /// <returns></returns>
        int SaveChange();

        #endregion

        #region 02-新增
        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="model">需要新增的實體</param>
        void AddNo<T>(T model) where T : class;

        #endregion

        #region 03-刪除
        /// <summary>
        /// 刪除
        /// </summary>
        /// <param name="model">需要刪除的實體</param>
        void DelNo<T>(T model) where T : class;

        #endregion

        #region 04-根據條件刪除
        /// <summary>
        /// 條件刪除
        /// </summary>
        /// <param name="delWhere">需要刪除的條件</param>
        void DelByNo<T>(Expression<Func<T, bool>> delWhere) where T : class;

        #endregion

        #region 05-修改
        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="model">修改后的實體</param>
        void ModifyNo<T>(T model) where T : class;

        #endregion


        //3. EF調用sql語句

        #region 01-執行增加,刪除,修改操作(或調用存儲過程)
        /// <summary>
        /// 執行增加,刪除,修改操作(或調用存儲過程)
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="pars"></param>
        /// <returns></returns>
        int ExecuteSql(string sql, params SqlParameter[] pars);


        #endregion

        #region 02-執行查詢操作
        /// <summary>
        /// 執行查詢操作
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <param name="pars"></param>
        /// <returns></returns>
        List<T> ExecuteQuery<T>(string sql, bool isTrack = true, params SqlParameter[] pars) where T : class;

        #endregion

        #region 03-執行查詢操作(與Linq相結合)
        /// <summary>
        /// 執行查詢操作
        /// 注:查詢必須返回實體的所有屬性字段;結果集中列名必須與屬性映射的項目匹配;查詢中不能包含關聯數據
        /// 除Select以外其他的SQL語句無法執行
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        ///  <param name="whereLambda">查詢條件</param>
        /// <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <param name="pars"></param>
        /// <returns></returns>
        List<T> ExecuteQueryWhere<T>(string sql, Expression<Func<T, bool>> whereLambda, bool isTrack = true, params SqlParameter[] pars) where T : class;

        #endregion



        /****************************************下面進行方法的封裝(異步)***********************************************/
        //1. 直接提交數據庫

        #region 01-新增
        Task<int> AddAsync<T>(T model) where T : class;

        #endregion

        #region 02-刪除
        /// <summary>
        /// 刪除
        /// </summary>
        /// <param name="model">需要刪除的實體</param>
        /// <returns></returns>
        Task<int> DelAsync<T>(T model) where T : class;

        #endregion

        #region 03-根據條件刪除(支持批量刪除)
        /// <summary>
        /// 根據條件刪除(支持批量刪除)
        /// </summary>
        /// <param name="delWhere">傳入Lambda表達式(生成表達式目錄樹)</param>
        /// <returns></returns>
        Task<int> DelByAsync<T>(Expression<Func<T, bool>> delWhere) where T : class;

        #endregion

        #region 04-單實體修改
        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="model">修改后的實體</param>
        /// <returns></returns>
        Task<int> ModifyAsync<T>(T model) where T : class;

        #endregion

        #region 05-批量修改(非lambda)
        /// <summary>
        /// 批量修改(非lambda)
        /// </summary>
        /// <param name="model">要修改實體中 修改后的屬性 </param>
        /// <param name="whereLambda">查詢實體的條件</param>
        /// <param name="proNames">lambda的形式表示要修改的實體屬性名</param>
        /// <returns></returns>
        Task<int> ModifyByAsync<T>(T model, Expression<Func<T, bool>> whereLambda, params string[] proNames) where T : class;

        #endregion

        #region 06-根據條件查詢
        /// <summary>
        /// 根據條件查詢
        /// </summary>
        /// <param name="whereLambda">查詢條件(lambda表達式的形式生成表達式目錄樹)</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        Task<List<T>> GetListByAsync<T>(Expression<Func<T, bool>> whereLambda, bool isTrack = true) where T : class;

        #endregion

        #region 07-根據條件排序和查詢
        /// <summary>
        /// 根據條件排序和查詢
        /// </summary>
        /// <typeparam name="Tkey">排序字段類型</typeparam>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="orderLambda">排序條件</param>
        /// <param name="isAsc">升序or降序</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        Task<List<T>> GetListByAsync<T, Tkey>(Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true, bool isTrack = true) where T : class;

        #endregion

        #region 08-分頁查詢(根據Lambda排序)
        /// <summary>
        /// 根據條件排序和查詢
        /// </summary>
        /// <typeparam name="Tkey">排序字段類型</typeparam>
        /// <param name="pageIndex">頁碼</param>
        /// <param name="pageSize">頁容量</param>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="orderLambda">排序條件</param>
        /// <param name="isAsc">升序or降序</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        Task<List<T>> GetPageListAsync<T, Tkey>(int pageIndex, int pageSize, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true, bool isTrack = true) where T : class;

        #endregion

        #region 09-分頁查詢(根據名稱排序)
        /// <summary>
        /// 分頁查詢輸出總行數(根據名稱排序)
        /// </summary>
        /// <param name="pageIndex">頁碼</param>
        /// <param name="rowCount">輸出的總數量</param>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="sortName">排序名稱</param>
        /// <param name="sortDirection">asc 或 desc</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        Task<List<T>> GetPageListByNameAsync<T>(int pageIndex, int pageSize, Expression<Func<T, bool>> whereLambda, string sortName, string sortDirection, bool isTrack = true) where T : class;

        #endregion




        //2. SaveChange剝離出來,處理事務

        #region 01-批量處理SaveChange()
        /// <summary>
        /// 事務批量處理
        /// </summary>
        /// <returns></returns>
        Task<int> SaveChangeAsync();

        #endregion

        #region 02-新增
        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="model">需要新增的實體</param>
        Task<EntityEntry<T>> AddNoAsync<T>(T model) where T : class;

        #endregion

        #region 03-根據條件刪除
        /// <summary>
        /// 條件刪除
        /// </summary>
        /// <param name="delWhere">需要刪除的條件</param>
        Task DelByNoAsync<T>(Expression<Func<T, bool>> delWhere) where T : class;

        #endregion


        //3. EF調用sql語句

        #region 01-執行增加,刪除,修改操作(或調用存儲過程)
        /// <summary>
        /// 執行增加,刪除,修改操作(或調用存儲過程)
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="pars"></param>
        /// <returns></returns>
        Task<int> ExecuteSqlAsync(string sql, params SqlParameter[] pars);


        #endregion


    }
View Code

ISupport代碼分享

    /// <summary>
    /// 一個標記接口,只有實現該接口的類才進行注入
    /// </summary>
    public interface ISupport
    {
    }
View Code

3. 業務層構建

 (1).給YpfCore.Service層添加對 YpfCore.Data、YpfCore.IServie、Ypf.Uitls層的引用,同時通過Nuget安裝如下程序集:

 【Microsoft.EntityFrameworkCore】【Microsoft.EntityFrameworkCore.SqlServer】

 (2).新增BaseService類,實現了IBaseService 和 ISupport接口,主要是EFCore對DB增刪改查各種操作封裝。

BaseService代碼分享:

 /// <summary>
    /// 泛型方法,直接注入EF上下文
    /// </summary>
    public class BaseService : IBaseService, ISupport
    {
        public DbContext db;

        /// <summary>
        /// 在使用的時候,自動注入db上下文
        /// </summary>
        /// <param name="db"></param>
        public BaseService(CoreFrameDBContext db)
        {
            this.db = db;

            //關閉全局追蹤的代碼
            //db.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
        }

        /****************************************下面EFCore基礎方法的封裝(同步)***********************************************/
        //1. 直接提交數據庫

        #region 01-數據源
        public IQueryable<T> Entities<T>() where T : class
        {
            return db.Set<T>();
        }

        public IQueryable<T> EntitiesNoTrack<T>() where T : class
        {
            return db.Set<T>().AsNoTracking();
        }

        #endregion

        #region 02-新增
        public int Add<T>(T model) where T : class
        {
            db.Entry(model).State = EntityState.Added;
            return db.SaveChanges();

        }
        #endregion

        #region 03-刪除
        /// <summary>
        /// 刪除
        /// </summary>
        /// <param name="model">需要刪除的實體</param>
        /// <returns></returns>
        public int Del<T>(T model) where T : class
        {
            db.Entry(model).State = EntityState.Deleted;
            return db.SaveChanges();
        }
        #endregion

        #region 04-根據條件刪除(支持批量刪除)
        /// <summary>
        /// 根據條件刪除(支持批量刪除)
        /// </summary>
        /// <param name="delWhere">傳入Lambda表達式(生成表達式目錄樹)</param>
        /// <returns></returns>
        public int DelBy<T>(Expression<Func<T, bool>> delWhere) where T : class
        {
            List<T> listDels = db.Set<T>().Where(delWhere).ToList();
            listDels.ForEach(model =>
            {
                db.Entry(model).State = EntityState.Deleted;
            });
            return db.SaveChanges();
        }
        #endregion

        #region 05-單實體修改
        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="model">修改后的實體</param>
        /// <returns></returns>
        public int Modify<T>(T model) where T : class
        {
            db.Entry(model).State = EntityState.Modified;
            return db.SaveChanges();
        }
        #endregion

        #region 06-批量修改(非lambda)
        /// <summary>
        /// 批量修改(非lambda)
        /// </summary>
        /// <param name="model">要修改實體中 修改后的屬性 </param>
        /// <param name="whereLambda">查詢實體的條件</param>
        /// <param name="proNames">lambda的形式表示要修改的實體屬性名</param>
        /// <returns></returns>
        public int ModifyBy<T>(T model, Expression<Func<T, bool>> whereLambda, params string[] proNames) where T : class
        {
            List<T> listModifes = db.Set<T>().Where(whereLambda).ToList();
            Type t = typeof(T);
            List<PropertyInfo> proInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList();
            Dictionary<string, PropertyInfo> dicPros = new Dictionary<string, PropertyInfo>();
            proInfos.ForEach(p =>
            {
                if (proNames.Contains(p.Name))
                {
                    dicPros.Add(p.Name, p);
                }
            });
            foreach (string proName in proNames)
            {
                if (dicPros.ContainsKey(proName))
                {
                    PropertyInfo proInfo = dicPros[proName];
                    object newValue = proInfo.GetValue(model, null);
                    foreach (T m in listModifes)
                    {
                        proInfo.SetValue(m, newValue, null);
                    }
                }
            }
            return db.SaveChanges();
        }
        #endregion

        #region 07-根據條件查詢
        /// <summary>
        /// 根據條件查詢
        /// </summary>
        /// <param name="whereLambda">查詢條件(lambda表達式的形式生成表達式目錄樹)</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        public List<T> GetListBy<T>(Expression<Func<T, bool>> whereLambda, bool isTrack = true) where T : class
        {
            if (isTrack)
            {
                return db.Set<T>().Where(whereLambda).ToList();
            }
            else
            {
                return db.Set<T>().Where(whereLambda).AsNoTracking().ToList();
            }

        }
        #endregion

        #region 08-根據條件排序和查詢
        /// <summary>
        /// 根據條件排序和查詢
        /// </summary>
        /// <typeparam name="Tkey">排序字段類型</typeparam>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="orderLambda">排序條件</param>
        /// <param name="isAsc">升序or降序</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        public List<T> GetListBy<T, Tkey>(Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true, bool isTrack = true) where T : class
        {
            IQueryable<T> data = null;
            if (isTrack)
            {
                data = db.Set<T>().Where(whereLambda);
            }
            else
            {
                data = db.Set<T>().Where(whereLambda).AsNoTracking();
            }
            if (isAsc)
            {
                data = data.OrderBy(orderLambda);
            }
            else
            {
                data = data.OrderByDescending(orderLambda);
            }
            return data.ToList();
        }
        #endregion

        #region 09-分頁查詢(根據Lambda排序)
        /// <summary>
        /// 根據條件排序和查詢
        /// </summary>
        /// <typeparam name="Tkey">排序字段類型</typeparam>
        /// <param name="pageIndex">頁碼</param>
        /// <param name="pageSize">頁容量</param>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="orderLambda">排序條件</param>
        /// <param name="isAsc">升序or降序</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        public List<T> GetPageList<T, Tkey>(int pageIndex, int pageSize, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true, bool isTrack = true) where T : class
        {

            IQueryable<T> data = null;
            if (isTrack)
            {
                data = db.Set<T>().Where(whereLambda);
            }
            else
            {
                data = db.Set<T>().Where(whereLambda).AsNoTracking();
            }
            if (isAsc)
            {
                data = data.OrderBy(orderLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            }
            else
            {
                data = data.OrderByDescending(orderLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            }
            return data.ToList();
        }
        #endregion

        #region 10-分頁查詢(根據名稱排序)
        /// <summary>
        /// 分頁查詢輸出總行數(根據名稱排序)
        /// </summary>
        /// <param name="pageIndex">頁碼</param>
        /// <param name="rowCount">輸出的總數量</param>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="sortName">排序名稱</param>
        /// <param name="sortDirection">asc 或 desc</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        public List<T> GetPageListByName<T>(int pageIndex, int pageSize, Expression<Func<T, bool>> whereLambda, string sortName, string sortDirection, bool isTrack = true) where T : class
        {
            List<T> list = null;
            if (isTrack)
            {
                list = db.Set<T>().Where(whereLambda).DataSorting(sortName, sortDirection)
                 .Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
            }
            else
            {
                list = db.Set<T>().Where(whereLambda).AsNoTracking().DataSorting(sortName, sortDirection)
                 .Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
            }
            return list;
        }
        #endregion

        #region 11-分頁查詢輸出總行數(根據Lambda排序)
        /// <summary>
        /// 根據條件排序和查詢
        /// </summary>
        /// <typeparam name="Tkey">排序字段類型</typeparam>
        /// <param name="pageIndex">頁碼</param>
        /// <param name="pageSize">頁容量</param>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="orderLambda">排序條件</param>
        /// <param name="isAsc">升序or降序</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        public List<T> GetPageList<T, Tkey>(int pageIndex, int pageSize, out int rowCount, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true, bool isTrack = true) where T : class
        {
            int count = db.Set<T>().Where(whereLambda).Count();
            IQueryable<T> data = null;
            if (isTrack)
            {
                data = db.Set<T>().Where(whereLambda);
            }
            else
            {
                data = db.Set<T>().Where(whereLambda).AsNoTracking();
            }
            if (isAsc)
            {
                data = data.OrderBy(orderLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            }
            else
            {
                data = data.OrderByDescending(orderLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            }
            rowCount = count;
            return data.ToList();
        }
        #endregion

        #region 12-分頁查詢輸出總行數(根據名稱排序)
        /// <summary>
        /// 分頁查詢輸出總行數(根據名稱排序)
        /// </summary>
        /// <param name="pageIndex">頁碼</param>
        /// <param name="pageSize">頁容量</param>
        /// <param name="rowCount">輸出的總數量</param>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="sortName">排序名稱</param>
        /// <param name="sortDirection">asc 或 desc</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        public List<T> GetPageListByName<T>(int pageIndex, int pageSize, out int rowCount, Expression<Func<T, bool>> whereLambda, string sortName, string sortDirection, bool isTrack = true) where T : class
        {
            int count = 0;
            count = db.Set<T>().Where(whereLambda).Count();
            List<T> list = null;
            if (isTrack)
            {
                list = db.Set<T>().Where(whereLambda).DataSorting(sortName, sortDirection)
                 .Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
            }
            else
            {
                list = db.Set<T>().Where(whereLambda).AsNoTracking().DataSorting(sortName, sortDirection)
                   .Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();

            }
            rowCount = count;
            return list;
        }
        #endregion


        //2. SaveChange剝離出來,處理事務

        #region 01-批量處理SaveChange()
        /// <summary>
        /// 事務批量處理
        /// </summary>
        /// <returns></returns>
        public int SaveChange()
        {
            return db.SaveChanges();
        }
        #endregion

        #region 02-新增
        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="model">需要新增的實體</param>
        public void AddNo<T>(T model) where T : class
        {
            db.Entry(model).State = EntityState.Added;
        }
        #endregion

        #region 03-刪除
        /// <summary>
        /// 刪除
        /// </summary>
        /// <param name="model">需要刪除的實體</param>
        public void DelNo<T>(T model) where T : class
        {
            db.Entry(model).State = EntityState.Deleted;
        }
        #endregion

        #region 04-根據條件刪除
        /// <summary>
        /// 條件刪除
        /// </summary>
        /// <param name="delWhere">需要刪除的條件</param>
        public void DelByNo<T>(Expression<Func<T, bool>> delWhere) where T : class
        {
            List<T> listDels = db.Set<T>().Where(delWhere).ToList();
            listDels.ForEach(model =>
            {
                db.Entry(model).State = EntityState.Deleted;
            });
        }
        #endregion

        #region 05-修改
        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="model">修改后的實體</param>
        public void ModifyNo<T>(T model) where T : class
        {
            db.Entry(model).State = EntityState.Modified;
        }
        #endregion


        //3. EF調用sql語句

        #region 01-執行增加,刪除,修改操作(或調用相關存儲過程)
        /// <summary>
        /// 執行增加,刪除,修改操作(或調用存儲過程)
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="pars"></param>
        /// <returns></returns>
        public int ExecuteSql(string sql, params SqlParameter[] pars)
        {
            return db.Database.ExecuteSqlRaw(sql, pars);
        }

        #endregion

        #region 02-執行查詢操作(調用查詢類的存儲過程)
        /// <summary>
        /// 執行查詢操作
        /// 注:查詢必須返回實體的所有屬性字段;結果集中列名必須與屬性映射的項目匹配;查詢中不能包含關聯數據
        /// 除Select以外其他的SQL語句無法執行
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <param name="pars"></param>
        /// <returns></returns>
        public List<T> ExecuteQuery<T>(string sql, bool isTrack = true, params SqlParameter[] pars) where T : class
        {
            if (isTrack)
            {
                //表示跟蹤狀態(默認是跟蹤的)
                return db.Set<T>().FromSqlRaw(sql, pars).ToList();
            }
            else
            {
                //表示不跟蹤狀態
                return db.Set<T>().FromSqlRaw(sql, pars).AsNoTracking().ToList();
            }
        }
        #endregion

        #region 03-執行查詢操作(與Linq相結合)
        /// <summary>
        /// 執行查詢操作
        /// 注:查詢必須返回實體的所有屬性字段;結果集中列名必須與屬性映射的項目匹配;查詢中不能包含關聯數據
        /// 除Select以外其他的SQL語句無法執行
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        ///  <param name="whereLambda">查詢條件</param>
        /// <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <param name="pars"></param>
        /// <returns></returns>
        public List<T> ExecuteQueryWhere<T>(string sql, Expression<Func<T, bool>> whereLambda, bool isTrack = true, params SqlParameter[] pars) where T : class
        {
            if (isTrack)
            {
                //表示跟蹤狀態(默認是跟蹤的)
                return db.Set<T>().FromSqlRaw(sql, pars).Where(whereLambda).ToList();
            }
            else
            {
                //表示不跟蹤狀態
                return db.Set<T>().FromSqlRaw(sql, pars).Where(whereLambda).AsNoTracking().ToList();
            }
        }
        #endregion



        /****************************************下面EFCore基礎方法的封裝(異步)***********************************************/

        #region 01-新增
        public async Task<int> AddAsync<T>(T model) where T : class
        {
            await db.AddAsync(model);
            return await db.SaveChangesAsync();
        }
        #endregion

        #region 02-刪除
        /// <summary>
        /// 刪除
        /// </summary>
        /// <param name="model">需要刪除的實體</param>
        /// <returns></returns>
        public async Task<int> DelAsync<T>(T model) where T : class
        {
            db.Entry(model).State = EntityState.Deleted;
            return await db.SaveChangesAsync();
        }
        #endregion

        #region 03-根據條件刪除(支持批量刪除)
        /// <summary>
        /// 根據條件刪除(支持批量刪除)
        /// </summary>
        /// <param name="delWhere">傳入Lambda表達式(生成表達式目錄樹)</param>
        /// <returns></returns>
        public async Task<int> DelByAsync<T>(Expression<Func<T, bool>> delWhere) where T : class
        {
            List<T> listDels = await db.Set<T>().Where(delWhere).ToListAsync();
            listDels.ForEach(model =>
            {
                db.Entry(model).State = EntityState.Deleted;
            });
            return await db.SaveChangesAsync();
        }
        #endregion

        #region 04-單實體修改
        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="model">修改后的實體</param>
        /// <returns></returns>
        public async Task<int> ModifyAsync<T>(T model) where T : class
        {
            db.Entry(model).State = EntityState.Modified;
            return await db.SaveChangesAsync();
        }
        #endregion

        #region 05-批量修改(非lambda)
        /// <summary>
        /// 批量修改(非lambda)
        /// </summary>
        /// <param name="model">要修改實體中 修改后的屬性 </param>
        /// <param name="whereLambda">查詢實體的條件</param>
        /// <param name="proNames">lambda的形式表示要修改的實體屬性名</param>
        /// <returns></returns>
        public async Task<int> ModifyByAsync<T>(T model, Expression<Func<T, bool>> whereLambda, params string[] proNames) where T : class
        {
            List<T> listModifes = await db.Set<T>().Where(whereLambda).ToListAsync();
            Type t = typeof(T);
            List<PropertyInfo> proInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList();
            Dictionary<string, PropertyInfo> dicPros = new Dictionary<string, PropertyInfo>();
            proInfos.ForEach(p =>
            {
                if (proNames.Contains(p.Name))
                {
                    dicPros.Add(p.Name, p);
                }
            });
            foreach (string proName in proNames)
            {
                if (dicPros.ContainsKey(proName))
                {
                    PropertyInfo proInfo = dicPros[proName];
                    object newValue = proInfo.GetValue(model, null);
                    foreach (T m in listModifes)
                    {
                        proInfo.SetValue(m, newValue, null);
                    }
                }
            }
            return await db.SaveChangesAsync();
        }
        #endregion

        #region 06-根據條件查詢
        /// <summary>
        /// 根據條件查詢
        /// </summary>
        /// <param name="whereLambda">查詢條件(lambda表達式的形式生成表達式目錄樹)</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        public async Task<List<T>> GetListByAsync<T>(Expression<Func<T, bool>> whereLambda, bool isTrack = true) where T : class
        {
            if (isTrack)
            {
                return await db.Set<T>().Where(whereLambda).ToListAsync();
            }
            else
            {
                return await db.Set<T>().Where(whereLambda).AsNoTracking().ToListAsync();
            }

        }
        #endregion

        #region 07-根據條件排序和查詢
        /// <summary>
        /// 根據條件排序和查詢
        /// </summary>
        /// <typeparam name="Tkey">排序字段類型</typeparam>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="orderLambda">排序條件</param>
        /// <param name="isAsc">升序or降序</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        public async Task<List<T>> GetListByAsync<T, Tkey>(Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true, bool isTrack = true) where T : class
        {
            IQueryable<T> data = null;
            if (isTrack)
            {
                data = db.Set<T>().Where(whereLambda);
            }
            else
            {
                data = db.Set<T>().Where(whereLambda).AsNoTracking();
            }
            if (isAsc)
            {
                data = data.OrderBy(orderLambda);
            }
            else
            {
                data = data.OrderByDescending(orderLambda);
            }
            return await data.ToListAsync();
        }
        #endregion

        #region 08-分頁查詢(根據Lambda排序)
        /// <summary>
        /// 根據條件排序和查詢
        /// </summary>
        /// <typeparam name="Tkey">排序字段類型</typeparam>
        /// <param name="pageIndex">頁碼</param>
        /// <param name="pageSize">頁容量</param>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="orderLambda">排序條件</param>
        /// <param name="isAsc">升序or降序</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        public async Task<List<T>> GetPageListAsync<T, Tkey>(int pageIndex, int pageSize, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true, bool isTrack = true) where T : class
        {

            IQueryable<T> data = null;
            if (isTrack)
            {
                data = db.Set<T>().Where(whereLambda);
            }
            else
            {
                data = db.Set<T>().Where(whereLambda).AsNoTracking();
            }
            if (isAsc)
            {
                data = data.OrderBy(orderLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            }
            else
            {
                data = data.OrderByDescending(orderLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            }
            return await data.ToListAsync();
        }
        #endregion

        #region 09-分頁查詢(根據名稱排序)
        /// <summary>
        /// 分頁查詢輸出總行數(根據名稱排序)
        /// </summary>
        /// <param name="pageIndex">頁碼</param>
        /// <param name="rowCount">輸出的總數量</param>
        /// <param name="whereLambda">查詢條件</param>
        /// <param name="sortName">排序名稱</param>
        /// <param name="sortDirection">asc 或 desc</param>
        ///  <param name="isTrack">是否跟蹤狀態,默認是跟蹤的</param>
        /// <returns></returns>
        public async Task<List<T>> GetPageListByNameAsync<T>(int pageIndex, int pageSize, Expression<Func<T, bool>> whereLambda, string sortName, string sortDirection, bool isTrack = true) where T : class
        {
            List<T> list = null;
            if (isTrack)
            {
                list = await db.Set<T>().Where(whereLambda).DataSorting(sortName, sortDirection)
                 .Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
            }
            else
            {
                list = await db.Set<T>().Where(whereLambda).AsNoTracking().DataSorting(sortName, sortDirection)
                 .Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
            }
            return list;
        }
        #endregion



        //2. SaveChange剝離出來,處理事務

        #region 01-批量處理SaveChange()
        /// <summary>
        /// 事務批量處理
        /// </summary>
        /// <returns></returns>
        public async Task<int> SaveChangeAsync()
        {
            return await db.SaveChangesAsync();
        }
        #endregion

        #region 02-新增
        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="model">需要新增的實體</param>
        public async Task<EntityEntry<T>> AddNoAsync<T>(T model) where T : class
        {
            return await db.AddAsync(model);
        }
        #endregion

        #region 03-根據條件刪除
        /// <summary>
        /// 條件刪除
        /// </summary>
        /// <param name="delWhere">需要刪除的條件</param>
        public async Task DelByNoAsync<T>(Expression<Func<T, bool>> delWhere) where T : class
        {
            List<T> listDels = await db.Set<T>().Where(delWhere).ToListAsync();
            listDels.ForEach(model =>
            {
                db.Entry(model).State = EntityState.Deleted;
            });
        }
        #endregion


        //3. EF調用sql語句

        #region 01-執行增加,刪除,修改操作(或調用存儲過程)
        /// <summary>
        /// 執行增加,刪除,修改操作(或調用存儲過程)
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="pars"></param>
        /// <returns></returns>
        public async Task<int> ExecuteSqlAsync(string sql, params SqlParameter[] pars)
        {
            return await db.Database.ExecuteSqlRawAsync(sql, pars);
        }
        #endregion

    }
View Code

 (3).將程序集的輸出路徑改為:..\YpfCore.AdminWeb\bin\Debug\ ,以便后續與YpfCore.AdminWeb層解耦。

 

分析:這里BaseService采用的是泛型方法而不是泛型類 。

好處:

 在子類Service中,想操控哪張表直接傳入表對應的實體即可,相對靈活。如果用泛型類,子類在實例化的時候已經決定了T的內容,不便於靈活調用各張表。  

4. 幫助類層構建

  暫無必須內容

5. DTO層構建

  暫無必須內容

6. UI層構建

 (1).給YpfCore.AdminWeb層添加對YpfCore.Data、YpfCore.IServie、Ypf.Uitls、YpfCore.DTO層的引用, 同時通過Nuget安裝如下程序集:

 【Autofac 6.0.0】【Autofac.Extensions.DependencyInjection 7.0.2】

 (2). 在Startup中的ConfigureService中添加EFCore上下文的注入,默認使用請求內單例的注入:

   services.AddDbContext<CoreFrameDBContext>(option => option.UseSqlServer(_Configuration.GetConnectionString("EFStr")), ServiceLifetime.Scoped);

 (3).通過AutoFac把YpfCore.Service.dll中所有實現ISupport的接口的(非抽象)類都注冊給實現他的全部接口,且支持在Asp.Net Core中以作用域單例的形式實現構造函數注入。

A. ConfigureService添加的代碼

         /// <summary>
         /// 在這個方法中注冊業務,他在ConfigureService后執行
        /// </summary>
        /// <param name="builder"></param>
        public void ConfigureContainer(ContainerBuilder builder)
        {
           builder.RegisterModule<DefaultModule>();   
        }

B. Auto封裝類

     /// <summary>
    /// 服務於AutoFac
    /// </summary>
    public class DefaultModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            {
                //這里就是AutoFac的注入方式,下面采用常規的方式
                //詳見:https://www.cnblogs.com/yaopengfei/p/9479268.html
                //官網:https://autofac.org/

                //特別注意:其中很大的一個變化在於,Autofac 原來的一個生命周期InstancePerRequest,將不再有效。正如我們前面所說的,整個request的生命周期被ASP.NET Core管理了,
                //所以Autofac的這個將不再有效。我們可以使用 InstancePerLifetimeScope ,同樣是有用的,對應了我們ASP.NET Core DI 里面的Scoped。

                //關於dll路徑的問題:開發環境 需要有 \bin\Debug\netcoreapp3.1\, 而生產環境不需要, 使用AppContext.BaseDirectory來獲取根目錄恰好符合該要求。

                //在普通類中配置文件的讀取麻煩,后面封裝(注:appsettings.json要改為始終復制)
                var Configuration = new ConfigurationBuilder().AddJsonFile(AppContext.BaseDirectory + "appsettings.json").Build();
                var dirName = Configuration["IocDll"];
                Assembly asmService = Assembly.LoadFile(AppContext.BaseDirectory + dirName);

                builder.RegisterAssemblyTypes(asmService)
                       .Where(t => !t.IsAbstract && typeof(ISupport).IsAssignableFrom(t))  //只有實現了ISupport接口的類才進行注冊
                       .AsImplementedInterfaces()    //把一個類注冊給它實現的全部接口
                       .InstancePerLifetimeScope()   //作用域單例(比如Task.Run就是另外一個作用域),而非請求內單例(請求內單例用:InstancePerRequest)
                       .PropertiesAutowired();       //在core里表示在注入類中實現構造函數注入
            }
        }
    }

配置文件

{
  "IocDll": "YpfCore.Service.dll"
}

C. Program中的代碼

  public static IHostBuilder CreateHostBuilder(string[] args) =>
      Host.CreateDefaultBuilder(args)
      .UseServiceProviderFactory(new AutofacServiceProviderFactory())  //Core3.0 后,AutoFac的用法
      .ConfigureWebHostDefaults(webBuilder =>
      {
           webBuilder.UseStartup<Startup>();
      });

PS:這里也可以使用原生反射和Core中自帶的注冊實現,不過AutoFac的功能更加豐富一些。

截止此處,一個最基本的簡單架構已經完成了。

 

三. 基本測試

1.調用模式1

 在YpfCore.AdminWeb層的控制器中注入IBaseService,操控哪張表,調用方法的時候傳入對應表的實體類即可。各種同步、異步的封裝方法詳見BaseService。

代碼分享:

 public void Test3([FromServices] IBaseService _myBaseService)
 {
   //查詢
   var data1 = _myBaseService.Entities<T_SysUser>().Where(u => u.id != "1").ToList();
   var data2 = _myBaseService.GetListBy<T_SysOperLog>(u => u.id != "1");

   //刪除
   var count1 = _myBaseService.DelBy<T_SysLoginLog>(u => u.id != "1");
}

2. 調用模式2

 分別在YpfCore.IService和YpfCore.Service中編寫子類接口ITest1Service和子類Test1Service,Test1Service需要繼承 BaseService, ITest1Service, ISupport,其中ISupport用來標記可以被AutoFac反射。

ITest1Service代碼:

 public interface ITest1Service 
    {
        //測試將業務寫到子Service中封裝
        int Test1();
        int Test2();
    }

Test1Service代碼:

   public class Test1Service : BaseService, ITest1Service, ISupport
    {public Test1Service(CoreFrameDBContext db) : base(db)
        {

        }

        #region 04-測試將業務寫到子Service中封裝
        /// <summary>
        /// 基本操作(推薦用法)
        /// </summary>
        /// <returns></returns>
        public int Test1()
        {
            var data3 = this.GetListBy<T_SysLoginLog>(u => u.id != "ddd");
            var data4 = this.GetListBy<T_SysPermisson>(u => u.id != "ddd");
            T_SysErrorLog s1 = new T_SysErrorLog()
            {
                id = Guid.NewGuid().ToString("N"),
                userId = "111",
                addTime = DateTime.Now
            };
            T_SysLoginLog s2 = new T_SysLoginLog()
            {
                id = Guid.NewGuid().ToString("N"),
                userId = "111",
                loginTime = DateTime.Now
            };
            this.AddNo(s1);
            this.AddNo(s2);
            int result2 = this.SaveChange();
            return 1;
        }
        /// <summary>
        /// SaveChanges事務操作
        /// </summary>
        /// <returns></returns>
        public int Test2()
        {//方案二:直接用父類的db (推薦用法)
            {
                T_SysErrorLog s1 = new T_SysErrorLog()
                {
                    id = Guid.NewGuid().ToString("N"),
                    userId = "111",
                    addTime = DateTime.Now
                };
                T_SysLoginLog s2 = new T_SysLoginLog()
                {
                    id = Guid.NewGuid().ToString("N"),
                    userId = "111",
                    loginTime = DateTime.Now
                };
                db.Add(s1);
                db.Add(s2);
                db.SaveChanges();
            }
            return 111;
        }
        #endregion   
    }

控制器中注入,調用代碼

  public void Test4([FromServices] ITest1Service _test1Service)
   {
            _test1Service.Test1();
            _test1Service.Test2();
   }

 

 

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鵬飛)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 聲     明1 : 如有錯誤,歡迎討論,請勿謾罵^_^。
  • 聲     明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。
 

 


免責聲明!

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



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