事件溯源中每个事件流有多个聚合
More than one Aggregate per Event Stream in Event Sourcing
假设一个事件流是一个事务边界,聚合是一个写入模型来强制执行不变量,我可以有两个或更多聚合专用于一个事件流吗?如果由于性能或过于复杂的设计原因不能选择一个大聚合体?
例如,我有以下由一个事件流表示的域模型:
{
"Products": [{
"Id": 1,
"Name": "Call-Centre",
"Services": [
{
"Id": 10,
"Name": "CloudStorage",
"Price": 250,
"Discount": 100
}
]
}]
我需要执行两个不变量。第一:每个产品的服务必须是唯一的(按名称)。第二:服务折扣值不能超过实际价格。
现在我考虑使用两个聚合:
ProductAggregate 包含用于执行第一个不变量的服务集合;
ServiceAggregate 仅包含用于执行第二个的服务信息。
我的解决方案是否存在缺陷?
一般来说,您不能将聚合嵌套在其他聚合中。他们可以通过根引用另一个聚合。您可以使对给定聚合的所有访问都通过另一个聚合。
例如产品汇总可能是这样的:
{
"Id": 1,
"Name": "Call-Centre",
"Services": {
"CloudStorage": 10
}
}
服务聚合可能是:
{
"Id": 10,
"Name": "CloudStorage",
"Price": 250,
"Discount": 100
}
如果服务实际上是产品的子项(产品 1 的 CloudStorage
不同于产品 2 的 CloudStorage
),那么您可以通过在服务(并且很可能有一个域约束,一旦服务与产品相关联,服务中的 Product
字段就不能更改)。涉及关系的操作可能会变成 sagas(例如,向产品添加服务或更新服务名称)。也可能值得将该关系编码到服务 ID 中,但如果 ID 可以是字符串或其他内容,这可能会更容易。
因为它们是不同的聚合,所以它们在概念上是不同的事件流(因为聚合定义的事务边界至少与事件流一样多)。将 2 个事件流投影为一个可能很有用:该投影可能能够正确排序两个源流之间的事件。这种排序的逻辑将取决于域(例如,知道哪些操作可以交错,哪些可以假设不是(例如,因为它们由 saga 协调))。
假设一个事件流是一个事务边界,聚合是一个写入模型来强制执行不变量,我可以有两个或更多聚合专用于一个事件流吗?如果由于性能或过于复杂的设计原因不能选择一个大聚合体?
例如,我有以下由一个事件流表示的域模型:
{
"Products": [{
"Id": 1,
"Name": "Call-Centre",
"Services": [
{
"Id": 10,
"Name": "CloudStorage",
"Price": 250,
"Discount": 100
}
]
}]
我需要执行两个不变量。第一:每个产品的服务必须是唯一的(按名称)。第二:服务折扣值不能超过实际价格。 现在我考虑使用两个聚合: ProductAggregate 包含用于执行第一个不变量的服务集合; ServiceAggregate 仅包含用于执行第二个的服务信息。 我的解决方案是否存在缺陷?
一般来说,您不能将聚合嵌套在其他聚合中。他们可以通过根引用另一个聚合。您可以使对给定聚合的所有访问都通过另一个聚合。
例如产品汇总可能是这样的:
{
"Id": 1,
"Name": "Call-Centre",
"Services": {
"CloudStorage": 10
}
}
服务聚合可能是:
{
"Id": 10,
"Name": "CloudStorage",
"Price": 250,
"Discount": 100
}
如果服务实际上是产品的子项(产品 1 的 CloudStorage
不同于产品 2 的 CloudStorage
),那么您可以通过在服务(并且很可能有一个域约束,一旦服务与产品相关联,服务中的 Product
字段就不能更改)。涉及关系的操作可能会变成 sagas(例如,向产品添加服务或更新服务名称)。也可能值得将该关系编码到服务 ID 中,但如果 ID 可以是字符串或其他内容,这可能会更容易。
因为它们是不同的聚合,所以它们在概念上是不同的事件流(因为聚合定义的事务边界至少与事件流一样多)。将 2 个事件流投影为一个可能很有用:该投影可能能够正确排序两个源流之间的事件。这种排序的逻辑将取决于域(例如,知道哪些操作可以交错,哪些可以假设不是(例如,因为它们由 saga 协调))。