我不会说有数据访问层本身。
实际上,存储库使用数据映射器将域转换为数据,反之亦然。
模型、服务或事务脚本必须使用存储库来获取和保存对象。这里没有循环引用:
- 服务层注入存储库/存储库以实现域操作。也就是说,如果服务需要对象,它会知道该怎么做,而不是关注如何将它们转换为数据。
- 存储库使用数据映射器来持久化和获取数据(1)。
- 数据映射器通常是 OR/M,如 Entity Framework、NHibernate、Dapper...
此外,一个好的 DDD 将强制执行 inversion of control,这意味着:
总之,DDD 没有你想象的 DAL,但它试图抽象和封装每个关注点,以便让上层与底层数据方法解耦。
关于循环引用的事情……
OP 说:
因为接口,实体是在模型中声明的
需要数据层和数据层需要参考
来自模型的持久性。
仔细检查您的陈述。如果模型代表比数据更高的抽象层,为什么数据应该引用模型?
需要数据的是模型。并且应该使用接口访问数据,以使模型与数据访问策略无关。 这叫做 inversion of control,正如我之前在这个答案中所说的那样。
也许您认为数据层需要对实体的引用,因为您仍在思考旧方法,但是如果您练习良好的关注点分离并使用数据映射器(或者您自己实现它),那么数据映射器只是将对象映射到原始数据,反之亦然,它不需要引用域对象等具体类(您应该问自己,Entity Framework 如何将您的实体持久保存到您最喜欢的数据库引擎,甚至不知道这些实体(2))。
无论如何,正如我之前在这个答案中所说的那样,您不应该考虑 DAL,而应该考虑一堆存储库和数据映射器,或者只是存储库(请参阅异常 (1))。
通常依赖的低层使用dependency injection pattern(inversion of control的可能实现)实例化并提供给上层。
(1) 这条规则的例外:如果我们不是在谈论关系存储,可能根本就没有数据映射器,存储库通过访问具有较低抽象级别的数据来实现其接口/封装。例如,如果存储库实现其操作以将数据存储在 XML 中,那么它将在内部使用 XDocument 或 XmlDocument,并且根本没有实际的数据映射器。
(2) 实际上,像实体框架这样的 OR/M 框架可以通过配置知道你的模型如何。虽然它不需要引用您的具体域来编译,但它要求您使用 Code First 或其他方法提供类映射)