ABP框架 - 实体
本节内容:
实体是DDD一个核心的概念。Eric Evans是这么描述的:“一个对象根本上不是按它的特性定义的,而是按一个线程的连续性和身份来定义”。所以实体有一个id属性存入数据库中。一个实体通常映射成关系型数据库的一个表。
实体类
在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。
聚合根类
“聚合在DDD里是一个模式,一个DDD聚合是一个领域对象群,可由单独的单元创建。例如一个订单和它的项,这些可以是分离的对象,但把订单(和它的项一起)看成是一个单独的聚合是有好处的。“(Martin Fowler 查看完整描述)。
虽然ABP没有强迫你使用聚合,但你也可能想在你的应用里,创建聚合和聚合根。ABP扩展了Entity,定义了AggregateRoot类,为一个聚合创建聚合根实体。
领域事件
AggregateRoot定义了DomainEvents集合,通过聚合根对象产生领域事件。这些事件在当前工作单元完成前自动触发,实质上,任何实体都可以通过实现IGeneratesDomainEvents接口产生领域事件,但通常(最佳实践)在聚合根里产生领域事件,这就是为什么把它默认到AggregateRoot里,而不是Entity类里。
约定的接口
在很多应用里,有很多相似的实体属性(数据库表的字段),如表示实体何时创建的CreationTime,ABP提供了一些有用的接口,明确和展现这些通用属性,这也给实现这些接口的实体,在编写这些属性代码时提供了一种通用的方式。
审计
IHasCreationTime为一个实体的“创建时间”信息采用通用的属性,在一个实体插入到数据库前,ABP自动为实现了该接口的实体,设置CreationTime属性为当前时间。
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。你也可以让你的类继承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。AuditiedEntity类同样也有一个适用于不同类型Id属性的泛型版本。
注意:ABP从ABP会话里获取用户Id。
软删除
软删除是一个通用的模式,它把一个实体标记为“已删除”代替从数据库直接删除。例如,你不想把一个User从数据库硬删除,因为它可能与其它表有关联,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; }
}
更快捷的方式是:你可以从已经实现了所有的FullAuditedEntity类继承你的实体。
- 注意1:所有审计接口和类都有一个为指向你的User实体的导航属性而设计的泛型版本(如ICreationAudited<TUser>和FullAuditedEntity<TPrimaryKey,TUser>)。
- 注意2:同时,它们都有一个AggregateRoot版本,如AuditedAggregateRoot。
活跃/消极 实体
有些实体需要标记为Active(活跃的)和Passive(消极的),然后你根据实体的活跃/消极状态进行不同的操作,IPassivable就是为此而设计的,它定义了IsActive属性。
如果你的实体想在创建时就是处于活跃状态,你可以在构造器里设置IsActive为true。
它与软删除(IsDeleted)不同,如果一个实体被软删除,Abp默认不从数据库里取出,但是是否获取活跃/消极实体完全取决于你。
实体变化事件
当一个实体插入、更新、删除时,ABP会自动触发某些事件,因此你可以注册这些事件执行你需要的任何逻辑。查看事件总线文档的“预定义事件”主题,获取更多信息。
IEntity 接口
实质上,Entity类实现了IEntity接口(且Entity<TPrimaryKey>实现了IEntity<TPrimaryKey>)。如果你不想从Entity类继承,你可以直接实现这些接口,这些接口对于其它实体类也是适用的,但是这不是推荐的方式,除非你有一个好的理由。
ABP框架 - 实体的更多相关文章
- ABP入门系列(1)——学习Abp框架之实操演练
作为.Net工地搬砖长工一名,一直致力于挖坑(Bug)填坑(Debug),但技术却不见长进.也曾热情于新技术的学习,憧憬过成为技术大拿.从前端到后端,从bootstrap到javascript,从py ...
- 一步一步使用ABP框架搭建正式项目系列教程
研究ABP框架好多天了,第一次看到这个框架的名称到现在已经很久了,但由于当时内功有限,看不太懂,所以就只是大概记住了ABP这个名字.最近几天,看到了园友@阳光铭睿的系列ABP教程,又点燃了我内心要研究 ...
- C#高级知识点&(ABP框架理论学习高级篇)——白金版
前言摘要 很早以前就有要写ABP高级系列教程的计划了,但是迟迟到现在这个高级理论系列才和大家见面.其实这篇博客很早就着手写了,只是楼主一直写写停停.看看下图,就知道这篇博客的生产日期了,谁知它的出厂日 ...
- 一步一步使用ABP框架搭建正式项目系列教程之本地化详解
返回总目录<一步一步使用ABP框架搭建正式项目系列教程> 本篇目录 扯扯本地化 ABP中的本地化 小结 扯扯本地化 本节来说说本地化,也有叫国际化.全球化的,不管怎么个叫法,反正道理都是一 ...
- ABP框架搭建项目系列教程基础版完结篇
返回总目录<一步一步使用ABP框架搭建正式项目系列教程> 经过前面十二篇的基础教程,现在终于该做个总结了. 回顾 第一篇,我们建议新手朋友们先通过ABP官网的启动模板生成解决方案,因为这样 ...
- 详解ABP框架的多租户
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:ABP框架对多租户场景提供了很好的支持,内建了多租户的处理机制,今天我们来深入解析一下 ...
- [译]ABP框架使用AngularJs,ASP.NET MVC,Web API和EntityFramework构建N层架构的SPA应用程序
本文转自:http://www.skcode.cn/archives/281 本文演示ABP框架如何使用AngularJs,ASP.NET MVC,Web API 和EntityFramework构建 ...
- ABP框架详解(三)Domain
此处的Domain主要指Abp类库根目录下Domain文件夹.顾名思义该目录下是用来存放与领域实体,领域逻辑执行,存储,领域服务相关的内容. 1.Entities (1)为整个Abp框架后期开发的所有 ...
- AutoMapper在ABP框架中的使用说明
为了说明AutoMapper如何使用,我专门开设了一个专题来讲,如果您还没有查看该专题,请点击这里.既然系统地学习了AutoMapper,那么接下来就是该用它实战的时候了.今天,我们就来揭开AutoM ...
随机推荐
- 如何在高并发环境下设计出无锁的数据库操作(Java版本)
一个在线2k的游戏,每秒钟并发都吓死人.传统的hibernate直接插库基本上是不可行的.我就一步步推导出一个无锁的数据库操作. 1. 并发中如何无锁. 一个很简单的思路,把并发转化成为单线程.Jav ...
- setAttribute()
●节点分为不同的类型:元素节点.属性节点和文本节点等. ●getElementById()方法将返回一个对象,该对象对应着文档里的一个特定的元素节点. ●getElementsByTagNam ...
- 创建APPID&&部署服务端教程
创建APPID&&部署服务端 一.创建APPID 1.打开https://console.developers.google.com ,左击顶部Project,然后左击创建项目 2.输 ...
- C++随笔:.NET CoreCLR之GC探索(3)
有几天没写GC相关的文章了哈,今天我讲GC的方式是通过一个小的Sample来讲解,这个小的示例代码只有全部Build成功了才会有.地址为D:\coreclr2\coreclr\bin\obj\Wind ...
- javascript动画系列第一篇——模拟拖拽
× 目录 [1]原理介绍 [2]代码实现 [3]代码优化[4]拖拽冲突[5]IE兼容 前面的话 从本文开始,介绍javascript动画系列.javascript本身是具有原生拖放功能的,但是由于兼容 ...
- Function.prototype.toString 的使用技巧
Function.prototype.toString这个原型方法可以帮助你获得函数的源代码, 比如: function hello ( msg ){ console.log("hello& ...
- AlloyTouch实战--60行代码搞定QQ看点资料卡
原文链接:https://github.com/AlloyTeam/AlloyTouch/wiki/kandian 先验货 访问DEMO你也可以点击这里 源代码可以点击这里 如你体验所见,流程的滚动的 ...
- 一个软件开发者的BPM之路
我是小林,一名普通的软件工程师,从事BPM(业务流程管理)软件开发工作.我没有几十年的技术底蕴,无法像大牛们一样高谈阔论,品评BPM开发之道:也不是资深的流程管理专家,能与大家分析流程管理的时弊.我只 ...
- Android Studio-—使用OpenCV的配置方法和demo以及开发过程中遇到的问题解决
前提: 1.安装Android Studio(过程略) 2.官网下载OpenCV for Android 网址:http:opencv.org/downloads.html 我下载的是下图的版本 3. ...
- Atitit.如何建立研发体系
Atitit.如何建立研发体系 组织,流程,prj..Mana oppm 发管理是一个完整的管理体系,从结构上来讲,它主要由四个方面的内容构架而成:组织结构与岗位设置 管理流程与工作流程..项目及管 ...