基于事件驱动架构构建微服务第7部分:在仓储上实现事件溯源
原文鏈接:https://logcorner.com/building-microservices-through-event-driven-architecture-part7-implementing-eventsourcing-on-repositories/
在本文中,我將討論Repository上的Event Sourcing實現(xiàn)。
倉儲負責將事件添加到事件存儲并從事件存儲中檢索所有事件。
保存聚合后,所有與該聚合根相關(guān)的未提交事件都會添加到事件存儲表中。
eventstore表是一個只能追加的表(不允許更新和刪除)。
eventstore表的架構(gòu)如下所示:
Id 主鍵
Version 聚合的版本
AggregateId 聚合的標識符
Name 事件的名稱:2@735f8407-16be-44b5-be96-2bab582b5298
TypeName 事件的類型:LogCorner.EduSync.Speech.Domain.Events.Speech.SpeechCreatedEvent、LogCorner.EduSync.Speech.Domain、Version=1.0.0.0、Culture=neutral、PublicKeyToken=null
OccurredOn 事件日期
PayLoad 事件流:
IsSync 指示事件是否同步的布爾值
要重建聚合的當前狀態(tài),我們必須讀取與給定聚合ID相關(guān)的所有事件,然后調(diào)用函數(shù)LoadFromHistory。此函數(shù)屬于AggregateRoot類,應將所有事件應用于聚合。
事件溯源接口
讓我們定義IEventStoreRepository接口
GetByIdAsync 一個函數(shù),用于從事件存儲中檢索與聚合相關(guān)的所有事件。
AppendAsync 一個將事件附加到事件存儲的函數(shù)
事件溯源實現(xiàn)
讓我們定義EventStore類
Id 事件流的標識符
Version 當前的聚合版本
AggregateId 聚合的標識符
Name 事件流的名稱
TypeName 事件的完整類型(例如:LogCorner.EduSync.Speech.Domain.Events.Speech.SpeechCreatedEvent、LogCorner.EduSync.Speech.Domain、Version=1.0.0.0、Culture=neutral、PublicKeyToken=null)
OccurredOn 事件發(fā)生的日期
SerializedBody 事件序列化的JSON
AppendAsync 一個函數(shù),用于指示事件是否已同步。
APPENDASYNC 實現(xiàn)
測試用例1:AppendAsync應該在eventstore上附加一個事件:
在這里,我必須模擬一個上下文,創(chuàng)建一個 IEventStoreRepository實例并使用EventStore對象調(diào)用AppendAsync,然后上下文應該有一組帶有單個元素的 EventStore,并且該元素應該等于我在AppendAsync的參數(shù)中傳遞的eventstore對象.
測試可能如下所示:
但是我將使用entityframeworkcore inmemory數(shù)據(jù)庫而不是使用moq,這是一種更簡單的數(shù)據(jù)庫單元測試方法。
所以我可以像這樣實例化一個內(nèi)存上下文:
下一步是創(chuàng)建一個EventStoreRepository類
然后將DbSetEventStore屬性添加到DatabaseContex類
代碼編譯成功但測試失敗,因為DbSetEventStore為空。
所以讓我們配置一些映射
EventStoreEntityTypeConfiguration類負責將EventStore類映射到EventStore數(shù)據(jù)庫表
最終測試如下所示:
GETBYIDASYNC實現(xiàn)
GetByIdAsync從事件存儲中檢索與聚合相關(guān)的所有事件。
在這里,我必須創(chuàng)建一個Speech類型的空聚合,從與它相關(guān)的事件存儲中讀取所有事件,最后應用這些事件。
測試用例2:AggregateRoot的CreateInstance應該返回一個空的聚合
讓我們創(chuàng)建一個Invoker類,負責創(chuàng)建一個空的聚合根
測試通過
測試用例3:GetByIdAsync和BadAggregateId應該引發(fā)BadAggregateIdException
給定一個錯誤的aggregateId(例如:空的aggregateId),GetByIdAsync應該引發(fā)一個異常(BadAggregateIdException)
測試用例4:GetByIdAsyncWithNullInstanceOfAggregateShouldRaiseNullInstanceOfAggregateIdException
給定不存在的聚合ID(例如:空聚合 ID),GetByIdAsync應該引發(fā)異常 (NullInstanceOfAggregateIdException)
測試用例5:GetByIdAsyncWithoutEventsShouldReturnEmptyList
如果沒有與給定聚合ID相關(guān)的事件,則GetByIdAsync應返回一個空列表
測試用例6:GetByIdAsyncWithEventsShouldReturnTheCurrentStateOfAggregate
在這里,我必須從事件存儲中讀取與給定聚合ID相關(guān)的所有事件,重建聚合狀態(tài)并返回它。
為了達到這個目標,我必須根據(jù)事件類型反序列化json結(jié)構(gòu)中的事件。
測試用例6.1:反序列化事件流應該返回一個事件
在這里,我將創(chuàng)建一個將json字符串反序列化為Event對象的函數(shù)
測試用例6.2:GetByIdAsyncWithEventsShouldReturnTheCurrentStateOfTheAggregate
到這里,我將完成我的函數(shù)的實現(xiàn)
本文的源代碼可在此處獲得 (Feature/Task/EventSourcingRepository)
https://github.com/logcorner/LogCorner.EduSync.Speech.Command/tree/Feature/Task/EventSourcingRepository
總結(jié)
以上是生活随笔為你收集整理的基于事件驱动架构构建微服务第7部分:在仓储上实现事件溯源的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微服务之 EShop on dapr概览
- 下一篇: 微服务的终极目标,Mecha分布式运行时