ABP(现代ASP.NET样板开发框架)系列之十、ABP领域层——实体

点这里进入ABP系列文章总目录html

 

基于DDD的现代ASP.NET开发框架--ABP系列之十、ABP领域层——实体
git

 

ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称。github

ABP的官方网站http://www.aspnetboilerplate.com数据库

ABP在Github上的开源项目https://github.com/aspnetboilerplate架构

 


本文由深圳-Carl提供翻译框架

实体是DDD(领域驱动设计)的核心概念之一。Eric Evans是这样描述的“不少对象不是经过它们的属性定义的,而是经过一连串的连续性事件和标识定义的”(引用领域驱动设计一书)。函数

译者注:对象不是经过它们的属性来下根本性的定义,而应该是经过它的线性连续性和标识性定义的。。因此,实体是具备惟一标识的ID且存储在数据库中。实体一般被映射成数据库中的一个表。网站

实体类(Entity classes) 

在ABP中,实体继承自Entity类,请看下面示例:ui

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

    public virtual DateTime CreationTime { get; set; }

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

Person 类被定义为一个实体。它具备两个属性,它的父类中有Id属性。Id是该实体的主键。因此,Id是全部继承自Entity类的实体的主键(全部实体的主键都是Id字段)。编码

Id(主键)数据类型能够被更改。默认是int(int32)类型。若是你想给Id定义其它类型,你应该像下面示例同样来声明Id的类型。

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

    public virtual DateTime CreationTime { get; set; }

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

你能够设置为string,Guid或者其它数据类型。

实体类重写了 equality (==) 操做符用来判断两个实体对象是否相等(两个实体的Id是否相等)。还定义了一个IsTransient()方法来检测实体是否有Id属性。

接口约定

在不少应用程序中,不少实体具备像CreationTime的属性(数据库表也有该字段)用来指示该实体是何时被建立的。APB提供了一些有用的接口来实现这些相似的功能。也就是说,为这些实现了这些接口的实体,提供了一个通用的编码方式(通俗的说只要实现指定的接口就能实现指定的功能)。

(1)审计(Auditing)

实体类实现 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 Task()
    {
        CreationTime = DateTime.Now;
    }
}

ICreationAudited 扩展自 IHasCreationTime 而且该接口具备属性 CreatorUserId :

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

当保存一个新的实体时,ABP会自动设置CreatorUserId 的属性值为当前用户的Id

你能够轻松的实现ICreationAudited接口,经过派生自实体类 CreationAuditedEntity (由于该类已经实现了ICreationAudited接口,咱们能够直接继承CreationAuditedEntity 类就实现了上述功能)。它有一个实现不一样ID数据类型的泛型版本(默认是int),能够为ID(Entity类中的ID)赋予不一样的数据类型。
下面是一个为实现相似修改功能的接口

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

当更新一个实体时,APB会自动设置这些属性的值。你只须要在你的实体类里面实现这些属性。

若是你想实现全部的审计属性,你能够直接扩展 IAudited 接口;示例以下:

public interface IAudited : ICreationAudited, IModificationAudited
{
        
}

做为一个快速开发方式,你能够直接派生自AuditedEntity 类,不须要再去实现IAudited接口(AuditedEntity 类已经实现了该功能,直接继承该类就能够实现上述功能),AuditedEntity 类有一个实现不一样ID数据类型的泛型版本(默认是int),能够为ID(Entity类中的ID)赋予不一样的数据类型。

(2)软删除(Soft delete)

软删除是一个通用的模式被用来标记一个已经被删除的实体,而不是实际从数据库中删除记录。例如:你可能不想从数据库中硬删除一条用户记录,由于它被许多其它的表所关联。为了实现软删除的目的咱们能够实现该接口 ISoftDelete:

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

ABP实现了开箱即用的软删除模式。当一个实现了软删除的实体正在被被删除,ABP会察觉到这个动做,而且阻止其删除,设置IsDeleted 属性值为true而且更新数据库中的实体。也就是说,被软删除的记录不能够从数据库中检索出,ABP会为咱们自动过滤软删除的记录。(例如:Select查询,这里指经过ABP查询,不是经过数据库中的查询分析器查询。)

若是你用了软删除,你有可能也想实现这个功能,就是记录谁删除了这个实体。要实现该功能你能够实现IDeletionAudited 接口,请看下面示例:

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

正如你所看到的IDeletionAudited 扩展自 ISoftDelete接口。当一个实体被删除的时候ABP会自动的为这些属性设置值。
若是你想为实体类扩展全部的审计接口(例如:建立(creation),修改(modification)和删除(deletion)),你能够直接实现IFullAudited接口,由于该接口已经继承了这些接口,请看下面示例:

public interface IFullAudited : IAudited, IDeletionAudited
{
        
}

做为一个快捷方式,你能够直接从FullAuditedEntity 类派生你的实体类,由于该类已经实现了IFullAudited接口。

注意:全部的审计接口和类都有一个泛型模板为了导航定义属性到你的User 实体(例如:ICreationAudited<TUser>和FullAuditedEntity<TPrimaryKey, TUser>),这里的TUser指的进行建立,修改和删除的用户的实体类的类型,详细请看源代码(Abp.Domain.Entities.Auditing空间下的FullAuditedEntity<TPrimaryKey, TUser>类),TprimaryKey 只的是Entity基类Id类型,默认是int。

(3)激活状态/闲置状态(Active/Passive)

有些实体须要被标记为激活状态或者闲置状态。那么你能够为实体采起active/passive状态的行动。基于这个缘由而建立的实体,你能够扩展IPassivable 接口来实现该功能。该接口定义了IsActive 的属性。

若是你首次建立的实体被标记为激活状态,你能够在构造函数设置IsActive属性值为true。

这是不一样于软删除(IsDeleted)。若是实体被软删除,它不能从数据库中被检索到(ABP已通过滤了软删除记录)。可是对于激活状态/闲置状态的实体,你彻底取决于你怎样去获取这些被标记了的实体。

IEntity接口

事实上Entity 实现了IEntity 接口(和Entity<TPrimaryKey> 实现了 IEntity<TPrimaryKey>接口)。若是你不想从Entity 类派生,你能直接的实现这些接口。其余实体类也能够实现相应的接口。可是不建议你用这种方式。除非你有一个很好的理由不从Entity 类派生。

 


 

但愿更多国内的架构师能关注到ABP这个项目,也许这其中有能帮助到您的地方,也许有您的参与,这个项目能够发展得更好。

欢迎加ABP架构设计交流QQ群:134710707

ABP架构设计交流群

 

点这里进入ABP系列文章总目录

相关文章
相关标签/搜索