歡迎來到《FreeSql.Repository 倉儲模式》系列文檔,本系列文檔專注介紹 【倉儲+工作單元】 的使用方式。完整文檔請前往 wiki 中心:https://github.com/dotnetcore/FreeSql/wiki
UnitOfWork 可将多個倉儲放在一個單元管理執行,最終通用 Commit 執行所有操作,内部采用了資料庫事務;
羅裡吧嗦一堆,簡單點了解:把它看成事務
工作單元定義
public interface IUnitOfWork : IDisposable
{
/// <summary>
/// 開啟事務,或者傳回已開啟的事務
/// </summary>
/// <param name="isCreate">若未開啟事務,則開啟</param>
/// <returns></returns>
DbTransaction GetOrBeginTransaction(bool isCreate = true);
IsolationLevel? IsolationLevel { get; set; }
void Commit();
void Rollback();
}
除上述的定義,我們增加了 IFreeSql Orm 屬性通路原始用法,并且保持在一個事務單元執行。
如何使用
工作單元建議使用 IoC 管理生命周期,否則用起來那叫一個麻煩:
using (var uow = fsql.CreateUnitOfWork())
{
var songRepo = fsql.GetRepository<Song>();
var userRepo = fsql.GetRepository<User>();
songRepo.UnitOfWork = uow; //手工綁定工作單元
userRepo.UnitOfWork = uow;
songRepo.Insert(new Song());
userRepo.Update(...);
uow.Orm.Insert(new Song()).ExecuteAffrows();
//注意:uow.Orm 和 fsql 都是 IFreeSql
//uow.Orm CRUD 與 uow 是一個事務(了解為臨時 IFreeSql)
//fsql CRUD 與 uow 不在一個事務
uow.Commit();
}
依賴注入
以 webapi 類型項目為例,如果注入 IUnitOfWork,一次請求隻能開啟一個工作單元事務。是以我們引入工作單元管理器(UnitOfWorkManager)的概念,負責管理請求内的一組工作單元。
本章節内容有點繁瑣,不過它是一勞永逸的,建議耐着性子看完,并且使用起來。從此不再為事務的用法煩惱掉發……
UnitOfWorkManager 支援六種傳播方式(propagation),意味着跨方法的事務非常友善,并且支援同步異步:
- Requierd:如果目前沒有事務,就建立一個事務,如果已存在一個事務中,加入到這個事務中,預設的選擇。
- Supports:支援目前事務,如果沒有目前事務,就以非事務方法執行。
- Mandatory:使用目前事務,如果沒有目前事務,就抛出異常。
- NotSupported:以非事務方式執行操作,如果目前存在事務,就把目前事務挂起。
- Never:以非事務方式執行操作,如果目前事務存在則抛出異常。
- Nested:以嵌套事務方式執行。
UnitOfWorkManager 成員 | 說明 |
---|---|
IUnitOfWork Current | 傳回目前的工作單元 |
void Binding(repository) | 将倉儲的事務交給它管理 |
IUnitOfWork Begin(propagation, isolationLevel) | 建立工作單元 |
第一步:配置 Startup.cs 注入
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IFreeSql>(fsql);
services.AddScoped<UnitOfWorkManager>();
services.AddFreeRepository(null, typeof(Startup).Assembly);
}
第二步:定義事務特性
[AttributeUsage(AttributeTargets.Method)]
public class TransactionalAttribute : Attribute
{
public Propagation Propagation { get; set; } = Propagation.Requierd;
public IsolationLevel? IsolationLevel { get; set; }
}
第三步:引入動态代理庫
在 Before 從容器中擷取 UnitOfWorkManager,調用它的 var uow = Begin(attr.Propagation, attr.IsolationLevel) 方法
在 After 調用 Before 中的 uow.Commit 或者 Rollback 方法,最後調用 uow.Dispose
第四步:在 Controller 或者 Service 中使用事務特性
public class SongService
{
BaseRepository<Song> _repoSong;
BaseRepository<Detail> _repoDetail;
SongRepository _repoSong2;
public SongService(
BaseRepository<Song> repoSong,
BaseRepository<Detail> repoDetail,
SongRepository repoSong2)
{
_repoSong = repoSong;
_repoDetail = repoDetail;
_repoSong2 = repoSong2;
}
[Transactional]
public virtual void Test1()
{
//這裡 _repoSong、_repoDetail、_repoSong2 所有操作都是一個工作單元
this.Test2();
}
[Transactional(Propagation = Propagation.Nested)]
public virtual void Test2() //嵌套事務,新的(不使用 Test1 的事務)
{
//這裡 _repoSong、_repoDetail、_repoSong2 所有操作都是一個工作單元
}
}
是不是進方法就開事務呢?
不一定是真實事務,有可能是虛的,就是一個假的 unitofwork(不帶事務)
也有可能是延用上一次的事務
也有可能是新開事務,具體要看 Propagation 傳播模式
示範項目:https://github.com/dotnetcore/FreeSql/tree/master/Examples/aspnetcore_transaction
實戰項目:https://github.com/zhontai
系列文章導航
- (一)什麼是倉儲
- (二)如何使用倉儲
- (三)實體特性
- (四)工作單元
- (五)狀态管理
- (六)導航屬性
- (七)多表查詢
- (八)級聯加載
- (九)級聯儲存
- (十)動态實體類型
- (十一)分表
- (十二)如何擴充