【问题标题】:Data Access Layer and DDD数据访问层和 DDD
【发布时间】:2015-11-14 10:24:30
【问题描述】:

我正在尝试学习领域驱动设计的思想,并试图弄清楚我们应该将数据库持久性代码放在哪里。

通过阅读“Vaughn Vernon 的实施领域驱动设计”一书,我了解到存储库或数据库操作(以及连接等)必须保存在模型项目(领域模型上下文)本身中。我的理解正确吗?

我指的是他的 IdentityAccessContext、AgilePMContext 等示例,其中有存储库的接口。我一直有一个想法,即拥有一个单独的数据层,在这里添加一个会导致我产生循环依赖。因为接口,实体是在模型中声明的,这是数据层所必需的,而数据层需要从模型中引用才能持久化。

这是正确的还是我遗漏了什么?

【问题讨论】:

    标签: c# domain-driven-design


    【解决方案1】:

    我不会说有数据访问层本身。

    实际上,存储库使用数据映射器将域转换为数据,反之亦然。

    模型、服务或事务脚本必须使用存储库来获取和保存对象。这里没有循环引用:

    • 服务层注入存储库/存储库以实现域操作。也就是说,如果服务需要对象,它会知道该怎么做,而不是关注如何将它们转换为数据。
    • 存储库使用数据映射器来持久化和获取数据(1)
    • 数据映射器通常是 OR/M,如 Entity Framework、NHibernate、Dapper...

    此外,一个好的 DDD 将强制执行 inversion of control,这意味着:

    • 上层了解下层。
    • 下层不拥有对上层的任何引用。

    总之,DDD 没有你想象的 DAL,但它试图抽象和封装每个关注点,以便让上层与底层数据方法解耦。

    关于循环引用的事情……

    OP 说:

    因为接口,实体是在模型中声明的 需要数据层和数据层需要参考 来自模型的持久性。

    仔细检查您的陈述。如果模型代表比数据更高的抽象层,为什么数据应该引用模型?

    需要数据的是模型。并且应该使用接口访问数据,以使模型与数据访问策略无关。 这叫做 inversion of control,正如我之前在这个答案中所说的那样

    也许您认为数据层需要对实体的引用,因为您仍在思考旧方法,但是如果您练习良好的关注点分离并使用数据映射器(或者您自己实现它),那么数据映射器只是将对象映射到原始数据,反之亦然,它不需要引用域对象等具体类(您应该问自己,Entity Framework 如何将您的实体持久保存到您最喜欢的数据库引擎,甚至不知道这些实体(2))。

    无论如何,正如我之前在这个答案中所说的那样,您不应该考虑 DAL,而应该考虑一堆存储库和数据映射器,或者只是存储库(请参阅异常 (1))。

    通常依赖的低层使用dependency injection patterninversion of control的可能实现)实例化并提供给上层。


    (1) 这条规则的例外:如果我们不是在谈论关系存储,可能根本就没有数据映射器,存储库通过访问具有较低抽象级别的数据来实现其接口/封装。例如,如果存储库实现其操作以将数据存储在 XML 中,那么它将在内部使用 XDocument 或 XmlDocument,并且根本没有实际的数据映射器。

    (2) 实际上,像实体框架这样的 OR/M 框架可以通过配置知道你的模型如何。虽然它不需要引用您的具体域来编译,但它要求您使用 Code First 或其他方法提供类映射)

    【讨论】:

    • 谢谢,所以这增加了 2 或 3 层,例如一个用于定义所有 IRepository 的存储库抽象的项目,第二个用于实际存储库实现,第三个用于 DTO 对象。我同意你关于 DI 和 IOC 的注释以及上层对下层的知识,它们都很清楚。
    • @Muthu 您将图层与 Visual Studio 项目混淆了。存储库接口可以与实现存在于同一个项目中。没错,DTO 应该存在于一个单独的项目中,因为域和其他层都可能需要 DTO。
    • Fidemraizer,好的,谢谢。所以我们需要一个单独的DTO层对象,在保存之前把数据集展平,嗯。这对于 RDBMS 来说是有意义的。像Mongo这样使用nosql文档对象存储的场景会发生什么?
    • @Muthu 您不应该在一个问题中提出其他问题。相反,如果你觉得我的回答已经回答了原来的问题,你应该把它标记为正确的,并提出一个新问题。发布后,如果需要,可以与我分享链接,我将在新的问答中回答这个新的特定问题:)
    • @Muthu 我看到你标记了另一个答案,这绝对是错误的......存储库实现不是基础架构细节。
    【解决方案2】:

    阅读 Vaughn 的《实施领域驱动设计》一书 Vernon”,我了解存储库或数据库操作 (连同连接等)必须保存在模型项目中 (域模型上下文)本身。我的理解正确吗?

    存储库抽象(接口)应该在域层,但它们的具体实现在基础设施层。

    参见他的代码示例:https://github.com/VaughnVernon/IDDD_Samples/tree/master/iddd_agilepm/src/main/java/com/saasovation/agilepm,例如域/模型中的TeamRepository 接口和端口/适配器/持久性中的LevelDBTeamMemberRepository

    没有循环引用,因为持久性与域强耦合,但域仅在需要时才与持久性松散耦合(感谢控制反转,大部分时间通过依赖注入实现)。

    【讨论】:

    • @guillame31,谢谢。我在 C# 项目版本中缺少此链接。所以这有点令人困惑,你和马蒂亚斯的回答都让我有所理解。非常感谢。
    猜你喜欢
    • 2011-11-13
    • 1970-01-01
    • 2014-08-05
    • 2010-12-14
    • 2011-10-20
    • 1970-01-01
    • 2020-11-28
    • 2014-11-16
    相关资源
    最近更新 更多