• 第一节:框架基础架构构建(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.AdminWebinDebug ,以便后续与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路径的问题:开发环境 需要有 inDebug
    etcoreapp3.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 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    linux中read用法
    apt-get 使用指南
    linux文件系统
    KMP
    在C#中的各种应用
    A*算法,遗传算法
    Dijkstra算法,Floyd算法
    AE开发tips
    TOC 右键菜单
    ubuntu下的一些意外
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/14226644.html
Copyright © 2020-2023  润新知