zoukankan      html  css  js  c++  java
  • 基于.net core 2.0+mysql+AceAdmin搭建一套快速开发框架

    前言

    .net core已经出来一段时间了,相信大家对.net core的概念已经很清楚了,这里就不再赘述。笔者目前也用.net core做过一些项目,并且将以前framework下的一些经验移植到了.net core下,并结合.net core本身的一些特性整理成此框架,以供学习参考。如有不足之处,欢迎指正。

     先睹为快,演示地址http://cloud.eggtwo.com/main/index

    框架介绍

    先来一张整体分层结构图

    基础层

    1.Cloud.Core项目是核心项目,主要实现缓存的操作、dapper操作、EF Repository、PageList、日志等操作

    2.Cloud.Utility属于帮助类

    领域层

    3.Cloud.Entity实体对象,存放数据库映射实体、Fluent API配置、枚举字典、DbContext等

    4.Cloud.UnitOfWork,操作数据库的网关,里面封装了对仓储的操作、dapper的操作、事务等

    服务层

    5.Cloud.Service 业务逻辑的实现

    6.Cloud.Dto 数据传输对象,实体对象不直接和表现层接触,通过dto互转

    表现层

    7.Cloud.Framework,表现层框架,封装了超类controller,全局授权过滤器,全局异常过滤器,ActionFilter,HtmlHelper等操作

    8.Cloud.Boss 启动项目

    使用的技术

     基于.net core 2.0的asp.net core mvc

     基于.net core 2.0的ef

    dapper

    mysql

     前端框架 aceAdmin

    技术要点

    1.实体基类定义

     2.泛型仓储的封装

    2.1仓储接口的定义,泛型约束T必须是BaseEntity类型

    public interface IRepository<T> where T : BaseEntity
        {
            DatabaseFacade Database { get; }
            IQueryable<T> Entities { get; }
            int SaveChanges();
            Task<int> SaveChangesAsync();
            void Disposed();
    
            bool Delete(List<T> entitys, bool isSaveChange = true);
            bool Delete(T entity, bool isSaveChange = true);
            Task<bool> DeleteAsync(List<T> entitys, bool isSaveChange = true);
            Task<bool> DeleteAsync(T entity, bool isSaveChange = true);
          
            Task<T> GetAsync(Expression<Func<T, bool>> predicate = null);
            Task<List<T>> GetListAsync(Expression<Func<T, bool>> predicate = null);
            T Get(object id);
            T Get(Expression<Func<T, bool>> predicate = null);
            Task<T> GetAsync(object id);
            Task<IQueryable<T>> LoadAsync(Expression<Func<T, bool>> predicate = null);
    
            bool Insert(List<T> entitys, bool isSaveChange = true);
            bool Insert(T entity, bool isSaveChange = true);
            Task<bool> InsertAsync(List<T> entitys, bool isSaveChange = true);
            Task<bool> InsertAsync(T entity, bool isSaveChange = true);
          
            bool Update(List<T> entitys, bool isSaveChange = true);
            bool Update(T entity, bool isSaveChange = true, List<string> updatePropertyList = null);
            Task<bool> UpdateAsync(List<T> entitys, bool isSaveChange = true);
            Task<bool> UpdateAsync(T entity, bool isSaveChange = true, List<string> updatePropertyList = null);
    
    
        }
    

      

    2.2仓储接口的实现

      public class Repository<T> : IRepository<T> where T : BaseEntity
        {
            DbContext _dbContext;
            public Repository(DbContext dbContext)
            {
                _dbContext = dbContext;
            }
            public int SaveChanges()
            {
                return _dbContext.SaveChanges();
            }
            public async Task<int> SaveChangesAsync()
            {
                return await _dbContext.SaveChangesAsync();
            }
            public void Disposed()
            {
                throw new Exception("不允许在这里释放上下文,请在UnitOfWork中操作");
                _dbContext.Dispose();
            }
            #region 插入数据
            public bool Insert(T entity, bool isSaveChange = true)
            {
                _dbContext.Set<T>().Add(entity);
                if (isSaveChange)
                {
                    return SaveChanges() > 0;
                }
                return false;
            }
            public async Task<bool> InsertAsync(T entity, bool isSaveChange = true)
            {
                _dbContext.Set<T>().Add(entity);
                if (isSaveChange)
                {
                    return await SaveChangesAsync() > 0;
                }
                return false;
            }
            public bool Insert(List<T> entitys, bool isSaveChange = true)
            {
                _dbContext.Set<T>().AddRange(entitys);
                if (isSaveChange)
                {
                    return SaveChanges() > 0;
                }
                return false;
            }
            public async Task<bool> InsertAsync(List<T> entitys, bool isSaveChange = true)
            {
                _dbContext.Set<T>().AddRange(entitys);
                if (isSaveChange)
                {
                    return await SaveChangesAsync() > 0;
                }
                return false;
            }
            #endregion
    
            #region 更新数据
            public bool Update(T entity, bool isSaveChange = true, List<string> updatePropertyList = null)
            {
                if (entity==null)
                {
                    return false;
                }
                _dbContext.Set<T>().Attach(entity);
                if (updatePropertyList==null)
                {
                    _dbContext.Entry<T>(entity).State = EntityState.Modified;//全字段更新
    
                }
                else
                {
                    updatePropertyList.ForEach(c => {
                        _dbContext.Entry(entity).Property(c).IsModified = true; //部分字段更新的写法
    
                    });
    
                }
                if (isSaveChange)
                {
                    return SaveChanges() > 0;
                }
                return false;
            }
            public bool Update(List<T> entitys, bool isSaveChange = true)
            {
                if (entitys==null||entitys.Count==0)
                {
                    return false;
                }
                entitys.ForEach(c => {
                    Update(c, false);
                });
                if (isSaveChange)
                {
                    return SaveChanges() > 0;
                }
                return false;
            }
            public async Task<bool> UpdateAsync(T entity, bool isSaveChange = true, List<string> updatePropertyList = null)
            {
                if (entity == null)
                {
                    return false;
                }
                _dbContext.Set<T>().Attach(entity);
                if (updatePropertyList == null)
                {
                    _dbContext.Entry<T>(entity).State = EntityState.Modified;//全字段更新
    
                }
                else
                {
                    updatePropertyList.ForEach(c => {
                        _dbContext.Entry(entity).Property(c).IsModified = true; //部分字段更新的写法
    
                    });
    
                }
                if (isSaveChange)
                {
                    return await SaveChangesAsync() > 0;
                }
                return false;
            }
            public async Task<bool> UpdateAsync(List<T> entitys, bool isSaveChange = true)
            {
                if (entitys == null || entitys.Count == 0)
                {
                    return false;
                }
                entitys.ForEach(c => {
                    _dbContext.Set<T>().Attach(c);
                    _dbContext.Entry<T>(c).State = EntityState.Modified;
                });
                if (isSaveChange)
                {
                    return await SaveChangesAsync() > 0;
                }
                return false;
            }
            #endregion
    
            #region 删除
            public bool Delete(T entity, bool isSaveChange = true)
            {
                _dbContext.Set<T>().Attach(entity);
                _dbContext.Set<T>().Remove(entity);
                return isSaveChange ? SaveChanges() > 0 : false;
            }
            public bool Delete(List<T> entitys, bool isSaveChange = true)
            {
                entitys.ForEach(entity =>
                {
                    _dbContext.Set<T>().Attach(entity);
                    _dbContext.Set<T>().Remove(entity);
                });
                return isSaveChange ? SaveChanges() > 0 : false;
            }
    
            public virtual async Task<bool> DeleteAsync(T entity, bool isSaveChange = true)
            {
    
                _dbContext.Set<T>().Attach(entity);
                _dbContext.Set<T>().Remove(entity);
                return isSaveChange ? await SaveChangesAsync() > 0 : false;
            }
            public virtual async Task<bool> DeleteAsync(List<T> entitys, bool isSaveChange = true)
            {
                entitys.ForEach(entity =>
                {
                    _dbContext.Set<T>().Attach(entity);
                    _dbContext.Set<T>().Remove(entity);
                });
                return isSaveChange ? await SaveChangesAsync() > 0 : false;
            }
            #endregion
    
            public IQueryable<T> Entities => _dbContext.Set<T>().AsQueryable().AsNoTracking();
            //public async Task<IQueryable<T>> EntitiesAsync => Task.Run(()=> _dbContext.Set<T>().AsQueryable().AsNoTracking()); 
    
            public DatabaseFacade Database => _dbContext.Database;
            #region 查找
            public T Get(object id)
            {
                return _dbContext.Set<T>().Find(id);
            }
            public T Get(Expression<Func<T, bool>> predicate = null)
            {
                return _dbContext.Set<T>().Where(predicate).AsNoTracking().FirstOrDefault();
            }
            public async Task<T> GetAsync(object id)
            {
                return await _dbContext.Set<T>().FindAsync(id);
            }
            public async Task<T> GetAsync(Expression<Func<T, bool>> predicate = null)
            {
                return await _dbContext.Set<T>().Where(predicate).AsNoTracking().FirstOrDefaultAsync();
            }
            public async Task<List<T>> GetListAsync(Expression<Func<T, bool>> predicate = null)
            {
                return await _dbContext.Set<T>().Where(predicate).AsNoTracking().ToListAsync();
            }
            public async Task<IQueryable<T>> LoadAsync(Expression<Func<T, bool>> predicate = null)
            {
                if (predicate == null)
                {
                    predicate = c => true;
                }
                return await Task.Run(() => _dbContext.Set<T>().Where(predicate).AsNoTracking());
            }
    
            public void Dispose()
            {
                throw new NotImplementedException();
            }
            #endregion
    
        }
    

      

    3.表部分字段更新实现

    EF默认的更新方式是一个实体对应的表全部字段更新,那么我们想更新表的部分字段怎么处理?

    首先定义需要更新的字段:

       public class PropertyExpression<T> where T : BaseEntity
        {
            private PropertyExpression() { }
            private static List<string> propertyList = new List<string>();
            public static PropertyExpression<T> Init
            {
                get
                {
                    propertyList.Clear();
                    return new PropertyExpression<T>();
                }
            }
    
            public PropertyExpression<T> Property(Expression<Func<T, object>> expr)
            {
                var rtn = "";
                if (expr.Body is UnaryExpression)
                {
                    rtn = ((MemberExpression)((UnaryExpression)expr.Body).Operand).Member.Name;
                }
                else if (expr.Body is MemberExpression)
                {
                    rtn = ((MemberExpression)expr.Body).Member.Name;
    
                }
                else if (expr.Body is ParameterExpression)
                {
                    rtn = ((ParameterExpression)expr.Body).Type.Name;
                }
                propertyList.Add(rtn);
                return this;
            }
            public List<string> ToList()
            {
                return propertyList;
            }
    
        }
    

      EF更新的处理

     public bool Update(T entity, bool isSaveChange = true, List<string> updatePropertyList = null)
            {
                if (entity==null)
                {
                    return false;
                }
                _dbContext.Set<T>().Attach(entity);
                if (updatePropertyList==null)
                {
                    _dbContext.Entry<T>(entity).State = EntityState.Modified;//全字段更新
    
                }
                else
                {
                    updatePropertyList.ForEach(c => {
                        _dbContext.Entry(entity).Property(c).IsModified = true; //部分字段更新的写法
    
                    });
    
                }
                if (isSaveChange)
                {
                    return SaveChanges() > 0;
                }
                return false;
            }
    

      使用

     var entity = _unitOfWork.SysRoleRep.Get(model.RoleId);
                        if (entity == null)
                        {
                            throw new Exception("要查找的对象不存在");
                        }
                        entity.Name = model.RoleName;
                        var updatedPropertyList = PropertyExpression<Sys_Role>.Init.Property(c => c.Name).ToList();
                        _unitOfWork.SysRoleRep.Update(entity, true, updatedPropertyList);
    

      

    4.动态加载实体到DbContext

     public class EntityTypeConfiguration<T> : IEntityTypeConfiguration<T> where T : class
        {
            public void Configure(EntityTypeBuilder<T> builder)
            {
                RelyConfigure(builder);
            }
            public virtual void RelyConfigure(EntityTypeBuilder<T> builder)
            {
    
            }
        }
    

      

    public class Sys_Error_LogConfiguration : EntityTypeConfiguration<Sys_Error_Log>
        {
            public override void RelyConfigure(EntityTypeBuilder<Sys_Error_Log> builder)
            {
                builder.ToTable("sys_error_log");
                builder.HasKey(x => x.Id);
                base.RelyConfigure(builder);
            }
    
        }
    

      

      public class EfDbContext : DbContext
        {
            public EfDbContext(DbContextOptions<EfDbContext> options) : base(options)
            {
    
            }
            //配置数据库连接
            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
               // optionsBuilder.UseSqlServer("xxxx connection string");
                base.OnConfiguring(optionsBuilder);
            }
           
            //第一次使用EF功能时执行一次,以后不再执行
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                //获取当前程序集中有基类并且基类是泛型的类
                var typesToRegister = Assembly.GetExecutingAssembly().GetTypes().Where(c => c.BaseType != null && c.BaseType.IsGenericType).ToList();
                foreach (var type in typesToRegister)
                {
                    //泛型定义相同
                    if (type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>))
                    {
                        dynamic configurationInstance = Activator.CreateInstance(type);
                        modelBuilder.ApplyConfiguration(configurationInstance);
                    }
    
    
                }
    
               base.OnModelCreating(modelBuilder);
            }
        }
    

      

    5.工作单元

    工作单元是对仓储和事务的封装

    原理参考:https://docs.microsoft.com/zh-cn/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

       public class EfUnitOfWork : IUnitOfWork
        {
            private EfDbContext _dbContext;//每次请求上下文只会创建一个
            public EfUnitOfWork(EfDbContext context)
            {
                this._dbContext = context;
            }
            public int SaveChanges()
            {
    
                return _dbContext.SaveChanges();
            }
            public async Task<int> SaveChangesAsync()
            {
                return await _dbContext.SaveChangesAsync();
            }
            private bool disposed = false;
    
            protected virtual void Dispose(bool disposing)
            {
                if (!this.disposed)
                {
                    if (disposing)
                    {
                        _dbContext.Dispose();//随着工作单元的销毁而销毁
                    }
                }
                this.disposed = true;
            }
    
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
            public IDbContextTransaction BeginTransaction()
            {
                var scope = _dbContext.Database.BeginTransaction();
                return scope;
            }
    
            public List<T> SqlQuery<T>(string sql, object param = null) where T : class
            {
                var con= _dbContext.Database.GetDbConnection();
                if (con.State!= ConnectionState.Open)
                {
                    con.Open();
                }
                var list= MysqlDapperReader.SqlQuery<T>(con, sql, param);
                return list;
                //throw new NotImplementedException();
            }
    
            public Task<List<T>> SqlQueryAsync<T>(string sql, object param = null) where T : class
            {
                throw new NotImplementedException();
            }
    
    
    
            #region Sys Repository
            private IRepository<Sys_User> _sysUserRep;
            public IRepository<Sys_User> SysUserRep
            {
                get
                {
                    if (_sysUserRep == null)
                    {
                        //var s= HttpContext.Current.Items["currentUser"];
                        //var s = HttpContext.Current.RequestServices.GetService<IRepository<Sys_User>>();
                        //HttpContext.RequestServices.GetService<IRepository<Sys_User>>();
                        _sysUserRep = new Repository<Sys_User>(_dbContext);
                    }
                    return _sysUserRep;
                }
            }
            private IRepository<Sys_Role> _sysRoleRep;
            public IRepository<Sys_Role> SysRoleRep
            {
                get
                {
                    if (_sysRoleRep == null)
                    {
                        _sysRoleRep = new Repository<Sys_Role>(_dbContext);
                    }
                    return _sysRoleRep;
                }
            }
            private IRepository<Sys_Role_User> _sysRoleUserRep;
            public IRepository<Sys_Role_User> SysRoleUserRep
            {
                get
                {
                    if (_sysRoleUserRep == null)
                    {
                        _sysRoleUserRep = new Repository<Sys_Role_User>(_dbContext);
                    }
                    return _sysRoleUserRep;
                }
            }
    
            private IRepository<Sys_Permission> _sysPermissionRep;
            public IRepository<Sys_Permission> SysPermissionRep
            {
                get
                {
                    if (_sysPermissionRep == null)
                    {
                        _sysPermissionRep = new Repository<Sys_Permission>(_dbContext);
                    }
                    return _sysPermissionRep;
                }
            }
            private IRepository<Sys_Module> _sysModuleRep;
            public IRepository<Sys_Module> SysModuleRep
            {
                get
                {
                    if (_sysModuleRep == null)
                    {
                        _sysModuleRep = new Repository<Sys_Module>(_dbContext);
                    }
                    return _sysModuleRep;
                }
            }
    
            private IRepository<Sys_Error_Log> _sysErrorLogRep;
            public IRepository<Sys_Error_Log> SysErrorLogRep
            {
                get
                {
                    if (_sysErrorLogRep == null)
                    {
                        _sysErrorLogRep = new Repository<Sys_Error_Log>(_dbContext);
                    }
                    return _sysErrorLogRep;
                }
            }
    
            private IRepository<Sys_Operation_Log> _sysOperationLogRep;
            public IRepository<Sys_Operation_Log> SysOperationLogRep
            {
                get
                {
                    if (_sysOperationLogRep == null)
                    {
                        _sysOperationLogRep = new Repository<Sys_Operation_Log>(_dbContext);
                    }
                    return _sysOperationLogRep;
                }
            } 
            #endregion
    
        }
    

    6.业务的实现方式

     以前我是service中直接创建仓储然后用仓储操作数据库,方式如下:

    这种方式比较繁琐,后来我将创建仓储统一放在工作单元中进行,在service中直接创建UnitOfWork,方式如下:

    7.Service的动态注册

    public static class AutoIocRegister
        {
            /// <summary>
            /// 动态注入IOC,注意类和接口的命名规则,接口在类名前面加"I"
            /// </summary>
            /// <param name="services"></param>
            /// <param name="assemblyName">程序集名称</param>
            public static void BatchAddScoped(this IServiceCollection services, string assemblyName)
            {
                var libs = DependencyContext.Default.CompileLibraries;
                var serviceLib = libs.Where(c => c.Name.Contains(assemblyName)).FirstOrDefault();
                var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(serviceLib.Name));
                var serviceClassList = assembly.GetTypes().Where(c => c.IsClass).ToList();
                foreach (var item in serviceClassList)
                {
                    var interfaceName = "I" + item.Name;
                    var interfaceType = assembly.GetTypes().Where(c => c.IsInterface && c.Name == interfaceName).FirstOrDefault();
                    if (interfaceType == null) continue;
                    services.AddScoped(interfaceType, item);
                }
            }
        } 

    调用:

     services.BatchAddScoped("Cloud.Service");
    

    8.日志记录:

    日志分操作日志和错误日志,可以设置在数据库和文本中同时记录:

    通过全局过滤器GlobalExceptionFilter和GlobalAuthorizeFilter处理

     

    9.前端的封装(分页、弹出层、ajax等)

    先放几张图吧,详细的以后再介绍

     演示地址:http://cloud.eggtwo.com/main/index

  • 相关阅读:
    Android popupwindow 失去焦点或者点击空白区域时消失的解决方法
    九度 题目1394:五连击数组
    地市级地铁数据管理信息系统解决方式
    用位运算实现两个整数的加法运算
    Leaflet--建设移动设备友好的互动地图
    atitit.自适应设计悬浮图片的大小and 位置
    PIM-DM协议内核触发机制及协议执行机制记录
    整合struts2+spring+hibernate
    UITableViewCell的prepareForReuse方法
    《linux 内核全然剖析》编译linux 0.12 内核 Ubuntu 64bits 环境
  • 原文地址:https://www.cnblogs.com/eggTwo/p/9564101.html
Copyright © 2011-2022 走看看