ABP框架详解(三)Domain
此處的Domain主要指Abp類(lèi)庫(kù)根目錄下Domain文件夾。顧名思義該目錄下是用來(lái)存放與領(lǐng)域?qū)嶓w,領(lǐng)域邏輯執(zhí)行,存儲(chǔ),領(lǐng)域服務(wù)相關(guān)的內(nèi)容。
1.Entities
(1)為整個(gè)Abp框架后期開(kāi)發(fā)的所有實(shí)體Model提供接口及基礎(chǔ)實(shí)現(xiàn),總的來(lái)講為實(shí)現(xiàn)某種規(guī)范的接口都擁有兩個(gè),一個(gè)是主鍵數(shù)據(jù)類(lèi)型為泛型的實(shí)現(xiàn),另一個(gè)則是繼承該泛型接口并為泛型提供一個(gè)默認(rèn)的數(shù)據(jù)類(lèi)型,例如IEntity<TPrimaryKey>的屬性Id就為T(mén)PrimaryKey類(lèi)型,另一個(gè)接口IEntity只是接單的繼承上述接口并指定一個(gè)int型public interface IEntity : IEntity<int>,最基本的模型接口IEntity<TPrimaryKey>提供了一個(gè)實(shí)現(xiàn)類(lèi)public abstract class Entity<TPrimaryKey>,提供了對(duì)象比較功能,bool Equals(object obj)和int GetHashCode()方法。Entities提供了一個(gè)IMayHaveTenant接口只有一個(gè)可空的TenantId屬性,用于確定實(shí)體是否屬于應(yīng)用級(jí)別的(值為空)或者租戶級(jí)別以及哪個(gè)租戶,在后面的EF的DynamicFilter也會(huì)用到。同時(shí)提供了一個(gè)IMustHaveTenant接口含有一個(gè)不可空的TenantId屬性,指明實(shí)體對(duì)象屬于哪個(gè)租戶所有,IPassivable接口包含一個(gè)IsActive的布爾類(lèi)型的屬性,用以指明實(shí)體對(duì)象是否激活狀態(tài)。ISoftDelete是為軟刪除設(shè)計(jì)模式設(shè)計(jì)的布爾類(lèi)型的IsDeleted屬性表明實(shí)體記錄是否已被刪除,對(duì)于EF搜索可用對(duì)象集合十分有幫助,ISoftDelete接口擁有一個(gè)擴(kuò)展方法bool IsNullOrDeleted(this ISoftDelete entity)可以方便表明對(duì)象是否屬于已刪除狀態(tài)。
(2)Entities為框架額外提供了一個(gè)審計(jì)模型接口包括一些基類(lèi)實(shí)現(xiàn),用以在實(shí)體對(duì)象中保存相關(guān)信息如:創(chuàng)建人,刪除人,更新人,更新時(shí)間用以保存到持久化設(shè)備中。所有的設(shè)計(jì)類(lèi)型都有泛型類(lèi)型(主要用于指定主鍵類(lèi)型)和默認(rèn)類(lèi)型(指明主鍵的類(lèi)型)。同時(shí)還有一個(gè)兩個(gè)泛型參數(shù)的版本,用以設(shè)置一個(gè)外鍵方便跳轉(zhuǎn)到相應(yīng)實(shí)體。
public abstract class CreationAuditedEntity<TPrimaryKey, TUser> : CreationAuditedEntity<TPrimaryKey>, ICreationAudited<TUser>where TUser : IEntity<long>{/// <summary>/// Reference to the creator user of this entity./// </summary>[ForeignKey("CreatorUserId")]public virtual TUser CreatorUser { get; set; }}- CreationAuditedEntity<TPrimaryKey>,如果模型實(shí)例僅需記錄創(chuàng)建者ID和創(chuàng)建時(shí)間,那么繼承該抽象類(lèi)就可以了,此時(shí)也無(wú)需再繼承Entity<TPrimaryKey>抽象類(lèi)就已經(jīng)是一個(gè)符合領(lǐng)域規(guī)范的實(shí)體了。
- AuditedEntity<TPrimaryKey>,繼承于第一個(gè)泛型類(lèi),同時(shí)添加了可空的修改人Id和修改時(shí)間
- FullAuditedEntity<TPrimaryKey>,為了方便實(shí)體記錄中添加創(chuàng)建人,修改人,是否已處于刪除狀態(tài),還有刪除人,刪除時(shí)間,提供了此類(lèi)包含上述所有需要記錄的信息。
2.Policies
只是提供了一個(gè)IPolicy接口,無(wú)任何實(shí)現(xiàn)。
3.Repositories
(1)IRepository空接口用以表明實(shí)例是一個(gè)Repository。
(2)IRepository<TEntity, TPrimaryKey>包含一個(gè)真正的Repository所擁有的CRUD方法,第一個(gè)泛型表示將要操作的實(shí)體類(lèi)型(必須繼承自IEntity<TPrimaryKey>接口),第二個(gè)泛型表示TEntity中主鍵的類(lèi)型。主要分為五大塊,分別是1.Select/Get/Query(用以搜索返回記錄)2.Insert 3.Update 4.Delete 5.Aggregate(計(jì)算所有記錄數(shù)),所有的方法都有同步及異步。
(3)AbpRepositoryBase<TEntity, TPrimaryKey>,關(guān)于上述接口,框架提供了一個(gè)默認(rèn)實(shí)現(xiàn),該實(shí)現(xiàn)是一個(gè)抽象類(lèi),定義了數(shù)個(gè)抽象方法用以在具體所使用的ORM框架來(lái)決定真正邏輯,public abstract IQueryable<TEntity> GetAll();就是這樣一個(gè)需要在后面實(shí)現(xiàn)的抽象類(lèi),所有其他的查找方法都是依賴(lài)此方法來(lái)完成自己的邏輯的,所以如果用EF來(lái)做ORM的話只需新建一個(gè)EFRepository并實(shí)現(xiàn)GetAll()抽象方法就ok了,1.public abstract TEntity Update(TEntity entity);2.public abstract void Delete(TEntity entity);同樣如此。
4.Services
該塊是系統(tǒng)的領(lǐng)域驅(qū)動(dòng)服務(wù),擁有一個(gè)空的IDomainService接口,同時(shí)擁有一個(gè)實(shí)現(xiàn)DomainService,這是一個(gè)抽象類(lèi),并繼承AbpServiceBase,在AbpServiceBase類(lèi)中已經(jīng)存在ISettingManager,IUnitOfWorkManager,IActiveUnitOfWork,ILocalizationManager,ILogger(默認(rèn)是一個(gè)空實(shí)現(xiàn)但是可以通過(guò)屬性注入獲得有意義的Logger,如果容器中有的話),還有一個(gè)本地方的方法string L(string name, CultureInfo culture, params object[] args)。
5.UOW
? 系統(tǒng)中所有事務(wù)邏輯都是保存于此的(系統(tǒng)默認(rèn)是IApplicationService和IRepository方法執(zhí)行時(shí)會(huì)生成事務(wù)環(huán)境并保存在靜態(tài)私有字典字段中,通過(guò)線程槽中得到GUID去唯一匹配)。另外也可以為所以將會(huì)存入依賴(lài)容器的類(lèi)型的方法上應(yīng)用UnitOfWorkAttribute來(lái)保證在事務(wù)中被執(zhí)行,同時(shí)該特性有一個(gè)IsDisabled來(lái)關(guān)閉默認(rèn)事務(wù)。
(1)在系統(tǒng)的啟動(dòng)階段,會(huì)注冊(cè)相關(guān)的類(lèi)型到依賴(lài)容器中,如果是IApplicationService和IRepository或者類(lèi)型或者方法上應(yīng)用了UnitOfWorkAttribute依賴(lài)容器就會(huì)為該類(lèi)添加一個(gè)UnitOfWorkInterceptor,確保方法在事務(wù)環(huán)境中被執(zhí)行,該攔截器的void Intercept(IInvocation invocation)方法執(zhí)行時(shí)會(huì)首先通過(guò)IUnitOfWorkManager的Current屬性獲取保存到線程槽中的IUnitOfWork(實(shí)際上是IUnitOfWork的GUID鍵值),如果不為空說(shuō)明其已經(jīng)在一個(gè)事務(wù)上下文中了,下面直接執(zhí)行真正的邏輯就行了,如果為空的話會(huì)嘗試獲取應(yīng)用在方法上的UnitOfWorkAttribute特性,如果沒(méi)有的話會(huì)new一個(gè)新的(默認(rèn)單元工作類(lèi)上沒(méi)有),利用此特性創(chuàng)建UnitOfWorkOptions,利用得到的options作為參數(shù)調(diào)用IUnitOfWorkManager的Begin方法,Begin方法會(huì)返回一個(gè)完成句柄,該句柄同時(shí)也是Disposable的,如果真正的邏輯執(zhí)行ok,在最后會(huì)調(diào)用完成句柄的Complete()完成保存,同時(shí)該句柄也會(huì)被Dispose掉,通過(guò)Begin方法保存到線程數(shù)據(jù)槽中的IUnitOfWork也會(huì)被釋放掉。(真正的執(zhí)行邏輯是可以分異步同步的,都是支持的)
(2)UnitOfWorkBase具有一些事件像Completed,Failed,Disposed都會(huì)在事務(wù)的相應(yīng)階段被處罰,需要額外處理一些東西的話可以監(jiān)控這些事件,關(guān)于動(dòng)態(tài)過(guò)濾的所有參數(shù)也UnitOfWorkBase中設(shè)置添加,在UnitOfWorkBase的繼承類(lèi)中會(huì)使用到控制在數(shù)據(jù)庫(kù)的記錄集的篩選。SaveChanges方法執(zhí)行真正的保存邏輯也需要根據(jù)不同的ORM而有所變化的。所以當(dāng)前是抽象方法。
(3)CallContextCurrentUnitOfWorkProvider,在每次生成新的IUnitOfWork的時(shí)候我們需要存放這些對(duì)象以方便在函數(shù)調(diào)用堆棧中的方法的獲得,所以提供了這樣一個(gè)類(lèi),實(shí)際上IUnitOfWorkManager的Current屬性就是調(diào)用該類(lèi)的同名屬性來(lái)獲取的,當(dāng)創(chuàng)建新的IUnitOfWork的時(shí)候,也通過(guò)此類(lèi)的Current屬性來(lái)保存。當(dāng)獲取當(dāng)前環(huán)境的IUnitOfWork的時(shí)候會(huì)先從線程數(shù)據(jù)槽中得到當(dāng)前執(zhí)行線程的單元工作的GUID,CallContext.LogicalGetData(ContextKey),如果不存在就返回null,如果存在就從該類(lèi)的ConcurrentDictionary<string, IUnitOfWork> UnitOfWorkDictionary私有靜態(tài)只讀屬性中獲取相應(yīng)的IUnitOfWork,如果不存在就返回null,同時(shí)清空數(shù)據(jù)槽中的GUID,如果存在就獲取IUnitOfWork再猜判斷是否已經(jīng)Dispose掉了,沒(méi)有被Dispose就返回該IUnitOfWork,否則清理數(shù)據(jù)返回null。而設(shè)置保存一個(gè)新建的IUnitOfWork則是跟獲取的方法執(zhí)行流程相反。
轉(zhuǎn)載于:https://www.cnblogs.com/Azula/p/4991838.html
與50位技術(shù)專(zhuān)家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的ABP框架详解(三)Domain的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Bezier(贝塞尔曲线)
- 下一篇: 非常不错的MySQL优化的8条经验