基於DDD的.NET開發框架 - ABP的Entity設計思想

返回ABP系列html

ABP是「ASP.NET Boilerplate Project (ASP.NET樣板項目)」的簡稱。git

ASP.NET Boilerplate是一個用最佳實踐和流行技術開發現代WEB應用程序的新起點,它旨在成爲一個通用的WEB應用程序框架和項目模板。github

ABP的官方網站:http://www.aspnetboilerplate.com數據庫

ABP官方文檔:http://www.aspnetboilerplate.com/Pages/Documents框架

Github上的開源項目:https://github.com/aspnetboilerplate函數

1、基本概念

實體是DDD(領域驅動設計)的核心概念之一。Eirc Evans是這樣描述的實體的:「它根本上不是經過屬性定義的,而是經過一系列連續性和標識定義的」。所以,實體都有Id屬性而且都存儲到數據庫中。一個實體通常會映射到數據庫的一張表。源碼分析

一、實體類網站

在ABP中,實體派生自Entity類,例如:ui

    public class Person : Entity
    {
        public virtual string Name { get; set; }

        public virtual DateTime CreationTime { get; set; }

        public Person()
        {
            CreationTime = DateTime.Now;
        }
    }

上面定義了一個Person實體類,並且在Entity類中定義了一個Id屬性,它是該Entity類的主鍵。所以,全部實體的主鍵名都是相同的,都是Id。編碼

主鍵Id的類型是能夠改變的,默認是int(int32)的。若是你想將Id定義爲其餘類型,能夠像下面那樣顯示聲明:

    public class Person : Entity<long>
    {
        public virtual string Name { get; set; }

        public virtual DateTime CreationTime { get; set; }

        public Person()
        {
            CreationTime = DateTime.Now;
        }
    }

主鍵Id也能夠設置爲string,Guid或其餘類型的。

Entity類重寫了等號運算符(==),能夠輕鬆地檢查兩個實體是否相同了(實體的Id相同則認爲它們相同)。它也定義了IsTransient方法來檢測它是否有Id。

二、接口約定

在不少應用程序中,不少實體具備像CreationTime的屬性(數據庫表也有該字段)用來指示該實體是何時被建立的。APB提供了一些有用的接口來實現這些相似的功能。也就是說,爲這些實現了這些接口的實體,提供了一個通用的編碼方式(通俗的說只要實現指定的接口就能實現指定的功能)。

1)、審計

實體類實現 IHasCreationTime 接口就能夠具備CreationTime的屬性。當該實體被插入到數據庫時, ABP會自動設置該屬性的值爲當前時間。

public interface IHasCreationTime
{
    DateTime CreationTime { get; set; }
}

Person類能夠經過實現IHasCreationTime接口來重寫,以下:

public class Person : Entity<long>, IHasCreationTime
{
    public virtual string Name { get; set; }

    public virtual DateTime CreationTime { get; set; }

    public Person()
    {
        CreationTime = DateTime.Now;
    }
}

ICreationAudited經過增長了CreatorUserId擴展了IHasCreationTime:

public interface ICreationAudited : IHasCreationTime
{
    long? CreatorUserId { get; set; }
}

當保存一個新的實體時,ABP會自動地將當前的用戶Id設置爲CreatorUserId。

你也能夠經過從CreationAuditedEntity類派生實體,從而輕易地實現ICreationAudited。

對於修改也有類似的接口:

public interface IModificationAudited
{
    DateTime? LastModificationTime { get; set; }

    long? LastModifierUserId { get; set; }
}

做爲一個快捷方式,你能夠從AuditedEntity類派生,而不須要直接實現IAudited。AuditedEntity類對於不一樣類型的Id屬性也有泛型的版本。

2)、軟刪除

軟刪除是一個通用的模式被用來標記一個已經被刪除的實體,而不是實際從數據庫中刪除記錄。例如:你可能不想從數據庫中硬刪除一條用戶記錄,由於它被許多其它的表所關聯。爲了實現軟刪除的目的咱們能夠實現該接口 ISoftDelete:

public interface ISoftDelete{
    bool IsDeleted { get; set; }
}

ABP實現了開箱即用的軟刪除模式。當一個軟刪除實體被刪除後,ABP檢測到以後,會阻止刪除,將IsDeleted設置爲true並更新數據庫中的實體。並且,它會自動地過濾數據庫中軟刪除的實體,不會檢索(select)它們。

