原文地址:https://aspnetboilerplate.com/Pages/Documents/Entities#DocAuditing

实体是DDD(领域驱动模型)的核心概念之一,Eric Evans 把它描述成“一个对象本质上不是通过其属性定义的,而是通过一系列连续性和标识来定义“。所以,实体都有一个Id,并保存在数据库里。一个实体类通常映射成关系型数据库的一个表。

Entity 类

在ABP里,实体类都派生自Entity类,如下面示例代码

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

Person类定义成为一个实体类,它有两个属性,同时,Entity类定义了一个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或者其它类型。

Entity类重写了equality操作符(==),使得检查两个实体是否相等(它们的Id是否相等)变得很容易;它也定义了一个**IsTransient()方法去检查是否有Id.

AggregateRoot类

“聚合是领域驱动模型里的一种模式,DDD聚合是聚合领域对象,可以把它当成一个单元,在例子中聚合根可能是一个订单和订单里的子项,这些是单独的对象,但是把订单(连同他的子项)当成一个单一的聚合来对待是很有帮助的。“(Martin Fowler 全文

虽然ABP不强制你使用聚合,你也可能想在你的应用程序里创建聚合和聚合根,ABP里定义了一个继承了Entity的AggregateRoot为聚合来创建聚合根实体。

领域事件

AggregateRoot定义了DomainEvents集合来生成领域事件,在当前工作单元完成前,这些事件会自动触发。事实上,任意一个实体都可以通过实现IGeneratesDomainEvents接口来生成领域事件,但是通常(最近实践)是在聚合根里来生成领域事件,这就是为什么把它默认定义在AggregateRoot里,而不是Entity类里。

常规接口

在许多应用程序里,实体类里都会用到一些相同的属性(和数据库表字段),例如CreateTime,用来表示实体被创建的时间。ABP里提供了一些有用的接口,使得这些通用属性更明显及更富表达性,这也为实现了这些接口的实体类提供了一种公共代码的方式。

审计

IHasCreationTime使得实体类的“创建时间”信息使用一个公共属性成为可能,当一个实现了这个接口的类对象插入到数据库里时,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会自动把CreatorUserId设置成当前用户的Id,针对不同类型的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 Session取得当前用户。

软删除

软删除时一种通用的做法来标识实体被删除了,而不是真的从数据库里删除它。例如,你可能不想直接从数据库里删除一个用户的数据,因为它关联了其它一些表。ISoftDelete接口就是为这个目的而建的:

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

ABP实现了软删除模式,当一个实体被软删除时,ABP就会侦测到,阻止它直接删除,而把它的IsDeleted设置为true,并更新到数据库里,在查询时,ABP会自动过滤掉被软删除的数据。

如果你使用了软删除,你可能想保存这条数据是什么时候删除的,被谁删除的,那这样的话,你可以实现IDeletionAudited接口,如下所示:

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

如你所见,IDeletionAudited继承了ISoftDelete,当实体被删除时,ABP会自动设置这些属性。

如果你想对一个实体实现所有审计接口(创建、修改和删除),你可以直接实现IFullAudited接口,因为它继承那些接口:

public interface IFullAudited : IAudited, IDeletionAudited
{}

作为一种快捷方式,你可以让你的类派生自实现了上面那些接口的FullAuditedEntity类。

  • 注意1:所有的审计接口和类都有一个对应的泛型版本,用于定义你的User实体的导航属性(如ICreationAudited 和 FullAuditedEntity<TPrimaryKey, TUser>)。
  • 它们也有一个AggregateRoot,如AuditedAggregateRoot。

激活/失效状态实体

有些实体需要标识为激活或失效,然后你可能对实体的激活/失效状态做一些操作,你可以实现IPassivable接口,它就是为了这个目的而建的,它定义了IsActive属性。

如果你的实体在第一次创建时就要被激活,你可以在构造函数里把IsActive设置为true。

这跟软删除(IsDeleted)有些不一样,如果一个实体被软删除了,它是无法从数据库里抓取出来的(ABP默认阻止获取软删除数据),但是,对于激活/失效状态的实体,从数据库获取数据时,就完全有你来决定了。

实体变更事件

当一个实体被插入、修改或删除时,ABP会自动触发一些特定的事件。因此,你可以注册这些事件去执行任何你需要的逻辑。想了解更多可以查看event bus documentation里的Predefined Events。

IEntity接口

实际上,Entity类实现了IEntity接口(和Entity实现了IEntity),如果你不想派生自Entity类,你可以直接实现这些接口,对于其它实体类也有相应的接口,但是不建议你这样做,除非你有一个好的理由不去派生自Entity类。

IExtendableObject接口

ABP提供了一个简单的接口,IExtendableObject,它可以轻易的把任意键值对数据与实体相关联起来,看看这个简单的实体:

public class Person : Entity, IExtendableObject
{public string Name { get; set; }public string ExtensionData { get; set; }public Person(string name){Name = name;}
}

IExtendableObject只是定义了一个ExtensionData字符串属性,它被用来存放JSON格式的键值对对象。例如:

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

我们可以用SetData方法设置任意类型的对象为值,当我们用到上面的代码时,ExtensionData的值是这样的:
{"CustomData":{"Value1":42,"Value2":"forty-two"},"RandomValue":178}

然后我们可以使用GetData取得任意值:

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

在有些情况下,这是很有用的(当你需要提供向实体类上动态添加额外数据的能力时),正常情况下你应该使用常规属性,动态类型的用法类型既不明确,也不是安全。

转载于:https://www.cnblogs.com/Lau7/p/8011492.html

(译)ABP之Entities相关推荐

  1. [译]ABP vNext介绍

    译者注 ASP.NET Boilerplate是.Net平台非常优秀的一个开源Web应用程序框架,在国内也有大量的粉丝. 近日, 本人在github上闲逛, 发现ASP.NET Boilerplate ...

  2. 基于 abp vNext 和 .NET Core 开发博客项目 - 数据访问和代码优先

    基于 abp vNext 和 .NET Core 开发博客项目 - 数据访问和代码优先 转载于:https://github.com/Meowv/Blog 本篇主要使用Entity Framework ...

  3. ABP vNext微服务架构详细教程——分布式权限框架(上)

    1 简介 ABP vNext框架本身提供了一套权限框架,其功能非常丰富,具体可参考官方文档:https://docs.abp.io/en/abp/latest/Authorization 但是我们使用 ...

  4. ABP vNext微服务架构详细教程——基础服务层

    1 服务创建 在除身份管理相关服务以外的其他业务服务中,我们不需要包含用户角色权限管理功能模块,ABP vNext框架为我们提供了模块模式,其默认模板不包含身份管理相关模块,更适合用于搭建普通的业务微 ...

  5. Abp太重了?轻量化Abp框架

    本文首发于个人博客(https://blog.zhangchi.fun/) 在进行框架的选型时,经常会听到"***框架太重了"之类的声音,比如"Abp太重了,不适合我们. ...

  6. 基于ABP落地领域驱动设计-02.聚合和聚合根的最佳实践和原则

    前言 上一篇 基于ABP落地领域驱动设计-01.全景图 概述了DDD理论和对应的解决方案.项目组成.项目引用关系,以及基于ABP落地DDD的通用原则.从这本篇开始,会更加深入地介绍在基于 ABP Fr ...

  7. Abp 0.18.0 正式发布! -ABP CLI,新模板和其他功能

    ABP CLI, v0.18版本新模板和其他功能 ABP v0.18已发布, 包含解决的80+个issue, 550+次提交. 网站更改 abp.io网站完全更新以突出ABP框架的目标和重要功能.文档 ...

  8. Abp vNext 切换MySql数据库

    Abp vNext是Abp的下一代版本,目前还在经一步完善,代码已经全部重写了,好的东西保留了下来,去除了很多笨重的东西,从官宣来看,Abp vNext主要是为了以后微服务架构而诞生的. 从源码来看, ...

  9. Abp vnext Web应用程序开发教程 10 —— 书与作者的关系

    文章目录 关于本教程 下载源代码 介绍 向书实体添加关系 数据库和数据迁移 更新EF核心映射 添加新的EF核心迁移 更改数据播种器 应用层 数据传输对象 IBookAppService BookApp ...

最新文章

  1. 基于OpenCV实战:对象跟踪
  2. java编程题有难度的_算法与编程面试题 不喜勿喷 难度指数:*****...
  3. Web API应用架构设计分析(2)
  4. 人工智能之华为云ModelArts的深度使用体验与AI Gallery应用开发实践
  5. 一个SAP成都研究院开发工程师 2020 年的所有文章列表
  6. SAP官方发布的ABAP编程规范
  7. 视不可当:信息图与可视化传播
  8. mysql怎么合并行_mysql怎么合并行
  9. 作者:李茹姣(1976-),女,博士,中国科学院北京基因组研究所生命与健康大数据中心高级工程师...
  10. 从Eclipse切换到IDEA后需要做的事情
  11. JZOJ.5274【NOIP2017模拟8.14】数组
  12. mysql高性能sql引擎剖析_Oracle+高性能SQL引擎剖析:SQL优化与调优机制详解-笔记之执行计划(一)...
  13. 分享一个自己写的QT小游戏-玛丽奥医生
  14. 谷歌小恐龙PHP代码,Chrome小恐龙前端修改代码代码总结
  15. 苹果服务器系统状态查询网址
  16. 32句期权交易的浓缩精华
  17. 为什么编程是独一无二的职业
  18. 【学术前沿分析】1 论文数据统计
  19. 集合框架中的共性功能
  20. c++之gbk和utf8编码转换

热门文章

  1. Android USB 输入设备
  2. 基于STM32F407标准库串口DMA+空闲中断
  3. 数字IC后端流程——(三)布局Placement
  4. ctf赛题上传一个php木马,从一道CTF题学习PHP反序列化漏洞
  5. 第六感38只19.9/吹风机29.9/长虹电暖器69/按摩护腰垫39/情侣卫衣54.9
  6. python最少钞票_钞票最少张数
  7. Windows11/10 使用RDP远程桌面时提示 您的凭据不工作/登录没有成功可能的一种原因
  8. 勿忘2022,迎接2023
  9. 创业书籍推荐,这本书最经典!
  10. 将光标从下划线变成竖线的方法