DDD领域驱动设计:领域事件
1 前置阅读
在阅读本文章之前,你可以先阅读:
- DDD领域驱动设计是什么
- DDD领域驱动设计:实体、值对象、聚合根
- DDD领域驱动设计:仓储
- MediatR一个优秀的.NET中介者框架
2 什么是领域事件?
领域事件是在领域中发生的事,你希望同一个领域(进程)的其他部分了解它。 通知部分通常以某种方式对事件作出反应。
3 实现领域事件?
重点强调领域事件发布/订阅是使用 MediatR 同步实现的。
首先,定义待办事项已更新的领域事件
public class TodoUpdatedDomainEvent : INotification
{
public Todo Todo { get; }
public TodoUpdatedDomainEvent(Todo todo)
{
Todo = todo;
}
}
然后,引发领域事件,将域事件添加到集合,然后在提交事务之前或之后立即调度这些域事件,而不是立即调度到域事件处理程序 。
public abstract class Entity
{
//...
private List<INotification> domainEvents;
public IReadOnlyCollection<INotification> DomainEvents => domainEvents?.AsReadOnly();
public void AddDomainEvent(INotification eventItem)
{
domainEvents = domainEvents ?? new List<INotification>();
domainEvents.Add(eventItem);
}
public void RemoveDomainEvent(INotification eventItem)
{
domainEvents?.Remove(eventItem);
}
public void ClearDomainEvents()
{
domainEvents?.Clear();
}
//... 其他代码
}
要引发事件时,只需将其在聚合根实体的方法处添加到代码中的事件集合。
public class Todo : AggregateRoot
{
//...
public void Update(
string name)
{
Name = name;
AddDomainEvent(new TodoUpdatedDomainEvent(this));
}
//... 其他代码
}
请注意 AddDomainEvent 方法的唯一功能是将事件添加到列表。 尚未调度任何事件,尚未调用任何事件处理程序。你需要在稍后将事务提交到数据库时调度事件。
public class Repository : IDisposable, IRepository
{
//...
private readonly IMediator mediator;
private readonly DbContext context;
public Repository(DbContext context, IMediator mediator)
{
this.context = context ?? throw new ArgumentNullException(nameof(context));
this.mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
}
public void Save()
{
mediator.DispatchDomainEvents(context);
context.SaveChanges();
}
public static void DispatchDomainEvents(this IMediator mediator, DbContext ctx)
{
var domainEntities = ctx.ChangeTracker
.Entries<Entity>()
.Where(x => x.Entity.DomainEvents != null && x.Entity.DomainEvents.Any());
var domainEvents = domainEntities
.SelectMany(x => x.Entity.DomainEvents)
.ToList();
domainEntities.ToList()
.ForEach(entity => entity.Entity.ClearDomainEvents());
foreach (var domainEvent in domainEvents)
mediator.Publish(domainEvent);
}
//... 其他代码
}
最后,订阅并处理领域事件
public class TodoUpdatedDomainEventHandler : INotificationHandler<TodoUpdatedDomainEvent>
{
private readonly ILoggerFactory logger;
public TodoUpdatedDomainEventHandler(ILoggerFactory logger)
{
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public Task Handle(TodoUpdatedDomainEvent todoUpdatedDomainEvent, CancellationToken cancellationToken)
{
logger.CreateLogger<TodoUpdatedDomainEvent>().LogDebug("Todo with Id: {TodoId} has been successfully updated",
todoUpdatedDomainEvent.Todo.Id);
return Task.CompletedTask;
}
}
DDD领域驱动设计:领域事件的更多相关文章
- 领域驱动设计和Spring
原文 http://static.olivergierke.de/lectures/ddd-and-spring/ 1.介绍这篇文章是的介绍一下领域驱动设计的基础构件.概念和Java的web应用(主要 ...
- 如何使用ABP进行软件开发(2) 领域驱动设计和三层架构的对比
简述 上一篇简述了ABP框架中的一些基础理论,包括ABP前后端项目的分层结构,以及后端项目中涉及到的知识点,例如DTO,应用服务层,整洁架构,领域对象(如实体,聚合,值对象)等. 笔者也曾经提到,AB ...
- 基于“事件”驱动的领域驱动设计(DDD)框架分析
摘抄自 从去年10月份开始,学了几个月的领域驱动设计(Domain Driven Design,简称DDD).主要是学习领域驱动设计之父Eric Evans的名著:<Domain-driven ...
- 浅谈我对DDD领域驱动设计的理解
从遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来解决. 比如,我是一家企业,然后我觉得我现在线下销售自己的产品还不够,我希望能够在线上也能销售自己的产品 ...
- DDD 领域驱动设计-商品建模之路
最近在做电商业务中,有关商品业务改版的一些东西,后端的架构设计采用现在很流行的微服务,有关微服务的简单概念: 微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成.系统中的各个微服务可被独 ...
- DDD 领域驱动设计-如何控制业务流程?
上一篇:<DDD 领域驱动设计-如何完善 Domain Model(领域模型)?> 开源地址:https://github.com/yuezhongxin/CNBlogs.Apply.Sa ...
- [转]DDD领域驱动设计基本理论知识总结
领域驱动设计之领域模型 加一个导航,关于如何设计聚合的详细思考,见这篇文章. 2004年Eric Evans 发表Domain-Driven Design –Tackling Complexity i ...
- 领域驱动设计(DDD)部分核心概念的个人理解
领域驱动设计(DDD)是一种基于模型驱动的软件设计方式.它以领域为核心,分析领域中的问题,通过建立一个领域模型来有效的解决领域中的核心的复杂问题.Eric Ivans为领域驱动设计提出了大量的最佳实践 ...
- DDD领域驱动设计之领域服务
1.DDD领域驱动设计实践篇之如何提取模型 2.DDD领域驱动设计之聚合.实体.值对象 3.DDD领域驱动设计之领域基础设施层 什么是领域服务,DDD书中是说,有些类或者方法,放实体A也不好,放实体B ...
随机推荐
- python之scrapy篇(三)
一.创建工程(cmd) scrapy startproject xxxx 二.编写item文件 # -*- coding: utf-8 -*- # Define here the models for ...
- Lambda 表达式实例
public class Java8Tester {/*** 语法 lambda 表达式的语法格式如下: (parameters) -> expression 或 (parameters) -& ...
- JavaScript入门-学习笔记(一)
JavaScript入门(一) 学习js之前,我们先来了解一下,什么是JavaScript? JavaScript是一种解释型语言.在运行的时候,一边读一边编译一边执行.简单来说就是,在执行js代码时 ...
- CVE-2021-3019 漏洞细节纰漏
CVE编号 CVE-2021-3019 lanproxy任意文件读取 该漏洞是2021年比较新的漏洞 是否需要认证:否 是否执行远程代码:否 是否执行远程命令:否 数据读取是否内网:否 漏洞软件介绍 ...
- 雅虎(ycsb)测试hbase(压测)
一.下载ycsb 0.10包 https://github.com/brianfrankcooper/YCSB/releases/download/0.10.0/ycsb-0.10.0.tar.gz ...
- ES6+Webpack+Babel基本环境搭建
### 本文基本是流水文,记录学习中步骤,希望对看到的你有用,蟹蟹. 基本环境搭建 技术栈 Webpack ES6 Babel 开发环境 VS Code Node 搭建环境过程 新建项目文件夹
- 第9章 集合处理(数组、Map、Set)
目录 1. 数组 1.1 创建数组 1.2 在数组两端添加删除元素 1.3 在数组任意位置添加.删除元素 delete删除数组元素无效 使用splice方法增.删.改元素 1.4 数组的常用操作 数组 ...
- EasyUI 表单插件 multiline easyui-textbox 多行换行失效问题
1.问题描述:原始html: <input class="easyui-textbox" name="myname" id="myid" ...
- Xamarin.Form 5.0: 新功能和控件以及调试改进
上周在.NET Conf 2020,Scott Hunter(.NET),Maddy Leger(微软移动开发工具-Xamarin项目经理)和David Ortinau(首席项目经理,移动开发人员工具 ...
- Java微服务 vs Go微服务,究竟谁更强!?
前言 Java微服务能像Go微服务一样快吗? 这是我最近一直在思索地一个问题. 去年8月份的the Oracle Groundbreakers Tour 2020 LATAM大会上,Mark Nels ...