【问题标题】:Aggregates, Transactional Consistency and the Entity Framework DbContext聚合、事务一致性和实体框架 DbContext
【发布时间】:2015-02-22 13:47:09
【问题描述】:

聚合必须设计为事务性和最终一致性。这种围绕实体的一致性边界有助于管理复杂性。

在我们的存储库实现中,我们使用实体框架与实际数据库进行交互。从历史上看,我们总是有巨大的上下文(跨越数十个表),它们代表数据库中(或至少在数据库的某些功能区域)中的每个可用表、字段和关系。这里的问题是,这个上下文被用于数百种不同的事情,并且随着系统变得越来越大而呈指数增长,导致一些事情变得非常难以维护。

限界上下文划分

因此,通常建议为系统中的每个有界上下文创建单独的 DbContext。 Julie Lerman 在她的文章Shrink EF Models with DDD Bounded Contexts 中提出了这一点。

按总量划分

如果我们的聚合在事务上是一致的,那么是什么阻止我们更进一步并创建专用上下文来为每个聚合存储库提供服务?

它不会混杂(满足每个人的需求),而是会给出上下文明确的意图

  • 仅当聚合需要更改时,上下文才需要更改。它随着聚合而发展。对于更大的上下文,系统的许多部分可能依赖于上下文的一部分。一个单一的变化可能会危及很多。

  • 只有聚合所需的表、字段和关系需要存在于上下文中。通常在处理更大的上下文时,您不会为给定表上的大多数关系或字段而烦恼。

这种方法有一些缺点。即:

  • 尽管它们的建模方式可能不同(取决于它们的用途),但某些数据库表和关系可能需要存在于多个上下文中。

  • 如果使用,代码优先迁移会很棘手。

  • 这可能被视为过度设计。

任何人都可以提供有关此方法的进一步见解吗? 是否有一些我忽略了的东西?

编辑:

请注意,我们没有在我们的域中使用 EF 数据实体。我们的存储库从这些数据实体中实例化并合成更丰富的域模型。

【问题讨论】:

  • 我认为强制有界上下文只包含一个聚合是违反 DDD 的,因为域服务于特定的业务任务/区域,这可能涉及多个聚合。我看到它可能有一些好处(正如你所提到的),但这些好处的代价太大而不能违反 DDD 原则。

标签: domain-driven-design ddd-repositories


【解决方案1】:

我不认为多聚合上下文是一个问题,特别是如果您遵循严格的聚合分离 - 没有对聚合之外的实体的引用,只有根到根的键松散引用。

另一方面,如果您确定原子 DbContexts 是性能瓶颈,我可以理解您为什么会想要它。

但有一件事:EF 上下文不必完全映射到域层有界上下文。如果他们这样做并且您尝试在两侧尽可能地缩小上下文,则可能会在域层 IMO 中造成损坏。域 BC 可能会失去连贯性,并且重要的普遍存在的语言概念和细分的语义可能会在此过程中丢失。

【讨论】:

    【解决方案2】:

    好问题 - 如果您使用 EF 作为 CRUD 访问来实现存储库,然后在顶级丰富的 DDD 实体上分层,那么您的有界上下文不会决定用于持久化包含在其中的所有实体的底层数据库架构的大小?

    如果基础表和 EF 上下文很大,我认为这表明有界上下文可以进一步分解?

    我在 EF 中找到了一个有用的链接:http://mehdi.me/ambient-dbcontext-in-ef6/ 当我开始使用非常复杂的 EF 架构时,我尝试了不同的技巧,但最终将它们换成了 EventSourcing 存储库,但只有在投影和基础设施的痛苦值得得到的地方远离迁移、表耦合等。

    最终,如果被建模的有界上下文的大小正确,那么即使所有 DbSet 都包含在同一个 DbContext 中,复杂性仍然是可控的。

    我的建议是通过坚持使用较小的有界上下文而不是在有界上下文之间共享 EF 上下文/数据库来保持一切正常和可管理。

    您可能会发现,当有界上下文被重构和拆分时,您可以将某些部分建模为纯 CRUD 直接访问 EntiyFramework,使用 EF 简单地作为 ORM 直接访问 POCO,然后输出到您的应用程序层。

    【讨论】:

    • 感谢您的回答。好吧,有界上下文可以轻松地由 10 - 20 个聚合组成。也许更多。据我了解,有界上下文只是系统中特定通用语言的一致性边界。有界上下文中的 10 - 20 个聚合可能仍需要相当大的 EF 上下文。我可以将这个有界上下文拆分成更小的部分,但是我必须在它们之间创建更多的“集成点”。
    • 这也是一个有趣的链接 stackoverflow.com/questions/28815732/… 并且所有在 ORM 和域模型之间进行 1:1 映射的类似方式有时可能会很棘手 - 我发布的链接答案的最佳建议而且 guillaume31 的回答是通过 Key 引用而不是试图使用 EF 关系导航属性——当我开始使用 DDD 和持久性时,这真的让我很困惑。如果您仅通过密钥 ID 引用,那么 10 到 20 个聚合和生成的 EF 模型不会导致我失眠:)
    【解决方案3】:

    如果我们的聚合在事务上是一致的,那么是什么阻止我们更进一步并创建专用上下文来为每个聚合存储库提供服务?

    在我看来,这是一个非常糟糕的主意。让我给你一些见解。

    在领域驱动设计中,您有两种工具;战略和战术。您不应该划分基于模型的任意战术解决方案

    Bounded Context 是一种战略工具。这提供了一个建模边界,可以在其中创建特定业务问题域的解决方案。在单个限界上下文中是团队制定的Ubiquitous Language。在信号建模边界内,团队可以使用任意数量的有用战术建模工具,例如 AggregatesEntitiesValues Objects

    所以应用 DDD 的最大价值在于有界上下文的正确定义。它不仅仅是一个理论制品。 除以聚合只会导致混乱和混乱。您将无法非常清楚地分辨出您正在解决什么样的领域问题。

    另一方面,您只能使用 AggregatesEntitiesValues Objects 等战术模式,但这不是领域驱动设计。

    它不会乱七八糟(满足每个人的需求),而是会给上下文明确的意图......

    怎么样?我无法得到它。对我来说,这会造成更多的混乱。限界上下文集成是通过Anti corruption layers 完成的,它可以保护您免受外部更改的影响。有界上下文可以独立于其他上下文演化。如果您想从战略的角度更多地了解有界上下文之间的集成是如何发生的,请查看Context mapping

    尽管它们的建模方式可能不同(取决于它们的用途),但某些数据库表和关系可能需要存在于多个上下文中。如果使用,代码优先迁移将是棘手的。这可能被认为是过度设计。

    在进行领域驱动设计时,您不会根据技术限制来推动您的选择,尤其是 ORM 框架。

    更进一步:

    有时,聚合可以与限界上下文进行 1:1 映射。但这实际上取决于业务问题,而不是技术解决方案。

    如果没有更深入的了解,领域驱动设计并不容易应用。有时您的域并不真正需要它,因此尝试将其强制用于您的具体问题是没有意义的。

    作为结论,我会坚持 Julie Lermann 文章中提出的主张。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-05
      • 1970-01-01
      • 1970-01-01
      • 2011-03-17
      • 1970-01-01
      • 2017-05-14
      • 1970-01-01
      相关资源
      最近更新 更多