知識全聚集 .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 具體的實現
其它類具體的解釋我都寫了注釋,自己下載看吧,