2015-08-28 83 views
1

我正在使用具有事件源的CQRS。我有一个实体eg.Form与entityId。现在我必须在这个实体上发送复制命令(CommandName:CopyForm,EventName:FormCopied)因此,整个表单应该被复制并且具有不同的entityId。用事件源在CQRS中使用EntityId复制整个实体

所以,要实现这一点,我发送需要复制CopyForm命令的窗体entityId。整个表单从事件存储中加载,同时引发事件我将事件作为FormAdded提交,而不是FormCopied,它将添加与我们从eventStore加载的源表单完全相同的新表单并仅设置新的entityId。但是这里发布它是为了我复制而不是复制的形式而提出的同样格式的事件。我的框架不允许更改entityId。框架默认情况下,我为源表单和事件引发的entityId是针对具有相同entityId的源表单引发的。

有没有更好的方法在CQRS中使用Event-Sourcing进行实体的复制功能?

回答

1

布莱恩的回答很好,但有点不完整。

在事件采集系统中,域的命令服务需要能够从事件日志中对实体进行再水化。无论事件日志的后备存储是什么,它都可能通过EntityID进行索引,并且实体将通过从后备数据存储中提取给定EntityID的所有事件来进行再水合。因此,FormCopied事件需要有一个标准的EntityId字段,不是吗?

我们可以使用下列内容:

FormCopied { EntityId, OriginalEntityId } 

这仅仅是从布莱恩的回答略有不同,因为它允许多数民众赞成由ENTITYID索引事件存储。

FormCopied事件似乎是正确的,将成为将补充新的“Form”实体的流的一部分。但仍然存在问题。例如,假设下一个我们的用户试图向他/她的表单中添加一个新字段。这里是一个可能的下一个命令:

AddFieldToForm { EntityId, NewField } 

现在还想象,这个“形”实体具有一定的业务规则来检查,因为实体经常做。命令服务需要加载新的“表单”实体以检查业务规则,因此它将尝试从事件日志中重新提供“表单”实体。我们拉动事件日志并仅查找一个事件。

FormCopied { EntityId, OriginalEntityId } 

所以现在我们必须回到事件日志,也拉动了OriginalEntityId事件流,以获得新的实体的完全水化的副本。至少有2种方式,你可以这样做:

  1. 通过实际拉了OriginalEntityId事件流,然后重新播放它,就好像它是事件起源于这个新的实体 - 或 -
  2. 通过加载了原来与OriginalEntityId相对应的实体,并将其属性逐一复制到新实体。

你选择哪个取决于你的框架的功能。

+0

如果我们将事件作为FormAdded而不是FormCopied进行提升,该怎么办?为什么我们仍然不需要为原始实体单独提出以前发生的每个事件? –

1

你的情况似乎有点奇怪,但无论如何,我能想到的最简单的方法是获取Form的事件流,复制它们并替换副本中的实体Id(可以这样做,因为事件是简单的数据结构)。然后保存并发布新的事件流。如果被复制的事实具有域意义,FormAdded事件可以有一个属性IsCopied

4

发布一个事件,说明了新的事实:

FormCopied { OriginalEntityId, NewEntityId } 

与域的历史相结合,你现在有足够的信息来准确地了解副本应包含什么,以及这两个实体之间的关系(与IDS)。

+0

还应包含原始实体的版本:o) –

+0

@SirRufo:“FormCopied”事件告诉我们原始文件被复制的时间点,为我们提供了足够的信息,无需引入额外的数据。事件采购非常棒,因为您可以利用时间关系,这在n层系统中经常会丢失。 –