实体

  实体是DDD(领域驱动设计)的核心概念之一。Eric Evans描述它为"An object that is not fundamentally defined by its attributes, but rather by a thread of continuity and identity."所以,实体有Id并存储在数据库。实体一般映射到关系库中的表。

实体类

  在ABP,实体继承自Entity类。如下示例:

public class Person : Entity
{
public virtual string Name { get; set; } public virtual DateTime CreationTime { get; set; } public Person()
{
CreationTime = DateTime.Now;
}
}

  Persion类定义为实体。它有两个属性,实体类还定义了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;
}
}

  还可以将主键类型设置为String、Guid或其他类型。

  实体类重写了相等运算符(==),可以方便的检查两个实体是否相等(Id相同)。实体还定义了IsTransient()方法检查是否有Id。

聚合根类

  “在DDD中,聚合是一种模式。一个DDD聚合是领域对象群集,这些领域对象可以作为一个单元对待。例如订单和它的行项目,这些是独立的对象,但是把订单(和它的行项目)作为一个聚合对待是有用的。”(Martin Fowler -参见详细描述)。

  虽然ABP不强制使用聚合,在应用中,我们或许想创建聚合和聚合根。ABP定义了AggregateRoot类,它扩展了实体为聚合创建聚合根实体。

领域事件

  聚合根定义了领域事件集合,通过聚合根类产生领域事件。这些事件在当前工作单元完成之前自动触发。实际上,任何实体可以通过实现IGeneratesDomainEvents接口来生成领域事件,但是,通常在(最佳实践)聚合根中生成领域事件。这就是为什么默认为聚合根而不是其他实体类。

常规接口

  在许多应用中,相似的实体属性(和数据库表字段)被使用,如CreationTime表示实体什么事件被创建。ABP提供了一些有用的接口使这些常见属性显示声明。这也提供了编写实体常用代码的一种方式,实现这些接口。

审计

  IHasCreationTime使实体拥有一个常用的"creation time"属性。当实现了这个接口的实体被插入到数据库时,ABP自动设置CreationTime为当前时间。

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

  ABP自动设置CreatorUserId为当前用户Id,当保存一个新实体的时候。也可以通过将实体继承CreationAuditedEntity类来实现ICreationAudited接口。它也有一个泛型版本,可以实现不同类型的Id属性。

  修改也有类似的接口:

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

  当更新实体时,ABP自动设置这些属性。只需要在实体中定义他们。

  如果想实现所有的审计属性,可以直接实现IAudited接口:

public interface IAudited : ICreationAudited, IModificationAudited
{ }

  有一个捷径,可以直接继承AuditedEntity类而不是直接实现IAudited接口。AuditedEntity类也有一个泛型版本,以适应不同类型的Id属性。

  注意:ABP从ABP会话中获取当前用户Id。

软删除

  软删除是常用的模式,用来标记实体删除而不是真的从数据库中删除。例如,可能不想从数据库中硬删除一个用户,因为它和其他表有许多关系。ISoftDelete接口用来实现这个目的:

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

  ABP实现了开箱即用的软删除模式。当软删除实体被删除时,ABP会检测到并阻止删除,设置IsDeleted为true,然后更新实体到数据库。ABP不会从数据库中获取(select)软删除的实体,自动过滤他们。

  如果使用软删除,也想记录实体什么时候被删除、谁删除,可以实现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类,它实现了所有。

  • NOTE1:所有的审计接口和类都有一个泛型版本,用来定义User实体(如ICreationAudited<TUser>和FullAuditedEntity<TPrimaryKey,TUser>)的导航属性。
  • NOTE2:所有这些都有一个聚合根版本,如AuditedAggregateRoot。

激活/失活实体

  一些实体需要被记录为激活或失活。然后可以基于实体的激活/失活状态进行操作。可以实现IPassiveable接口,这个接口便是为这个目的设计的。它定义了IsActive属性。

  如果实体第一次创建时为激活状态,那么可以在构造函数中设置IsActive为true。

  这和软删除(IsDeleted)是不同的。如果实体被软删除,它不能从数据库中获取(ABP默认会阻止获取),但是,对于激活/失活的实体,控制获取实体完全由自己决定。

实体改变事件

  当实体被插入、更新或删除时,ABP自动触发这些确定的事件。然后,我们可以注册这些事件,执行需要的任何逻辑。参见在事件总线文档的预定义事件部分了解更多信息。

IEntity接口

  实际上,Entity类实现了IEntity接口(Entity<TPrimaryKey>实现了IEntity<TPrimaryKey>)。如果不想从Entity类集成,可以直接实现这些接口。其他实体类也有相关的接口。但是,不建议使用这种方式,除非有好的理由不从Entity类继承。

返回主目录