若是你用了軟刪除,你有可能也想實現這個功能,就是記錄誰刪除了這個實體。要實現該功能你能夠實現IDeletionAudited 接口,請看下面示例:

public interface IDeletionAudited : ISoftDelete
{
    long? DeleterUserId { get; set; }
    DateTime? DeletionTime { get; set; }
}

IDeletionAudited擴展了ISoftDelete,當刪除一個實體時,ABP會自動設置這些屬性。

若是你想爲一個實體實現全部的審計接口(建立,修改和刪除),那麼能夠直接實現IFullAudited,由於它繼承了全部的這些接口:

public interface IFullAudited : IAudited, IDeletionAudited
{
        
}

做爲一個快捷方式,你能夠直接從FullAuditedEntity 類派生你的實體類,由於該類已經實現了IFullAudited接口。

注意:全部的審計接口和類都有一個定義導航屬性到User實體的泛型版本(好比ICreationAudited和FullAuditedEntity<tprimarykey,tuser>)。

3)、激活/未激活

一些實體須要標記爲激活的或未激活的。這樣,你就能夠根據實體的激活或者未激活狀態來採起行動。你能夠實現IPassivable接口來達到目的。該接口定義了IsActive屬性。

若是實體在第一次建立時是激活的,那麼你能夠在構造函數中將IsActive設置爲true。

這與軟刪除(IsDeleted)是不一樣的。若是一個實體是軟刪除的,那麼它就不會從數據庫中檢索到了(ABP默認會阻止),可是,對於激活或者未激活的實體,控制獲取實體徹底取決於你。

二、IEntity接口

實際上,Entity類實現了IEntity接口(且Entity實現了IEntity)。若是不想從Entity類中派生,那麼能夠直接實現這些接口。可是,除非你有一個好的緣由不從Entity類派生,不然,不建議這麼作。

2、ABP源碼分析

代碼:

部分類圖:

IEntity<TPrimaryKey>: 封裝了PrimaryKey:Id,這是一個泛型類型

IEntity: 封裝了PrimaryKey:Id,這是一個int類型

Entity<TPrimaryKey> :支持主鍵是泛型類型的Entity

Entity:支持主鍵是int類型的Entity

 

IHasCreationTime: 封裝了CreationTime

ICreationAudited: 封裝了CreatorUserId,這個是long類型

CreationAuditedEntity<TPrimaryKey> : 支持主鍵是泛型類型的Entity,而且封裝了CreationTime 和 CreatorUserId

CreationAuditedEntity: 只支持主鍵是int類型的Entity,而且封裝了CreationTime 和 CreatorUserId

ICreationAudited<TUser> :封裝了泛型類型的creator

CreationAuditedEntity<TPrimaryKey, TUser> :  支持主鍵是泛型類型,而且封裝了泛型類型的creator的Entity

 

ISoftDelete:封裝了軟刪除的標誌IsDeleted

IHasDeletionTime:封裝了DeletionTime

IDeletionAudited:封裝了DeleterUserId,這個是long類型

IDeletionAudited: 封裝了泛型類型的DeleterUser

 

IHasModificationTime:封裝了LastModificationTime

IModificationAudited: 封裝了LastModifierUserId,這個是long類型

IModificationAudited<TUser> :  封裝了泛型類型的LastModifierUser

 

IAudited:從其父類接口那繼承了Creation 和 Modification 的時間和UserID,這個是long類型

AuditedEntity<TPrimaryKey> :支持主鍵是泛型類型的Entity,而且從其父類接口那繼承了Creation 和 Modification 的時間和UserID,這個是long類型

AuditedEntity: 與AuditedEntity<TPrimaryKey>的區別就是其只支持主鍵是int類型的Entity。

AuditedEntity<TPrimaryKey, TUser> :與AuditedEntity<TPrimaryKey>的區別就是其支持泛型類型的LastModifierUser和CreatorUser。

 

IAudited:從其父類接口那繼承了Creation,Modification和delete 的時間和UserID,這個是long類型

FullAuditedEntity<TPrimaryKey> :支持主鍵是泛型類型的Entity,而且從其父類接口那繼承了Creation,Modification和delete 的時間和UserID,這個是long類型

FullAuditedEntity:與FullAuditedEntity<TPrimaryKey>的區別就是其只支持主鍵是int類型的Entity

FullAuditedEntity<TPrimaryKey, TUser> :與FullAuditedEntity<TPrimaryKey>的區別就是其支持泛型類型的LastModifierUser,CreatorUser 和 deleteuser。