.net core已經出來一段時間了,相信你們對.net core的概念已經很清楚了,這裏就再也不贅述。筆者目前也用.net core作過一些項目,而且將之前framework下的一些經驗移植到了.net core下,並結合.net core自己的一些特性整理成此框架,以供學習參考。若有不足之處,歡迎指正。前端
先睹爲快,演示地址:http://cloud.eggtwo.com/main/indexmysql
先來一張總體分層結構圖ajax
基礎層sql
1.Cloud.Core項目是核心項目,主要實現緩存的操做、dapper操做、EF Repository、PageList、日誌等操做數據庫
2.Cloud.Utility屬於幫助類緩存
領域層前端框架
3.Cloud.Entity實體對象,存放數據庫映射實體、Fluent API配置、枚舉字典、DbContext等mvc
4.Cloud.UnitOfWork,操做數據庫的網關,裏面封裝了對倉儲的操做、dapper的操做、事務等app
服務層框架
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等)