前言
ABP
ABP是“ASP.NET Boilerplate Project”的簡稱。
ABP的官方網站:http://www.aspnetboilerplate.com
ABP在Github上的開源項目:https://github.com/aspnetboilerplate
ABP其他學習博客推薦及介紹:http://www.cnblogs.com/mienreal/p/4528470.html
Unit of Work
Unit of Work 又稱之為“工作單元”,Unit of Work的相關概念及介紹,請移步另一篇博客:設計模式/原則篇 - Unit of Work。
在ABP中,因為不能確定開發人員實際使用的ORM和數據訪問層具體是什么,為了更好的擴展性,ABP為Unit of Work封裝了一套通用接口抽象,並提供了Entity Framework及NHibernate的實現。
使用
默認行為
在ABP中,ApplicationService(領域服務,實現IApplicationService接口的類)和Repository(實現IRepository接口的類)的每個方法默認都是一個工作單元。在方法的起始處就開始了一個事務,在方法的結束時,事務也會自動提交,如果這個方法中拋出了異常,事務會自動回滾。
public interface ISimpleAppService : IApplicationService { void ComplexOperation(); } public class SimpleAppService : ISimpleAppService { public void ComplexOperation() { //該方法默認就是一個工作單元 } } public interface ISimpleRepository : IRepository<Simple, string> { List<Simple> GetAllByName(string name); } public class SimpleRepository : ABPRepositoryBase<Simple, long>, ISimpleRepository { public List<Simple> GetAllByName(string name) { //該方法默認就是一個工作單元,ABPRepositoryBase默認有一些公共方法的實現,比如GetAll、Update這些 } }
UnitOfWorkAttribute
另一種添加Unit of Work的方式,便是在方法上面添加UnitOfWork特性,這樣便和上面的默認行為相同,該方法成為一個工作單元。
UnitOfWork特性,還包含一系列參數,Scope(事務參數)、IsTransactional(工作單元是否是事務)、Timeout(超時時間)、IsolationLevel(事務隔離級別)、IsDisabled(是否禁用工作單元,這個屬性用於關閉領域服務和倉儲庫默認的方法即工作單元的設置)。
public class TempService { [UnitOfWork] public void Method() { //TempService不是領域服務,沒有實現IApplicationService接口,但是通過UnitOfWorkAttribute,使Method也成為一個工作單元 } }重要
標記UnitOfWork特性的方法的所在類,需要注冊到IoC容器中,並通過IoC容器進行創建,類和方法的可訪問級別需要為public或protected,因為ABP通過動態代理實現AOP進行切面編程,具體緣由將在ABP使用及框架解析系列 - [Unit of Work part.2-框架實現]中解析。
IUnitOfWorkManager
上面兩種方式,其內部都是使用IUnitOfWorkManager進行單元控制的,所以我們也可以直接通過IUnitOfWorkManager進行控制,如下代碼所示:
public class TempService { private IUnitOfWorkManager _uowManager; private ITempRepository _tempRsy; public TempService(IUnitOfWorkManager uowManager, ITempRepository tempRsy) { this._uowManager = uowManager; this._tempRsy = tempRsy; } public void Method() { using (var uow = _uowManager.Begin()) { _tempRsy.Insert(new Temp()); _tempRsy.Delete(1); uow.Complete(); } } }TempService並非領域服務,沒有實現IApplicationService接口,所以Method方法默認不是一個工作單元。在Method內部,使用using塊便是一個工作單元,通過uow.Complete()進行提交,如果出現異常,會自動回滾。
IUnitOfWorkManager的Begin方法可接受一系列參數對工作單元或事務進行設置,在這里就不對每個參數進行詳細說明了。如有疑問,大家都已在評論中進行討論。
上述三種方式為Unit of Work在ABP中的使用方式,下面還有一些ABP中Unit of Work的特性、配置及注意事項。
全局/默認配置
不論是在使用Attribute還是IUnitOfWorkManager,都是可以進行一些參數設置的,但是同時也是可以不對其進行設置的,當不對其進行設置時,將會使用默認參數,而這個默認參數,可以通過一個全局配置進行修改。
ABP有一個IUnitOfWorkDefaultOptions接口,並且通過IoC與UnitOfWorkDefaultOptions進行了單例依賴注冊,所以通過IoC容器獲取IUnitOfWorkDefaultOptions實例時,可以獲取到Unit of Work全局默認配置,通過修改這個對象里的參數,可以修改其默認配置。但是需要注意的是,這個配置是一個全局配置,所以隨便在一個地方就進行修改不是一個好的做法。
ABP中有一個模塊(AbpModule)的概念,推薦在主項目的模塊類的PreInitialize方法中進行修改。ABP也為此提供了更加便捷的方式進行修改默認配置,AbpModule類下有一個Configuration屬性,該屬對象齊聚了很多配置項,其中UnitOfWork屬性便是IUnitOfWorkDefaultOptions接口對象,通過這個便可方便的修改默認配置了。
其他特性
1.支持多個工作單元嵌套,它們共用最外層的工作單元。但如果嵌套的工作單元在不同主線程上,則每個主線程會有一個不同的工作單元,具體實現將在ABP使用及框架解析系列 - [Unit of Work part.2-框架實現]中解析。
2.在工作單元中,進行數據查詢,如有返回IQueryable,需要再工作單元內進行ToList或ToArray等操作,因為返回IQueryable對象時並沒有進行真正的數據操作(延遲執行),而數據庫連接會在工作單元結束后關閉,所以如果再工作單元結束后進行ToList等操作,會拋出異常(當然,這里說的是ABP提供的NH和Ef的實現,自己實現ABP接口可以自行限制)。
3.Unit of Work除了提供了Complete外,還提供了SaveChanges方法,用於先行提交數據。在Entity主鍵為自增ID,並且后續操作需要這個ID時,可以通過先SaveChanges來提交數據來獲取自增ID值。
4.在使用ABP提供的EF實現中,在工作單元中對Entity進行修改后,即使不手動調用Update,在UoW結束時也會自動保存修改,因為Ef對Entity的狀態進行了跟蹤,並且在UoW進行Complete操作前,會先SaveChanges(NH沒有仔細研究)。
5.可以為Unit of Work注冊三個事件:Completed、Failed、Disposed。這三個事件,在IUnitOfWorkManager對象的Current屬性定義。
框架實現
由於框架實現內容較多,為了不導致篇幅過長,框架實現部分,請移步 ABP使用及框架解析系列 - [Unit of Work part.2-框架實現]