前言
.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类型
+ View Code
2.2仓储接口的实现
+ View Code
3.表部分字段更新实现
EF默认的更新方式是一个实体对应的表全部字段更新,那么我们想更新表的部分字段怎么处理?
首先定义需要更新的字段:
public class PropertyExpression
where T : BaseEntity
{
private PropertyExpression() { }
private static List propertyList = new List();
public static PropertyExpression Init
{
get
{
propertyList.Clear();
return new PropertyExpression();
}
}
public PropertyExpression Property(Expression> 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 ToList()
{
return propertyList;
}
}
EF更新的处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public bool Update(T entity, bool isSaveChange = true, List updatePropertyList = null)
{
if (entity==null)
{
return false;
}
_dbContext.Set().Attach(entity);
if (updatePropertyList==null)
{
_dbContext.Entry(entity).State = EntityState.Modified;//全字段更新
}
else
{
updatePropertyList.ForEach(c => {
_dbContext.Entry(entity).Property(c).IsModified = true; //部分字段更新的写法
});
}
if (isSaveChange)
{
return SaveChanges() > 0;
}
return false;
}
使用
1
2
3
4
5
6
7
8
var entity = _unitOfWork.SysRoleRep.Get(model.RoleId);
if (entity == null)
{
throw new Exception("要查找的对象不存在");
}
entity.Name = model.RoleName;
var updatedPropertyList = PropertyExpression.Init.Property(c => c.Name).ToList();
_unitOfWork.SysRoleRep.Update(entity, true, updatedPropertyList);
4.动态加载实体到DbContext
1
2
3
4
5
6
7
8
9
10
11
public class EntityTypeConfiguration : IEntityTypeConfiguration where T : class
{
public void Configure(EntityTypeBuilder builder)
{
RelyConfigure(builder);
}
public virtual void RelyConfigure(EntityTypeBuilder builder)
{
}
}
1
2
3
4
5
6
7
8
9
10
public class Sys_Error_LogConfiguration : EntityTypeConfiguration
{
public override void RelyConfigure(EntityTypeBuilder builder)
{
builder.ToTable("sys_error_log");
builder.HasKey(x => x.Id);
base.RelyConfigure(builder);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class EfDbContext : DbContext
{
public EfDbContext(DbContextOptions 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
public class EfUnitOfWork : IUnitOfWork
{
private EfDbContext _dbContext;//每次请求上下文只会创建一个
public EfUnitOfWork(EfDbContext context)
{
this._dbContext = context;
}
public int SaveChanges()
{
return _dbContext.SaveChanges();
}
public async Task 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 SqlQuery(string sql, object param = null) where T : class
{
var con= _dbContext.Database.GetDbConnection();
if (con.State!= ConnectionState.Open)
{
con.Open();
}
var list= MysqlDapperReader.SqlQuery(con, sql, param);
return list;
//throw new NotImplementedException();
}
public Task> SqlQueryAsync(string sql, object param = null) where T : class
{
throw new NotImplementedException();
}
#region Sys Repository
private IRepository _sysUserRep;
public IRepository SysUserRep
{
get
{
if (_sysUserRep == null)
{
//var s= HttpContext.Current.Items["currentUser"];
//var s = HttpContext.Current.RequestServices.GetService>();
//HttpContext.RequestServices.GetService>();
_sysUserRep = new Repository(_dbContext);
}
return _sysUserRep;
}
}
private IRepository _sysRoleRep;
public IRepository SysRoleRep
{
get
{
if (_sysRoleRep == null)
{
_sysRoleRep = new Repository(_dbContext);
}
return _sysRoleRep;
}
}
private IRepository _sysRoleUserRep;
public IRepository SysRoleUserRep
{
get
{
if (_sysRoleUserRep == null)
{
_sysRoleUserRep = new Repository(_dbContext);
}
return _sysRoleUserRep;
}
}
private IRepository _sysPermissionRep;
public IRepository SysPermissionRep
{
get
{
if (_sysPermissionRep == null)
{
_sysPermissionRep = new Repository(_dbContext);
}
return _sysPermissionRep;
}
}
private IRepository _sysModuleRep;
public IRepository SysModuleRep
{
get
{
if (_sysModuleRep == null)
{
_sysModuleRep = new Repository(_dbContext);
}
return _sysModuleRep;
}
}
private IRepository _sysErrorLogRep;
public IRepository SysErrorLogRep
{
get
{
if (_sysErrorLogRep == null)
{
_sysErrorLogRep = new Repository(_dbContext);
}
return _sysErrorLogRep;
}
}
private IRepository _sysOperationLogRep;
public IRepository SysOperationLogRep
{
get
{
if (_sysOperationLogRep == null)
{
_sysOperationLogRep = new Repository(_dbContext);
}
return _sysOperationLogRep;
}
}
#endregion
}
6.业务的实现方式
以前我是service中直接创建仓储然后用仓储操作数据库,方式如下:
这种方式比较繁琐,后来我将创建仓储统一放在工作单元中进行,在service中直接创建UnitOfWork,方式如下:
7.Service的动态注册
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static class AutoIocRegister
{
///
/// 动态注入IOC,注意类和接口的命名规则,接口在类名前面加"I"
///
///
/// 程序集名称
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);
}
}
}
调用:
1
services.BatchAddScoped("Cloud.Service");
8.日志记录:
日志分操作日志和错误日志,可以设置在数据库和文本中同时记录:
通过全局过滤器GlobalExceptionFilter和GlobalAuthorizeFilter处理
9.前端的封装(分页、弹出层、ajax等)
先放几张图吧,详细的以后再介绍
演示地址:http://cloud.eggtwo.com/main/index
作者:梦亦晓,转载请注明出处
本人拙作【问卷调查系统】,敬请赐教
如果此文能给您提供帮助,请点击右下角的【推荐】
如果您对此文有不同的见解或者意见,欢迎留言讨论https://www.cnblogs.com/eggTwo/p/9564101.html