知识全聚集 .Net Core 技术突破 | 简单说说工作单元
知识全聚集 .Net Core 技术突破 | 简单说说工作单元
教程
其他教程预览
分库分表项目实战教程
Git地址: https://github.com/MrChuJiu/EasyLogger
从10.1到现在都太忙了,好久没更新文章了,也主要因为 工作单元这个东西我也是不知道该怎么才能讲明白,很多东西需要靠自己的一个理解。
今天可以稍微讲一下,看完这篇文章在对应源码去看,我觉得就会舒服很多。
本文章请一定要配合源码食用,注释都在源码里写好了。
https://github.com/MrChuJiu/Easy.Core.Flow
简单说说运行路线
工作单元的开始入口是从 AspNetCoreUowMiddleware
中间件开始的
1.判断是否匹配到了路由地址
2.判断是否携带 UnitOfWorkAttribute 属性 如果携带了获取属性值
3.判断是否携带了属性中禁用工作单元,如果是直接跳出该中间件
4.获取链接字符串名称 启动一个工作单元包裹当前中间件
5.接口操作结束后 判断相应状态提交工作单元
先看主要的文件和描述
接口文件 | 描述 | 实现 |
---|---|---|
IUnitOfWork | 工作单元实例 | UnitOfWorkBase |
ICurrentUnitOfWorkProvider | 工作单元提供者 | AsyncLocalCurrentUnitOfWorkProvider |
IUnitOfWorkManager | 工作单元管理器 | DefaultUnitOfWorkManager |
一个基础的EF工作单元操作(记住这个概念我们接下来看代码)
var unitOfWorkManager = scopeServiceProvider.GetService<IUnitOfWorkManager>();
using (var uow = unitOfWorkManager.Begin())
{
var appContext = unitOfWorkManager.Current.GetDbContext<AppDbContext>();
var user = new User();
user.Creator = "Creator";
appContext.Users.Add(user);
await uow.CompleteAsync();
}
表面通过 工作单元管理器创建一个工作单元实例 IUnitOfWork 实例
内部: 工作单元管理器中 将 工作单元配置参数(事务级别/事务范围/超时/事件/连接字符串显示名称) 存放到工作单元提供者后续 提供给具体实现进行使用
IUnitOfWorkManager 工作单元管理器
Begin() 方法返回的是一个类型为 IUnitOfWorkCompleteHandle 工作单元事件处理器 主要看继承他的方法
一:InnerUnitOfWorkCompleteHandle
主要调用 Complete()/CompleteAsync() 会将 _isCompleteCalled 置为 true,然后在 Dispose() 方法内会进行检测,为 faslse 的话直接抛出异常。
可以看到在 InnerUnitOfWorkCompleteHandle 内部并不会真正地调用 DbContext.SaveChanges() 进行数据保存。
该类可以在 Begin() 方法中看到在创建 UOW 对象的时候,他在内部进行了一个判断,如果不存在外部工作单元的情况下才会创建 InnerUnitOfWorkCompleteHandle 对象,否则是解析的一个 IUnitOfWork 对象。
请下载代码调试
using (var scope = app.ApplicationServices.CreateScope())
{
var scopeServiceProvider = scope.ServiceProvider;
var unitOfWorkManager = scopeServiceProvider.GetService<IUnitOfWorkManager>();
using (var outerUOW1 = unitOfWorkManager.Begin()) // 这里返回的是 IOC 解析出的 IUnitOfWork
{
var appContext1 = unitOfWorkManager.Current.GetDbContext<AppDbContext>();
var user1 = new User();
user1.Creator = "Creator1111";
appContext1.Users.Add(user1);
using (var innerUOW2 = unitOfWorkManager.Begin()) // 内部 UOW
{
var appContext2 = unitOfWorkManager.Current.GetDbContext<AppDbContext>();
var user2 = new User();
user2.Creator = "Creator222";
appContext2.Users.Add(user2);
using (var innerUOW3 = unitOfWorkManager.Begin()) // 内部 UOW
{
var appContext3 = unitOfWorkManager.Current.GetDbContext<AppDbContext>();
var user3 = new User();
user3.Creator = "Creator333";
appContext3.Users.Add(user3);
await innerUOW3.CompleteAsync();
}
await innerUOW2.CompleteAsync();
}
await outerUOW1.CompleteAsync();
}
}
二:IUnitOfWork
Id 是使用的 Guid 生成的,用于标识每个工作单元。
Outer 则是当前 UOW 对象的引用对象
Begin 根据工作单元选项创建(各个ORM启动工作单元的方式不同,让他们各自去继承实现)
EfCoreUnitOfWork -> UnitOfWorkBase -> IUnitOfWork
ICurrentUnitOfWorkProvider 工作单元提供者
我们在 UnitOfWorkManager.Begin() 方法最后一行 _currentUnitOfWorkProvider.Current = uow;
_currentUnitOfWorkProvider 的实现在 AsyncLocalCurrentUnitOfWorkProvider 内部,其作用是维护一个 UOW 链 确保当前的工作单元始终是最新的
重点是 value.Outer = AsyncLocalUow.Value.UnitOfWork; = IUnitOfWork.Outer
电脑截图有限最好下载代码去对着文章自己过一下
EfCoreUnitOfWork 落实到EFCore实际处理
EfCoreUnitOfWork -> UnitOfWorkBase -> IUnitOfWork
随随便便结尾
IUnitOfWork、ICurrentUnitOfWorkProvider、IUnitOfWorkManager 实现原理
EfCoreUnitOfWork 具体的实现
其它类具体的解释我都写了注释,自己下载看吧,