如何使用更新频率不同于根的子实体集合处理聚合根?

时间:2016-05-24 09:32:01

标签: domain-driven-design repository-pattern aggregateroot

我们的系统中有一个聚合根,并且在集合中有子实体。问题是容器需要在交易的基础上非常频繁地更新,而子实体不需要更新,它们实际上几乎没有变化,它们在性质上更像是配置。

我的第一反应是将它们分成两个不同的聚合根,因为我们的应用要求。但我被提醒了级联删除规则,如果我们删除那个删除应该级联,所以它们的生命周期是相关联的。

当我们发现存在缓存问题时,我们偶然发现了这个问题。子系统实体(配置)的更改未在运行时在系统中反映,因为父级不知道这些更改(我们将它们作为一个聚合根,但有人为其子级创建了一个存储库)。

2 个答案:

答案 0 :(得分:6)

聚合边界的主要驱动因素是域的不变量 - 或者换句话说,聚合边界应该是一致性边界。 必须一起更改原子的内容必须在同一个聚合中。

级联删除是(关于聚合边界)而不是规则的好处。您始终可以通过在加载Parent个实体的位置要求一个Child来强制实施这一事实。使用此设计,您可以使ParentChild具有不同的聚合,同时仍然执行不会自由浮动的规则#34;可以请求Child聚合。如果您有域事件,则删除Child聚合以响应已删除的Parent很容易。

注意:所有这一切都假设您的域不变量允许首先分离聚合。

答案 1 :(得分:3)

这在讨论格式中可能更好,而不是Q& A格式。我建议您在DomainDrivenDesignDDDCQRS

尝试观众

您确定要有业务要求来删除域模型中的数据吗?这是非常不寻常的 - 在我见过的大多数领域模型中,聚合将达到生命的终点" state,(例如:AccountClosed),但实际上并没有从系统中删除。

聚合设计中的一个常见陷阱是考虑实体的结构。 " A有B"并不一定意味着它们是同一聚合体的一部分;关键的想法是" A需要保持B和C一致"。你可以像图表一样思考它;状态B和状态C是图中的节点,一致性规则是边。如果你不能将图表从B转移到C,那么他们就不需要成为同一聚合的一部分,而且可能不应该是。

我的直觉是缓存应该是正确的答案。如果您每天处理数百万笔交易,并且该集合每月只更改一次,那么只需使用集合的缓存值就可以在大多数情况下产生正确的答案。

在这一点上,我受到了Udi Dahan的论文Race Conditions Don't Exist的影响;通过将此配置集合与集合的其余部分耦合,您实质上断言,对于集合的两个其他更改,业务将理解对配置的更改(这种情况很少见)。每天3M交易平均每30毫秒1;你真的在准确安排你的配置变化吗?

这里通常的模式是从域模型中删除一致性规则;相反,您监视引入不一致的更改并缓解它们。这取决于有一种合理的方法来检测错误,一种有效的缓解方法,以及一种控制速度的机制。

后者通常通过让客户端/应用程序检查其集合的本地副本,并确保发送的命令与将命令分派给域模型之前的命令一致来完成。 (对于您的域专家可能存在的问题:需要多快地应用配置更改?当聚合频繁更改或安静时,是否会发生配置更改?)

另一种可能性可能是改变你的持久性策略;如果集合没有经常变化,那么就没有很多与之相关的变化事件。所以也许不是坚持聚合,而是坚持其历史 - 换句话说,在这里使用事件采购。也许如果这个聚合体生活在微服务中,你可以限制改变的风险吗?很难说,每天有一百万笔交易,这个汇总听起来非常重要。