2015-08-28 35 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層系統中經常會丟失。 –