ABP框架系列之一:(Entity-實體)


Entities are one of the core concepts of DDD (Domain Driven Design). Eric Evans describe it as "An object that is not fundamentally defined by its attributes, but rather by a thread of continuity and identity". So, entities have Id's and stored in a database. An entity is generally mapped to a table for relational databases.

實體是DDD(領域驅動設計)的核心概念之一。Eric Evans把它描述為“一個沒有被它的屬性基本定義的對象,而是一個連續性和同一性的線程”。因此,實體擁有id並存儲在數據庫中。實體通常映射到關系數據庫的表。

Entity Class(實體類

In ASP.NET Boilerplate, 實體是從實體類派生的. See the sample below:

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

    public virtual DateTime CreationTime { get; set; }

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

Person class is defined as an entity. It has two properties. Also, Entity class defines an Id property. It's primary key of the Entity. So, name of primary keys of all Entities are same, it's Id.

Type of Id (primary key) can be changed. It's int (Int32) by default. If you want to define another type as Id, you should explicitly declare it as shown below:

人員類定義為一個實體。它有兩個屬性。此外,實體類定義id屬性。它是實體的主鍵。因此,所有實體的主鍵名稱相同,它是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;
    }
}

Also, you can set it as string, Guid or something else.

Entity class overrides equality operator (==) to easily check if two entities are equal (their Id is equal). It also defines the IsTransient() method to check if it has an Id or not.

另外,可以將其設置為字符串、GUID或其他內容。

實體類重寫相等運算符(=)以輕松檢查兩個實體是否相等(它們的ID是相等的)。它還定義了istransient()方法檢查它是否有一個ID或不。

