我正在深入研究领域驱动设计 (DDD),并遇到了一个看似典型挑战的场景。它围绕创建域对象(例如聚合)进行,这些对象依赖于 ID,这些 ID 仅在对象持久化到数据库后才可用。
考虑这个例子:我们有一个功能可以将乘客添加到预订中。此操作的业务逻辑和规则封装在 Booking 聚合中。然而,Booking 聚合的旅客名单要求每位旅客都有一个 ID。问题是,除非乘客符合 Booking 聚合设置的特定规则,否则不应在数据库中创建乘客。另外,根据我的理解,我们希望将聚合作为一个整体而不是单独保存聚合的一部分。
处理 DDD 中这种常见情况的最佳方法是什么?其中一个聚合的创建取决于另一个聚合的 ID,但两者都需要遵守某些业务规则和验证?
预先感谢您的见解!
从我的角度来看,我尝试对需要 ID 的对象使用联合类型,这提供了一些灵活性。然而,它并不理想,因为它在许多通常需要 ID 的情况下添加了额外的检查和类型断言。同样在过去,我尝试在不存在的情况下分配随机 UUID,但某些数据库提供商不允许您分配 Id,所以我也不喜欢该解决方案。
在讨论细节之前,我必须指出,DDD 与实现细节无关,它是通过关注领域知识而不是实现细节来解决复杂性。领域模型模式有助于将这些细节与领域模型分离,让您专注于核心业务逻辑。
关于你的问题,首先我们看一下聚合设计。乘客和预订在同一个集合中是否有效?您可以将其设计为同时具有这两者。否则,您应该考虑最终一致性方法。
对于最终一致性,如果情况简单,可以通过集成事件来实现。您可以在通过发布事件持久化依赖实体后设置它们的 ID。
但如果很复杂(比如需要补偿操作),请考虑使用 Saga 模式(预订是在长期运行的过程中传递某些状态的请求)。
对于数据库设计问题,通过删除外键约束或使 FK 可为空来放松与其他聚合的关系。另一种方法是使用客户端生成的 ID,就像您刚才所说的,它解决了大部分问题。