Architecture 是否可以将服务/API客户端注入聚合根目录?

Architecture 是否可以将服务/API客户端注入聚合根目录?,architecture,domain-driven-design,modeling,event-sourcing,Architecture,Domain Driven Design,Modeling,Event Sourcing,我在建模或DDD方法方面完全没有经验。下面的描述可能会指出我缺乏关于实体、聚合或微服务如何工作的知识 背景 因此,我有一个发票域,其中发票对象是聚合根。我还有一个包含个人账单或发货数据的域,名为person 我的发票模型是通过使用简单事件源创建的。假设我有一个InvoiceCreated事件,带有发票ID、发卡人ID、状态和创建日期: class InvoiceCreated { private string id; private string issuerId; private

我在建模或DDD方法方面完全没有经验。下面的描述可能会指出我缺乏关于实体、聚合或微服务如何工作的知识

背景

因此,我有一个发票域,其中发票对象是聚合根。我还有一个包含个人账单或发货数据的域,名为person

我的发票模型是通过使用简单事件源创建的。假设我有一个InvoiceCreated事件,带有发票ID、发卡人ID、状态和创建日期:

class InvoiceCreated {
  private string id;
  private string issuerId;
  private string status;
  private Date dateCreated;
但是,我的发票实体不包含发卡机构的ID,而是包含全部值:

class Invoice {
  private string id;
  //...
  private Issuer issuer;
Issuer类只是从另一个域实体创建的VO。这两个域通过RESTAPI相互通信

问题

我正在从事件重新创建发票实体,该实体只有来自其他域的对象的ID。我无法从发票域直接访问此数据。我的总根数 应用应用和记录事件的方法。因此,为了正确应用上述事件,我需要拥有创建(开具)此发票的人员的数据

可能的解决方案

我正在考虑为聚合根提供某种服务/API客户机,从外部检索这些数据。它将对此数据进行API调用,然后在重播事件时将其存储在Redis中,然后使缓存无效

这种方法的主要缺点是我的事件的不变性——在人员模型更改的情况下,我所要做的就是更改发票的人员值——根本不需要更改事件,也不需要创建事件的新版本

但我担心这种方法的正确性。这个想法对我来说似乎很好也很正确,但实现起来让我有点困惑。我正在考虑用这种方法打破SRP规则,把代码弄得一团糟


你觉得怎么样?也许是我的模型错了?还是在这种情况下这样做是正确的?我没有使用任何事件处理程序或事件总线-这是一个非常简单的情况,我认为在聚合中应用事件本身并将其用作事件存储条目并不是一件坏事。

我认为在聚合中注入一些外部服务是一个坏主意。在我看来,聚合应该对应于事件流,并且应该是自一致的。根据事件流中的当前事件和命令中包含的数据,它应该决定是否生成另一个事件

接下来,发票的领域是什么?这里的发票似乎不正确。可能是订单、合同或类似的东西。它定义了业务价值和业务边界。对于此类合计,发票可能只是其中一个报告,即读取模型。它还将包含来自其他有界上下文的数据。例如客户名称和地址,它不属于初始上下文

我记不起Udi Dahan在脑海中的链接了,他对Amazon购物车的设计进行了一些鼓舞人心的讨论,该购物车可以从多个上下文中获取数据。所以,你的案子也需要更多的思考。当您认为发票是一个读取模型——那么,有多个数据源来构建它是完全可以的。但是,当您在自己的范围内管理数据一致性时,您更愿意保持自一致性


从单个聚合的事件中重新创建的内容实际上是决策所需的聚合快照。是的,事件必须是不可变的。因为更新事件就像修复过去的时间。它可能会导致一种不可能存在的状态。

我认为在聚合中注入一些外部服务是个坏主意。在我看来,聚合应该对应于事件流,并且应该是自一致的。根据事件流中的当前事件和命令中包含的数据,它应该决定是否生成另一个事件

接下来,发票的领域是什么?这里的发票似乎不正确。可能是订单、合同或类似的东西。它定义了业务价值和业务边界。对于此类合计,发票可能只是其中一个报告,即读取模型。它还将包含来自其他有界上下文的数据。例如客户名称和地址,它不属于初始上下文

我记不起Udi Dahan在脑海中的链接了,他对Amazon购物车的设计进行了一些鼓舞人心的讨论,该购物车可以从多个上下文中获取数据。所以,你的案子也需要更多的思考。当您认为发票是一个读取模型——那么,有多个数据源来构建它是完全可以的。但是,当您在自己的范围内管理数据一致性时,您更愿意保持自一致性

从单个聚合的事件中重新创建的内容实际上是决策所需的聚合快照。是的,事件必须是不可变的。因为更新事件就像修复过去的时间。它可能导致一个根本不可能存在的国家

是否可以将服务/API客户端注入聚合根目录

通常,域模型是内存中的数据结构和操作内存中数据结构的方法。试图跨越进程/应用程序/网络边界是很奇怪的。 “从其他地方获取数据”是您通常从应用程序层而不是域层执行的操作

域模型中的实体包含对不属于同一聚合的另一实体的引用,这也很奇怪

“事件源”实体需要不在事件中的数据是非常奇怪的。这种情况有时会发生,因为我们希望单独存储东西(例如,一个实体需要具有“被放弃的权利”的数据)
invoice = Invoice.fromEvents(...)
issuerId = invoice.issuerId()
issuerData = findTheIssuer(issuerId)
invoice.onIssuer(issuerid, issuerData)
// ...