我正在尝试学习域驱动设计的想法,并试图找出应该在何处放置数据库持久性代码。
通过“Vaughn Vernon实现域驱动设计”一书,我理解存储库或数据库操作(以及连接等)必须保存在模型项目(域模型上下文)本身中。我的理解是否正确?
我指的是他的IdentityAccessContext,AgilePMContext等样本,其中有存储库的接口。我一直在想着拥有一个单独的数据层,并且在这里添加一个数据层会让我产生循环依赖。因为接口,实体在模型中声明,这是数据层所必需的,并且需要从模型中引用数据层以实现持久性。
这是正确的还是我错过了什么?
答案 0 :(得分:2)
我不会说本身就有数据访问层。
实际上,存储库使用数据映射器将域转换为数据,反之亦然。
模型,服务或事务脚本必须使用存储库来获取和持久化对象。这里没有循环引用:
此外,一个好的DDD会强制执行 inversion of control ,这意味着:
总之,DDD没有你想象的DAL,但它试图抽象和封装每个关注点,以便让上层与底层数据方法分离。
因为Interfaces,Entities在Model中声明了 需要引用数据层和数据层 来自持久性的模型。
仔细检查你的陈述。如果模型代表比数据更高的抽象层,为什么数据应该引用模型?
这将是需要数据的模型。并且应该使用接口访问数据,以使模型对数据访问策略不可知。 这被称为 inversion of control ,正如我之前在此回答中所说的那样。
也许您认为数据层需要对实体的引用,因为您仍在考虑旧的方式,但如果您实践了良好的关注点分离并且您使用数据映射器(或者您自己实现),数据映射器只是将对象映射到原始数据,反之亦然,它不需要引用像域对象这样的具体类(你应该问自己,实体框架如何将你的实体持久保存到你喜欢的数据库引擎中,而不知道这些实体(2) )。
无论如何,正如我之前所说的那样,你不应该考虑DAL而是一堆存储库和数据映射器,或者只是存储库(参见 exception(1))。
通常使用dependency injection pattern(inversion 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只是在需要时才松散地与持久性耦合(感谢控制反转,大部分时间由依赖注入实现)。