DDD - 如何在 EF Core 中管理跨边界上下文的实体

DDD - How to manage entities across bounded contexts in EF Core

我还没有找到这方面的具体例子。我知道每个限界上下文都有自己的实体版本,您不应该跨上下文共享实体。但是我该如何管理与使用像 EF 这样的 ORM 相关的问题呢?

例如,下面是我的实体及其存在的限界上下文:

成分(实体限界上下文 A)

食谱(实体限界上下文 b)
成分(实体限界上下文 b)
MenuItem(聚合有界上下文 b)

现在每个限界上下文都有自己的成分版本。但是由于我在 EF 中有一个单独的数据库上下文来管理它,我该如何安排呢?我正在使用 CQRS,因此我可以在需要时触发事件。我的计划是在我的 Recipe 实体中维护一个 ID 列表,并从数据库中提取相关成分,这样数据就不会重复。

但我不确定我的数据重复问题是否成立。在我上面的示例中,想象一家销售食材的企业,但也有可以在食品摊上出售的预设食谱(带有食材清单)。

在一个上下文中,成分与另一个实体没有关系,而在另一个上下文中,它是一个子实体(在聚合中)。我可以看到它应该如何设计(有界上下文中的单独实体)但是当涉及到数据库时,这实际上是如何设置的?如果在上下文 A 和上下文 B 中需要跟踪的 properties/domain 成分知识不同怎么办?这最终会成为一个单独的 table 吗?我对此有点迷茫。

编辑: 请记住我在这里只使用 1 个数据库。我知道通常每个限界上下文都有单独的数据库来避免这种情况,但我想知道如何通过 1 个数据库来实现这一点。

TL/DR:拥有单一数据库服务完全没问题(对于较小的服务或由于某些业务特定原因),只要不共享数据.如果您使用普通形式的数据库,请使用不同的 tables 来存储您的两种成分。

更长的版本:

如果这两个限界上下文中的 ingredient 实体由相同的物理 table 支持,而且它们可以共享数据(一个 Ingredient 实体可以对其他成分实体创建的数据进行操作),那么它们并不是真正独立的。

以 BC 为边界的一个非常重要的方面是允许这些实体独立进化。通过让他们共享 table(或文档集合),您不允许这种情况发生。此外,这违反了 "you shouldn't share a db across service boundaries".

更通用的(我的意思是非 DDD 特定的)指南

我会将您的问题分为两部分:

  1. 架构部分:限界上下文design/boundaries
  2. 技术部分:数据库模式管理、EF 映射等

从第 1 点开始,我要强调的是,限界上下文边界比您在问题中暗示的要厚。如果边界定义明确,则 BC 之间几乎没有数据重复,一部分来自某些 ID,仅此而已。在您的例子中,BC-A 中的成分与 BC-B 中的成分具有相同的 ID。

例如,您的BC-A可能会管理成分的名称、描述、图片等。 BC-B 不需要此信息,但它可能具有创建配方所需的一些重要属性。以类似的方式,BC-C 可能具有每种成分的供应商、价格等。

此外,在您的 BC-B 中,您可能在两个地方有配料:A table 包含所有配料及其有趣的配方属性,以及作为配方一部分的实体。例如,该实体不会具有所有这些属性,而是具有成分 ID 加上该配方中使用的数量。

使用这种类型的设置,不仅原则上不可取,而且在实践中,跨限界上下文共享成分 tables 也是不可取的。

很多时候,数据复制的需求来自UI需求。比如显示Recipes时需要显示Ingredient的名称,但是可以通过UI composition来解决。 UI 可以从 BC-B 中提取食谱,并使用 BC-A 中的名称以及 BC-C 中的价格来丰富数据。

如果您采用这种方法,第 2 点应该独立存在:每个 BC 都应该有自己的 DbContext。可以为所有 DbContext 使用相同的连接字符串(数据库),但您可以使用特定的 DB 模式初始化 DbContext。这样,您可以在每个 BC 中有一个 Ingredients table 而没有 DB table 冲突,并且您也可以在每个 DbContext 中有 EF 迁移版本 tables(尽管我相信它也适用于共享 table)。此设置还为您提供了一个优势,即允许您在每个限界上下文的单个 DB 中分离数据库,而无需更改任何代码。出于可扩展性的原因,或者为了促进基础架构即代码等,您最终可能需要它。