关于ABP聚合根类AggregateRoot的思考
AggregateRoot和Entity的区别
AggregateRoot继承于Entity,并实现了IGeneratesDomainEvents接口
public class AggregateRoot<TPrimaryKey> : Entity<TPrimaryKey>, IAggregateRoot<TPrimaryKey>, IEntity<TPrimaryKey>, IGeneratesDomainEvents
{
public AggregateRoot();
[NotMapped]
public virtual ICollection<IEventData> DomainEvents { get; }
}
在DDD里面聚合根是一定对应一个实体
为什么要使用AggregateRoot
实现了IGeneratesDomainEvents,属性DomainEvents可以方便产生领域事件,这些事件在当前的工作单元完成之前自动的触发。
在ABP里面不会强迫使用聚合,但既然选用了ABP这个框架,那就是希望能使用DDD的开发模式,所以使用AggregateRoot是更好的实践。
IGeneratesDomainEvents解析
先贴关键源码
public abstract class AbpDbContext : DbContext, ITransientDependency
{
public override int SaveChanges()
{
//从DomainEvents中拿到定义的领域事件
var changeReport = ApplyAbpConcepts();
var result = base.SaveChanges();
//数据保存后,触发领域事件
EntityChangeEventHelper.TriggerEvents(changeReport);
return result;
}
protected virtual EntityChangeReport ApplyAbpConcepts()
{
var changeReport = new EntityChangeReport();
...
var entries = ChangeTracker.Entries().ToList();
foreach (var entry in entries)
{
...
AddDomainEvents(changeReport.DomainEvents, entry.Entity);
}
return changeReport;
}
protected virtual void AddDomainEvents(List<DomainEventEntry> domainEvents, object entityAsObj)
{
var generatesDomainEventsEntity = entityAsObj as IGeneratesDomainEvents;
if (generatesDomainEventsEntity == null)
{
return;
}
if (generatesDomainEventsEntity.DomainEvents.IsNullOrEmpty())
{
return;
}
domainEvents.AddRange(generatesDomainEventsEntity.DomainEvents.Select(eventData => new DomainEventEntry(entityAsObj, eventData)));
//清空DomainEvents
generatesDomainEventsEntity.DomainEvents.Clear();
}
}
怎么在聚合根里面如何发布领域事件
DomainEvents.Add(new BlogUrlChangedEventData(this, oldUrl));
没有调用EventBus.Trigger来触发领域事件,那添加到DomainEvents的EventData是在什么时候触发的呢?
阅读下源码不难发现,重写了SaveChanges方法,在序列化到数据库后触发领域事件
聚合根里面有两个甚至多个方法都调用DomainEvents来产生领域事件,会不会造成事件多次触发呢?
不会,阅读源码,很容易发现DomainEvents只是负责临时传递EventData,传递给了changeReport这个局部变量后,就会清空,实际上真正触发领域事件的是changeReport。
简单说,就是每次调用SaveChanes后就会清空DomainEvents
关于ABP聚合根类AggregateRoot的思考的更多相关文章
- 基于ABP落地领域驱动设计-02.聚合和聚合根的最佳实践和原则
目录 前言 聚合 聚合和聚合根原则 包含业务原则 单个单元原则 事务边界原则 可序列化原则 聚合和聚合根最佳实践 只通过ID引用其他聚合 用于 EF Core 和 关系型数据库 保持聚合根足够小 聚合 ...
- 基于ABP实现DDD--聚合和聚合根实践
在下面的例子中涉及Repository.Issue.Label.User这4个聚合根,接下来以Issue聚合为例进行分析,其中Issue聚合是由Issue[聚合根].Comment[实体].Iss ...
- Abp 领域事件简单实践 <四> 聚合根的领域事件
聚合根有个 DomainEvents 属性. 首先聚合根是一个实体.这个实体的仓储有变化(增删改)的时候,会触发这个DomainEvents 里的事件.就像EventBus.Trigger一样. pu ...
- DDD的实体、值对象、聚合根的基类和接口:设计与实现
1 前置阅读 在阅读本文章之前,你可以先阅读: 什么是DDD 2 实现值对象 值对象有两个主要特征:它们没有任何标识.它们是不可变的. 我们举个例子:小明是"浙江宁波"人,小红也是 ...
- 初识ABP vNext(11):聚合根、仓储、领域服务、应用服务、Blob存储
Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 目录 前言 开始 聚合根 仓储 领域服务 BLOB存储 应用服务 单元测试 模块引用 最后 前言 在前两节中介绍了ABP模块开发的基本步 ...
- ASP.NET Core Web API下事件驱动型架构的实现(四):CQRS架构中聚合与聚合根的实现
在前面两篇文章中,我详细介绍了基本事件系统的实现,包括事件派发和订阅.通过事件处理器执行上下文来解决对象生命周期问题,以及一个基于RabbitMQ的事件总线的实现.接下来对于事件驱动型架构的讨论,就需 ...
- 从壹开始微服务 [ DDD ] 之六 ║聚合 与 聚合根 (下)
前言 哈喽大家周二好,上次咱们说到了实体与值对象的简单知识,相信大家也是稍微有些了解,其实实体咱们平时用的很多了,基本可以和数据库表进行联系,只不过值对象可能不是很熟悉,值对象简单来说就是在DDD领域 ...
- NET Core Web API下事件驱动型架构CQRS架构中聚合与聚合根的实现
NET Core Web API下事件驱动型架构在前面两篇文章中,我详细介绍了基本事件系统的实现,包括事件派发和订阅.通过事件处理器执行上下文来解决对象生命周期问题,以及一个基于RabbitMQ的事件 ...
- Abp 聚合测试
Abp 官网开始的教程例子,是IRpositoty<entity> 直接出现在应用层.但是如果是一个聚合根也会这样吗? 那么聚合根是访问仓储的最小单元,要通过聚合根来操作业务,就是实体, ...
随机推荐
- HDU 2079-课程时间(生成函数)
课程时间(标题已被修改,注意阅读题) Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- leetcode[73] Set Matrix Zeroes 将矩阵置零
给定一个矩阵,把零值所在的行和列都置为零.例如: 1 2 3 1 3 1 1 1 操作之后变为 1 3 0 0 0 1 1 方法1: 赋值另存一个m*n的矩阵,在原矩阵为零的值相应置新的矩阵行和列为零 ...
- leetcode第20题--Valid Parentheses
Problem: Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if ...
- TableLayout中怎么填充相同的布局
在Android界面xml文件中可以导入另一个xml文件,就能实现一个功能就是重复利用相同的xml布局 有两种方法进行处理: include引入 定义一个布局Tab_flag.xml <?xml ...
- 前后端分离之Web前端架构设计
架构设计:前后端分离之Web前端架构设计 在前面的文章里我谈到了前后端分离的一些看法,这个看法是从宏观的角度来思考的,没有具体的落地实现,今天我将延续上篇文章的主题,从纯前端的架构设计角度谈谈前后端分 ...
- sql分组合并字段重复项sql for xml path
-------------------------(情景描述) 在我们处理数据时,可能会碰到这种情景: Id Name 1 a,b 2 ...
- DataGridView的使用和批量修改
DataGridView的属性:AllowUserToAddRows:如果为true允许用户添加行,false不允许用户添加行ReadOnly:true表示只读.不能修改单元格中的值,false可以对 ...
- java中数据库通用层
/** * 数据库通用类 * */ public class ConnDB { /** * 获取数据库连接对象 * @return 数据库连接对象 * */ public static Connect ...
- 字符串的使用(string,StringBuffer,StringBuilder)
String中==与equals的区别:==比较字符串中的引用相等equals比较字符串中的内容相等(因为字符串有重写equals方法) string常用的方法 返回类型 方法 操作功能 Char c ...
- 根据首尾字节的tcp分包断包算法
这个算是我的一点小总结吧,放出来分享给大家,原来在网上找这种算法都找了N久没找到,自己写也是走了许多弯路,就放出来遛一遛吧 大家将就这个看看, 这是其中的一个主要的方法,其余的我就不放出来了,其中的I ...