AggregateRoot Class(聚合根類

"Aggregate is a pattern in Domain-Driven Design. A DDD aggregate is a cluster of domain objects that can be treated as a single unit. An example may be an order and its line-items, these will be separate objects, but it's useful to treat the order (together with its line items) as a single aggregate." (Martin Fowler - see full description)

“聚合是領域驅動設計中的一種模式。DDD聚合是一組域對象,可以作為單個單元處理。一個例子可能是一個訂單和它的行項目,它們將是單獨的對象,但是將訂單(連同它的行項目)作為單個集合處理是有用的。”(Martin Fowler -參見完整描述)

While ABP does not enforce you to use aggregates, you may want to create aggregates and aggregate roots in your application. ABP defines AggregateRoot class that extends Entity to create aggregate root entities for an aggregate.

雖然ABP不強制您使用聚合,但您可能希望在應用程序中創建聚合和聚合根。 ABP定義聚合根類,為了類擴展的實體創建一個聚集根實體。

(1)Domain Events(領域事件

AggregateRoot defines DomainEvents collection to generate domain events by the aggregate root class. These events are automatically triggered just before the current unit of work is completed. Actually, any entity can generate domain events by implementing IGeneratesDomainEvents interface, but it's common (best practice) to generate domain events in aggregate roots. That's why it's default for AggregateRoot but not for Entity class.

聚合根定義領域事件集合,通過聚合根類自動生成領域事件。這些事件是在當前工作單元完成之前自動觸發的。事實上,任何實體可以通過繼承 Igeneratesdomainevents接口自動生成領域的事件,但它是常見的(最佳實踐),用聚合根自動生成領域事件。這就是為什么它的默認聚合根而不是實體類。

Conventional Interfaces(接口約定

In many application, similar entity properties (and database table fields) are used like CreationTime indicates that when this entity is created. ASP.NET Boilerplate provides some useful interfaces to make this common properties explicit and expressive. Also, this provides a way of coding common code for Entities which implement these interfaces.

在許多應用中,類似的實體屬性(和數據庫表的字段)是用於 CreationTime表明這個實體的創建。ASP.NET的模板提供了一些有用的接口,使這個共同的屬性的明確和有表達力。此外,這為實現這些接口的實體提供了一種編碼公共代碼的方法。

(1)Auditing(審計

IHasCreationTime makes it possible to use a common property for 'creation time' information of an entity. ASP.NET Boilerplate automatically sets CreationTime to current time when an Entity is inserted into database which implements this interface.

ihascreationtime使得它可以使用一個共同的屬性的一個實體的創建時間信息。ASP.NET樣板自動設置的創建時間為當前時間當實體插入到數據庫中,只要實現這個接口

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

Person class can be re-written as shown below by implementing IHasCreationTime interface:

人員類能被重寫如下通過實現 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 extens IHasCreationTime by adding  CreatorUserId:

ICreationAudited擴展IHasCreationTime,增加 CreatorUserId屬性

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

ASP.NET Boilerplate automatically sets CreatorUserId to current user's id when saving a new entity. You can also implement ICreationAudited easily by deriving your entity from CreationAuditedEntity class. It has also a generic version for different type of Id properties.

ASP.NET 樣板自動設置CreatorUserId作為當前用戶的ID,當存儲一個新的實體時。你也可以很容易的實現icreationaudited,通過CreationAuditedEntity獲得你的實體類。它還有一個通用版本,用於不同類型的id屬性。

There is also similar interfaces for modifications:

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

public interface IModificationAudited : IHasModificationTime
{
    long? LastModifierUserId { get; set; }
}

ASP.NET Boilerplate also automatically sets these properties when updating an entity. You just define them for your entity.

If you want to implement all of audit properties, you can direcly implement IAudited interface:

ASP.NET樣板也自動設置這些屬性,當一個實體時更新。你只需為你的實體定義它們。

如果你想實現所有審計的屬性,你可以直接實現iaudited接口:

public interface IAudited : ICreationAudited, IModificationAudited
{

}

As a shortcut, you can derive from AuditedEntity class instead of direcly implementing IAudited. AuditedEntity class has also a generic version for different type of Id properties.

Note: ASP.NET Boilerplate gets current user's Id from ABP Session.

作為一種快捷方式,你可以從auditedentity類而不是直接實現iaudited。auditedentity類也有不同類型的ID屬性的通用版本。

注:ASP.NET樣板從會話獲取當前用戶的ID ABP。

(2)Soft Delete(軟刪除

Soft delete is a commonly used pattern to mark an Entity as deleted instead of actually deleting it from database. For instace, you may not want to hard delete a User from database since it has many releations to other tables.ISoftDelete interface is used for this purpose:

軟刪除是一種常用模式,用於將實體標記為已刪除,而不是實際從數據庫中刪除它。如,你可能不想從數據庫中刪除用戶因為它有許多關系到其他tables.isoftdelete接口用於此目的的:

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

ASP.NET Boilerplate implements soft delete pattern out-of-the-box. When a soft-delete entity is being deleted, ASP.NET Boilerplate detects this, prevents deleting, sets IsDeleted as true and updates entity in the database. Also, it does not retrive (select) soft deleted entities from database, automatically filters them.

ASP.NET樣板實現軟刪除模式開箱。當軟刪除實體被刪除,ASP.NET樣板檢測,防止刪除、設置isDeleted作為真正的更新數據庫實體。而且,它沒有獲得(選擇)軟刪除實體數據庫,自動過濾。

If you use soft delete, you may also want to store information when an entity is deleted and who deleted it. You can implement IDeletionAudited interface that is shown below:

如果你使用軟刪除,則可能希望在刪除實體和誰刪除它時記錄信息。你可以實現ideletionaudited接口,如下圖所示:

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

    DateTime? DeletionTime { get; set; }
}
			

IDeletionAudited extends ISoftDelete as you noticed. ASP.NET Boilerplate automatically sets these properties when an entity is deleted.

If you want to implement all audit interfaces (creation, modification and deletion) for an entity, you can directly implement IFullAudited since it inherits all:

當你注意到 ideletionaudited擴展isoftdelete 。ASP.NET樣板自動設置這些屬性,當一個實體被刪除。

如果你想實現所有審計接口(創建,修改和刪除)一個實體,可以直接實現ifullaudited因為它繼承了所有:

public interface IFullAudited : IAudited, IDeletionAudited
{

}

As a shortcut, you can derive your entity from FullAuditedEntity class that implements all.

  • NOTE 1: All audit interfaces and classes have a generic version for defining navigation property to your User entity (like ICreationAudited<TUser> and FullAuditedEntity<TPrimaryKey, TUser>).
  • NOTE 2: Also, all of them has an AggregateRoot version, like AuditedAggregateRoot.

  • 作為一種快捷方式,你可以從fullauditedentity得到你的實體類,實現了所有。

    注1:所有審計接口和類都定義導航屬性用戶實體的通用版本(如 ICreationAudited<TUser> and FullAuditedEntity<TPrimaryKey, TUser>)。
    注2:同時,他們都有一個aggregateroot版,如AuditedAggregateRoot。

(3)Active/Passive Entities(激活/閑置實體

Some entities need to be marked as Active or Passive. Then you may take action upon active/passive state of the entity. You can implement IPassivable interface that is created for this reason. It defines IsActive property.

If your entity will be active on first creation, you can set IsActive to true in the constructor.

This is different than soft delete (IsDeleted). If an entity is soft deleted, it can not be retrieved from database (ABP prevents it as default). But, for active/passive entities, it's completely up to you to control getting entities.

一些實體需要標記為激活或閑置。然后你可以對實體的激活或閑置狀態采取行動。你可以實現ipassivable接口就是這個原因了。它定義了IsActive屬性。

如果你的實體將第一次創作是激活的,你可以設置 IsActive = true在構造函數。

這是不同於軟刪除(isDeleted)。如果一個實體被軟刪除,它不能從數據庫中檢索(ABP防止它作為默認)。但是,對於激活/閑置實體,完全由您來控制獲取實體。

Entity Change Events(實體改變事件

ASP.NET Boilerplate automatically triggers certain events when an entity is inserted, updated or deleted. Thus, you can register to these events and perform any logic you need. See Predefined Events section in event bus documentation for more information.

ASP.NET樣板自動觸發某些事件時,一個實體的插入、更新或刪除。因此,您可以注冊這些事件並執行您需要的任何邏輯。有關詳細信息,請參閱事件總線文檔中的預定義事件部分。

IEntity Interfaces(IEntity 接口

Actually, Entity class implements IEntity interface (and Entity<TPrimaryKey> implements IEntity<TPrimaryKey>). If you do not want to derive from Entity class, you can implement these interfaces directly. There are also corresponding interfaces for other entity classes. But this is not the suggested way, unless you have a good reason to do not derive from Entity classes.

實際上,實體類實現的接口(and Entity<TPrimaryKey> implements IEntity<TPrimaryKey>)。如果不希望從實體類派生,則可以直接實現這些接口。其他實體類也有相應的接口。但這不是建議的方法,除非您有很好的理由不從實體類派生出來。

IExtendableObject Interface(IExtendableObject接口

ASP.NET Boilerplate provides a simple interface, IExtendableObject, to easily associate arbitrary name-value data to an entity. Consider this simple entity:

ASP.NET的模板提供了一個簡單的接口,iextendableobject,很容易聯想到一個實體任意name-value數據。考慮這個簡單的實體:

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

    public string ExtensionData { get; set; }

    public Person(string name)
    {
        Name = name;
    }
}

IExtendableObject just defines ExtensionData string property which is used to store JSON formatted name value objects. Example:

IExtendableObject 定義ExtensionData  string 屬性用來存儲json格式的name-value objects,如:

var person = new Person("John");

person.SetData("RandomValue", RandomHelper.GetRandom(1, 1000));
person.SetData("CustomData", new MyCustomObject { Value1 = 42, Value2 = "forty-two" });

We can use any type of object as value to SetData method. When we use such the code above, ExtensionData will be like that:

我們可以使用任何類型的對象作為值SetData方法。當我們使用上面的代碼,extensiondata如下:

{"CustomData":{"Value1":42,"Value2":"forty-two"},"RandomValue":178}

Then we can use GetData to get any value:

用GetData取得任意的值

var randomValue = person.GetData<int>("RandomValue");
var customData = person.GetData<MyCustomObject>("CustomData");

While this technique can be very useful in some cases (when you need to provide ability to dynamically add extra data to an entity), you normally should use regular properties. Such a dynamic usage is not type safe and explicit.

雖然這種技術在某些情況下非常有用(當您需要提供向實體動態添加額外數據的能力時),但您通常應該使用常規屬性。這種動態用法不是類型安全的和顯式的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM