使用NEventStore进行事件源,反腐败层设计

时间:2016-07-18 19:07:34

标签: c# domain-driven-design event-sourcing neventstore

我有两个具有一些类似功能的传统企业应用程序。我需要构建一个系统来响应来自这些系统的数据更改事件,处理该数据并通过多种格式的API公开组合结果。我想使用事件源/ DDD风格的架构,但我不确定它是否有意义。鉴于下面的简化模型,我该如何设计系统?

注意 - 编辑以下内容以澄清问题:

两个系统都有根据日期包含不同价格的产品。当价格变化时,每个系统可以发出包含遗留系统的标识符,该系统的主键,日期和新价格的事件PriceChanged。产品ID对于系统是唯一的,但在两个系统之间可能不是唯一的,因此系统ID也将包含在内。

    PriceUpdated {
       int systemId,
       int productId,
       Date date,
       Float amount
    }

在我的新系统的有界上下文中,将有一个服务接收此事件,需要通过systemId,productId和date查找我的聚合,然后发出命令以更新聚合中的相应价格。我的聚合定义为:

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和date查询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?由VoiceOfUnreason作为答案发布,我可以使用可重复的约定来生成systemId,productId和date的ID。这是从DDD角度推荐的选项吗?

1 个答案:

答案 0 :(得分:2)

你控制自己的身份证吗?

PriceUpdated {
   int systemId,
   int productId,
   Date date,
   Float amount
}

尝试查找aggregateId的另一种方法是计算aggregateId必须是什么。基本思想是,需要从此事件中查找聚合的不同点共享一个封装计算的域服务实例。

签名看起来就像您在问题中写的查询

// Just a query, we aren't changing state anywhere.
var aggregateId = idGenerator.getId(e.systemId, e.productId, e.date);

任何给定的实现都会使用它自己的salt,传递给它的参数,并生成一个哈希,它是在任何地方用来将这个参数组合映射到聚合的公共ID。

当然,您可以通过传入具有不同盐的idGenerator,使用相同的事件数据为不同的聚合生成标识符。

对于您的ID为UUID的特定情况,您可以使用Name-Based UUID