问题标签 [domain-events]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
3 回答
505 浏览

event-handling - 领域事件 - 继承或使用枚举

所以猜想我有这种领域事件:

是更好还是:

因为他们说只有在类之间存在不同的行为时才使用继承,所以我假设在这里我会使用枚举示例(案例 #2)——因为域事件只是简单的 DTO。

但同样,在我的领域中,这种不同类型的事件具有不同的含义(不同的处理路径)。因此,如果我使用示例#1,我最终会得到很多:

而且我不能像这样明确:

我将不得不进行某种预处理,例如:

0 投票
2 回答
1649 浏览

domain-driven-design - 如何使用 DDD 处理更新实体 (CRUD) 和域事件?

我知道 DDD 非常适合基于任务的 UI,但我正在重构一个遗留应用程序,其中我有贫血域模型(许多设置器没有业务逻辑)。

第一步是让它到达模型并添加领域事件。虽然添加用于创建(TaskCreated在构造函数中)和删除(TaskRemoved)模型的事件是一个简单的过程,但我正在努力更新模型。

我们有一个带有 PUT/tasks/{id}端点的 RESTful API。在底层,框架将响应的主体映射到 DTO 对象,然后一一调用 setter:

我想在任务更新时收听一些事件,并在例如谷歌日历中更新它。正如您所想象的那样,如果我在每个setter(TextChanged、StartDateChanged)中记录事件并监听所有事件,我最终会收到许多对 Google API 的 API 调用,这不是我想要的。

问题是:我应该如何以正确的方式使用更新操作?我应该setters用一个update(newData)电话替换所有这些电话并在那里只调度一个域事件吗?更新任务后如何只对谷歌日历进行一次API 调用?

0 投票
0 回答
332 浏览

nservicebus - 有没有办法让域事件上下文不知道 NServiceBus 6 和 IBus 的删除?

我正在努力解决我们目前在域事件处理程序中使用 IBus 接口 (NServiceBus v5) 将命令发送到后端服务进行处理的情况。使用 IBus,无论是什么触发了事件,无论是在接收 Web API 请求时还是作为 NServiceBus 处理程序(公共域模型)的一部分,都可以发送这些命令。但是,在 NServiceBus v6 中,随着转向特定于上下文的接口、IEndpointInstance 或 IMessageHandlerContext,我的域事件处理程序现在似乎需要变得上下文感知。而且,看起来 IMessageHandlerContext 只能通过方法注入获得,所以我可能不得不在整个调用堆栈中都使用这个参数?

是否有一些我没有看到的方法可以让我的域事件处理程序上下文不知道?或者我是否遵循了一些通过这种代码气味暴露出来的不良做法?

编辑

这是将场景简化为最相关部分的尝试。领域模型中有一个订单,其状态可能会发生变化。当订单状态发生变化时,我们会通过发布者触发 StatusChanged 域事件。此特定域事件的订阅者写出状态更改的记录,并发送 NServiceBus 命令以传达此状态 - 此特定命令的处理程序将遵循一些关于是否发送电子邮件、SMS 消息等的进一步逻辑.,我认为不相关的细节。

订购领域对象

领域事件发布者

状态更改域事件处理程序

事情是,到目前为止,上面的示例代码都不需要知道状态是由于通过 Web API 请求进入的请求还是由于在 NServiceBus 消息的上下文中更改状态而改变的处理程序(在 Windows 服务中)- IBus 接口不是特定于上下文的。但是随着 NServiceBus v6 中 IEndpointInstance 和 IMessageHandlerContext 的区别,我不觉得我有同样的灵活性。

如果我理解正确,我可以在我的容器中注册 IEndpointInstance 并注入到 EventSubscriber,所以我会在 Web API 调用的情况下被覆盖,但我还需要添加一个 IMessageHandlerContext 作为参数如果状态恰好在消息处理程序的上下文中更改,则可以选择通过调用堆栈从 ChangeStatus 传递到发布者,最后传递到域事件订阅者。在整个调用堆栈中添加这个参数真的感觉不对。

0 投票
3 回答
2417 浏览

domain-driven-design - 领域驱动设计:如何建模嵌套的产品类别层次结构?更糟糕的是,如果产品类别是聚合根怎么办?

我正在练习领域驱动设计,那么为什么不构建一个演示产品目录项目呢?显然Product这里是核心域,但由于我想让项目更有趣,我很想支持嵌套Category层次结构。换句话说, aCategory可以有多个 child Category

此外,我想与域分离CategoryProduct使其成为自己的支持域。

问题:标记Category为 AggregateRoot 对我来说听起来不对。ACategory可以有很多孩子Category,这也是 AggregateRoots?!!我该如何进行建模?嵌套产品类别在电子商务现实生活中非常普遍。


命名空间DL.Demo.Domain.Shared

而且我实际上有AggregateRoot内在的东西,Entity因为我猜只有一个Entity可能是一个AggregateRoot


命名空间DL.Demo.Domain.Catalog

拥有 AggregateRoot 的嵌套列表对我来说听起来不合适。如果您不将 标记Category为 AggregateRoot,您将如何对其进行建模?

我是 DDD 和所有其他相关的很酷的东西,如领域事件、事件溯源等的新手。如果有经验的人能告诉我我是否走对了路,我将不胜感激。

0 投票
1 回答
262 浏览

domain-driven-design - DDD:同步有界上下文导致不同的域行为/逻辑

我目前正在研究一个由几个有界上下文组成的 DDD 系统。其中2个是:

  1. 上下文“账户管理”:只允许工作人员在这里工作。这个想法是管理客户帐户(如地址、电话号码、联系人等)并验证客户的帐户(基本上检查客户提供的数据是否有效)。
  2. 上下文“网站”:我可以作为客户登录并编辑我的数据(例如更改我的地址)

这是问题:

根据定义,登录到帐户管理上下文的用户是员工。所以我可以假设这里所做的更改在“数据已验证”的意义上是“值得信赖的”。appservice 的简化变体如下所示:

这是我在员工更改地址时调用的 appservice。请注意,我没有注入/使用 IdentityService 来了解员工是谁,因为这在这里并不有趣。Account 实体在成功调用其 changeAddress() 方法后会发出一个 AccountAddressChanged 事件,如下所示

但是,一旦客户在网站上编辑数据,我还需要反映更改。我计划通过“AccountAddressChangedViaWebsite”事件来异步执行此操作。帐户管理上下文将订阅并处理该事件,将相应的帐户再次设置为“未验证”。因此,帐户管理上下文的简化订阅者可能如下所示:

现在的问题是:员工直接调用应用服务,客户通过订阅者。如果我们说“我们必须在客户更新他的数据后重新验证一个帐户”,这听起来像是一个域概念。领域概念适合实体或领域服务,但不适合我所知道的应用程序服务或订阅者。这对我来说意味着应该避免以下情况(注意最后一行调用 unverifyAccount()):

这是有点隐藏在订阅者中的域逻辑,这看起来很奇怪。我有直觉认为这应该是域服务的责任,但是域服务如何知道它是由外部事件(通过订阅者)或命令调用的?

我可以传递一种“发起者”ValueObject,它告诉我造成这种情况的用户是员工还是外部系统。例子:

在这里,我将要做的事情委托给域服务。但是将 OriginatorService 双重分派到 Account 实体是否是一个好的解决方案?这样,实体可以通过询问传入的 originatorService 来检查是谁导致了更改,并且可以取消验证自己。

我想我会在这里陷入 DDD 兔子洞,但是在这种情况下,您的经验/最佳实践是什么?

0 投票
1 回答
269 浏览

asp.net - 如何使用 StructureMap 和当前请求容器从域对象发布域事件?

我正在尝试使用 DDD 创建一个应用程序,实现Domain Events,使用Entity FrameworkStructureMap进行依赖注入。

我创建了 UnitOfWork 和 Repositories 的抽象。很明显,IUnitOfWork实现封装了DbContext,所有实例都是通过StructureMap(Nested Container的per HTTP request)注入的,所以在所有repositories中注入(也注入)的IUnitOfWork都是同一个实例(顺便说一句,同理,只每个请求创建一个 DbContext 实例)。

UnitOfWork 实现是这样的......

...和存储库就像..

所有这些都运行良好,我可以使用 IUnitOfWork 实例管理上下文中的更改。

问题

我想实现领域事件,想法是有一个静态类,该类具有以这种方式发布事件的方法:

所以我可以在像实体这样的域对象中使用它。

但要让它工作,我不仅需要访问我的容器实例(所有事件处理程序都在其中注册),我需要访问当前嵌套容器实例以共享相同的 IUnitOfWork 实例(我不需要直接 IUnitOfWork,但我需要在所有存储库中注入相同的实例),因此事件处理程序中的任何操作都可以在相同的 DbContext 上执行)。