ABP官方文档翻译 3.1 实体的更多相关文章

  1. ABP官方文档翻译 3.3 仓储

     仓储 默认仓储 自定义仓储 自定义仓储接口 自定义仓储实现 基础仓储方法管理数据库连接 查询 获取单个实体 获取实体列表 关于IQueryable 自定义返回值 插入 更新 删除 其他 关于异步方法 ...

  2. ABP官方文档翻译 10.1 ABP Nuget包

    ABP Nuget包 Packages Abp Abp.AspNetCore Abp.Web.Common Abp.Web Abp.Web.Mvc Abp.Web.Api Abp.Web.Api.OD ...

  3. ABP官方文档翻译 9.3 NHibernate集成

    NHibernate集成 Nuget包 配置 实体映射 仓储 默认实现 自定义仓储 应用程序特定基础仓储类 ABP可以使用任何ORM框架,它内置集成NHibernate.此文档将讲解ABP如何使用NH ...

  4. ABP官方文档翻译 9.2 Entity Framework Core

    Entity Framework Core 介绍 DbContext 配置 在Startup类中 在模块PreInitialize方法中 仓储 默认仓储 自定义仓储 应用程序特定基础仓储类 自定义仓储 ...

  5. ABP官方文档翻译 9.1 EntityFramework集成

    EntityFramework集成 Nuget包 DbContext 仓储 默认仓储 自定义仓储 应用特定的基础仓储类 自定义仓储示例 仓储最佳实践 事务管理 数据存储 ABP可以使用ORM框架,它内 ...

  6. ABP官方文档翻译 8.1 通知系统

    通知系统 介绍 发送模型 通知类型 通知数据 通知严重性 关于通知持久化 订阅通知 发布通知 用户通知管理 实时通知 客户端 通知存储 通知定义 介绍 在系统中通知用来基于特定的事件告知用户.ABP提 ...

  7. ABP官方文档翻译 7.1 后台Jobs和Workers

    后台Jobs和Workers 介绍 后台Jobs 关于Job持久化 创建后台Job 在队列中添加一个新Job 默认的后台Job管理器 后台Job存储 配置 禁用Job执行 异常处理 Hangfire集 ...

  8. ABP官方文档翻译 5.3 OData集成

    OData集成 介绍 安装 安装Nuget包 设置模块依赖 配置实体 创建控制器 配置 示例 获取实体列表 Request Response 获取单个实体 Request Response 使用导航属 ...

  9. ABP官方文档翻译 4.2 数据传输对象

    数据传输对象 DTOs的必要性 领域层的抽象 数据隐藏 序列化和懒加载问题 DTO转换和验证 示例 DTOs和实体间的自动映射 辅助接口和类 数据传输对象用来在应用层和展示层之间传输数据. 展示层调用 ...

随机推荐

  1. bzoj 1935: [Shoi2007]Tree 园丁的烦恼

    Description 很久很久以前,在遥远的大陆上有一个美丽的国家.统治着这个美丽国家的国王是一个园艺爱好者,在他的皇家花园里种植着各种奇花异草.有一天国王漫步在花园里,若有所思,他问一个园丁道: ...

  2. JS中const、var 和let的区别

    今天第一次遇到const定义的变量,查阅了相关资料整理了这篇文章.主要内容是:js中三种定义变量的方式const, var, let的区别. 1.const定义的变量不可以修改,而且必须初始化. 1 ...

  3. oracle 数据库——知识点总结(加示例)

    新入oracle数据库,把目前学到的知识点记录下来,可能都比较基础,但还是比较全的,里面的示例都是自己在PL/SQL中跑过的,如果有错误,还望各位大侠指出哈. 创建用户 1.创建用户(使用管理员身份创 ...

  4. ceph -s集群报错too many PGs per OSD

    背景 集群状态报错,如下: # ceph -s cluster 1d64ac80-21be-430e-98a8-b4d8aeb18560 health HEALTH_WARN <-- 报错的地方 ...

  5. 如何开发由Create-React-App 引导的应用(一)

    此文章是翻译How to develop apps bootstrapped with Create React App 官方文档 系列文章 如何开发由Create-React-App 引导的应用 如 ...

  6. 邓_ phpcms_

    {pc:content action="lists" catid="$catid" num="10" order="id DESC ...

  7. VS code注释快捷键

    注释:        先CTRL+K,然后CTRL+C 取消注释: 先CTRL+K,然后CTRL+U

  8. Thrift compiler代码生成类解析

    代码生成类解析: Thrift--facebook RPC框架,介绍就不说了,百度,google一大把,使用也不介绍,直接上结构和分析吧. Hello.thrift文件内容如下: namespace ...

  9. MySql Outer Join 简单化

    查询from语句中的Outer Join可以在多种情况下被简化: 在解析阶段,右外连接操作可以被转变为等下ode值包含left join的操作,在一般情况下,转变: (T1, ...) RIGHT J ...

  10. Number()和new Number()的区别以及一种简单实现

    看MDN Beginners文档的时候注意到了这种用法 var n1 = Number(123); , 冒出的第一个疑问就是和 var n2 = new Number(123); 有什么区别呢? 首先 ...