数据访问层和DDD

时间:2015-08-20 16:51:50

标签: c# domain-driven-design

我正在尝试学习域驱动设计的想法,并试图找出应该在何处放置数据库持久性代码。

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

我指的是他的IdentityAccessContext,AgilePMContext等样本,其中有存储库的接口。我一直在想着拥有一个单独的数据层,并且在这里添加一个数据层会让我产生循环依赖。因为接口,实体在模型中声明,这是数据层所必需的,并且需要从模型中引用数据层以实现持久性。

这是正确的还是我错过了什么?

2 个答案:

答案 0 :(得分:2)

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

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

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

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

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

  • 上层知道下层。
  • 较低层不拥有对上层的任何引用。

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

关于循环参考物......

OP说:

  

因为Interfaces,Entities在Model中声明了   需要引用数据层和数据层   来自持久性的模型。

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

这将是需要数据的模型。并且应该使用接口访问数据,以使模型对数据访问策略不可知。 这被称为 inversion of control ,正如我之前在此回答中所说的那样

也许您认为数据层需要对实体的引用,因为您仍在考虑旧的方式,但如果您实践了良好的关注点分离并且您使用数据映射器(或者您自己实现),数据映射器只是将对象映射到原始数据,反之亦然,它不需要引用像域对象这样的具体类(你应该问自己,实体框架如何将你的实体持久保存到你喜欢的数据库引擎中,而不知道这些实体(2) )。

无论如何,正如我之前所说的那样,你不应该考虑DAL而是一堆存储库和数据映射器,或者只是存储库(参见 exception(1))。

通常使用dependency injection patterninversion of control的可能实现)实例化相关的较低层并将其提供给上层。

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

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

答案 1 :(得分:1)

  

阅读本书"实施Vaughn的域驱动设计   Vernon",我理解Repository或Database操作   (以及连接等)必须保留在Model项目中   (域模型上下文)本身。我的理解是否正确?

存储库抽象(接口)应该在Domain层中,但它们的具体实现位于Infrastructure层。

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

没有循环引用,因为持久性与Domain紧密耦合,但Domain只是在需要时才松散地与持久性耦合(感谢控制反转,大部分时间由依赖注入实现)。