那么......我怎样才能拥有一个带有发布方法的静态类,以便在域中可用?

目前,我暂时解决了在服务上注入 IDomainBus 实例的问题,因此当前的嵌套容器用于创建事件处理程序实例。

但是,如果我想从这样的域实体内部发布事件,则无法使用此解决方案:

一个可能的解决方案...

一种可能的解决方案是将 DbContext 存储在 HttpContext 中并从存储库中检索它。因此,存储库实例和 IUnitOfWork 实例将不同,但使用的 DbContext 将是相同的。

我不喜欢这个解决方案,因为我不想使用 HttpContext。

也许有某种方法可以获取当前请求的嵌套容器......

你能给我一点光吗?谢谢

0 投票
2 回答
408 浏览

domain-driven-design - 域事件和数据库生成的 ID 作为原子进程的一部分

我在 DDD 中使用最终一致性和域事件,我遇到了以下问题。

使用工厂创建域对象时,我可以生成 GUID,但无法获取 DB 生成的 ID 以返回有效 ID 作为响应的一部分。

在同一事务中持久化域对象并避免等待最终一致性时,是否有可能以及如何使用域事件获取数据库生成的 ID。

数据库生成的 ID 是同一聚合根和存储库的一部分。

0 投票
0 回答
228 浏览

