事件源,使用NEventStore进行反腐败层设计
本文关键字:反腐败 使用 NEventStore 事件源 | 更新日期: 2023-09-27 17:57:43
我有两个遗留的企业应用程序,它们具有一些类似的功能。我需要构建一个系统来响应来自这些系统的数据更改事件,处理这些数据,并通过多种格式的API公开组合结果。我想使用事件源/DDD风格的体系结构,但我不确定它是否有意义。考虑到下面的简化模型,我该如何设计系统?
注-以下内容经过编辑以澄清问题:
这两个系统都有根据日期包含不同价格的产品。当价格发生变化时,每个系统都可以发出一个事件PriceChanged,该事件包含旧系统的标识符、该系统的主键、日期和新价格。产品ID对于系统是唯一的,但在两个系统之间可能不是唯一的,因此还将包括系统ID。
PriceUpdated {
int systemId,
int productId,
Date date,
Float amount
}
在我的新系统的有限上下文中,会有一个服务接收到这个事件,需要按systemId、productId和日期查找我的聚合,然后发出一个命令来更新聚合中的相应价格。我的聚合将被定义为:
class ProductPriceAggregate
{
Guid Id,
int systemId,
int productId,
Date date,
Float amount
Apply(CreateProductPriceCommand e){
Id = e.Id;
systemId = e.systemId;
productId = e.productId;
date = e.date;
RaiseEvent(new ProductPriceCreatedEvent(this))
}
Apply(UpdateProductPriceCommand d){
amount = e.amount;
RaiseEvent(new ProductPriceUpdatedEvent(this));
}
}
如果我使用的是使用GUID存储流的NEventStore,那么每个aggreateId都将由GUID表示。我的服务需要使用systemId、productId和日期查询GUID,才能发出具有正确ID的命令。
服务可能看起来像这样:
class PriceUpdateService : ISubscribeTo<PriceUpdated>{
Handle<PriceUpdated>(PriceUpdated e)
{
var aggregateId = RetrieveId(e.systemId, e.productId, e.date);
if (aggregateId == null)
Raise(new CreateProductPriceCommand(e))
else
Raise(new UpdateProductPriceCommand(aggregateId, e.amount);
}
RetrieveId(int systemId, int productId, DateTime date)
{
// ???
}
}
问题是,查询聚合ID的最佳方式是什么?发出PriceUpdated事件的遗留系统将不知道此新系统。我可以使用一个响应ProductPriceCreatedEvent而更新的读取模型吗?该模型包含足够的信息来查询ID?我需要另一个负责索引ProductPrices的汇总吗?正如VoiceOfUnrealson发布的答案一样,我可以使用一个可重复的约定来根据systemId、productId和日期生成ID。从DDD的角度来看,这是推荐的选项吗?
您控制自己的ID吗?
PriceUpdated {
int systemId,
int productId,
Date date,
Float amount
}
尝试查找聚合ID的另一种方法是计算该聚合ID必须是什么。基本思想是,需要从该事件中查找聚合的不同点共享一个封装计算的域服务实例。
签名看起来像你在问题中写的查询
// Just a query, we aren't changing state anywhere.
var aggregateId = idGenerator.getId(e.systemId, e.productId, e.date);
任何给定的实现都有自己的salt,即传递给它的参数,并生成一个散列,该散列是用于将参数组合映射到聚合的通用id。
当然,您可以通过传递带有不同salt的idGenerator,使用相同的事件数据为不同的聚合生成标识符。
对于ID为UUID的特定情况,可以使用基于名称的UUID。