ioc-container - 使用 StructureMap 错误实现领域事件

我试图在我的解决方案中掌握引发/处理领域事件的基础知识。我正在使用 Visual Studio 2017、.Net Core 1.1、C#、StructureMap 4.5.1。

我的代码中的故障在单元测试中暴露出来,该单元测试在检查我的域事件是否被正确引发时失败。

我的Startup.cs课程包括以下代码:

在可能的情况下,我一直在关注 Udi Dahan 的方法Domain Events - Salvation

My DomainEvents 类实现以下接口:

DomainEvents 类如下:

我有一Task门课,更新时会引发TaskUpdatedEvent. TaskUpdatedEvent课程如下:

Task并且在我的课堂上通过以下几行引发了该事件:

到目前为止,我只有一个单元测试来检查是否引发了此事件。单元测试如下:

调用该Raise方法时,故障似乎发生在 DomainEvent 类中。调试显示事件已引发并设置了参数,但是容器是Null这样的,因此foreach循环无法检查处理程序。

我无法弄清楚为什么 Container 是Null,但我确定我一定遗漏了一些明显的东西。欢迎任何建议。

0 投票
1 回答
259 浏览

php - 聚合,DomainEvent 与 Prooph

我正在开发一个应用程序,它在验证后抓取 HTML 提要。这些网站仅支持电子邮件/密码身份验证,但某些集成可能需要额外信息。所以我的问题现在是在创建域事件和聚合时应该得到的具体问题吗?我与 Prooph 合作过,并创建了仅处理单个实体类型的简单聚合和域事件。但现在我想知道聚合和域事件是否应该针对这些第三方网站抓取工具。每个提要刮板应该有一个事件,还是创建一个通用事件并更好地聚合?每个聚合的属性可能不同。

然后类似的领域事件

还是创建单个聚合和域事件会更好?这两个网站都使用。请记住,支持的网站列表将会增加。

0 投票
1 回答
473 浏览

domain-driven-design - 应用命令后调用交叉聚合计算函数更新读取模型

我是 CQRS 的新手,在我的设计中需要关于以下情况的建议。一条命令更新聚合 A 的状态;因此需要使用交叉聚合计算方法的结果更新读取模型;此方法属于另一个聚合 B,该聚合 B 持有对聚合 A 的引用;该方法是聚合 B 和引用聚合 A 的状态的函数。调用此函数的正确位置在哪里?

我的考虑(可以跳过):

  • 命令处理程序更新聚合 A 的状态,技术上可以从存储库中获取聚合 B,对其调用计算并将结果放入域事件中;但是我认为获取聚合而不是被修改的聚合不是命令处理程序的工作,即使是出于阅读目的;此外,执行计算以发送事件而不是修改域的状态也不是命令处理程序的工作。
  • 域事件('聚合 A 已更新')仅包含聚合A的更新状态,聚合B的状态信息不足。读取模型的事件处理程序无法访问域模型,因此它既不能获取聚合B 也不在聚合 B 上调用所需的函数来更新读取模型。
  • 我知道命令所需的任何状态都在被修改的聚合外部,必须与命令一起传递。这样,应用服务在发送命令之前可以获取聚合 B 的状态(从读取模型中),并将其放入命令中。为此,我必须将函数从聚合 B 移动到某个服务,并在那里传递 A 和 B 的状态。这会使聚合 B 更加贫乏。加上上面提到的在命令处理程序中进行计算的问题。
  • 我读过有人建议只有读取模型感兴趣的任何计算都属于读取模型本身。因此,我的事件的读取模型处理程序将拥有执行计算所需的所有状态和行为。但是,这意味着我必须在查询端复制许多域模型概念;拥有完整的读取模型太复杂了。

我刚刚想到了以下解决方案:在域中,创建域事件“ Aggregate A updated ”的处理程序。它将获取聚合 B,对其调用计算方法,然后引发一个“聚合 B 函数结果已更改”事件,其中包含新的计算结果。然后读取模型能够从该事件中获取结果并更新自身。这样可以吗?

请注意,以防万一我没有使用事件溯源。

对这种情况的任何想法将不胜感激。谢谢!

更新: 使情况更加具体

我的聚合是Workers(聚合 B)和Group工人的 s(聚合 B)。Workers 和 Groups 是多对多的关系。想象一下 Group 和 Worker 都有一些Value财产。Worker'scalculateValue()是 Worker 的 Value 加上 Worker 参与的所有 Group 的 Value 的函数。上面描述的 Command 是Value针对某个 Group 进行修改的。结果,参与该组的所有工人将返回不同的结果calculateValue()

我想从读取模型中得到什么?我想要一个具有计算值的工人列表(已经考虑了工人所有组的值)。我什至不需要 Group 在读取端。如果我采用“在读取端进行计算”的方式,我需要组以及那里的整个关系结构。恐怕这将是一个不合理的并发症。