当我第一次了解域驱动设计时,我还被介绍到了存储库和工作单元模式,这些存储模式和工作单元曾经看起来像是那些酷炫的孩子向数据库发送SQL查询(例如穴居人)的最佳选择。我对这个话题的了解越深,我越了解到它们似乎不再是必需的了,因为EF和NHibernate之类的ORM将工作单元和存储库都实现到一个称为会话或上下文的API中。
现在我不确定该怎么办。是否存储库。我真的很理解这样的论点,即这样的泄漏抽象只会使事情变得复杂,而绝对没有增加任何可以简化数据访问的东西,但是,将我的应用程序的各个方面都耦合到例如实体框架。通常,我遵循一些简单的准则:
域层是系统的核心,包含实体,服务,存储库...
基础结构层提供基础设施关注的域接口的实现,例如文件,数据库,协议..
应用程序层承载一个组合根,该根将所有事物连接起来并进行编排。
我的解决方案通常如下所示:
Domain.Module1
Domain.Module2
IModule2Repo
IModule2Service
Module2
Infrastructure.Persistence
Repositories
EntityFrameworkRepositoryBase
MyApp
Boostrapper
-> inject EntityFrameworkRepositoryBase into IRepository etc.
我使用
IRepository<'T>
保持域层整洁,这也是一个域关注点,不依赖于其他任何告诉我如何访问数据的内容。现在,当我需要需要数据访问的IModule2Service
的具体实现时,我将不得不注入DbContext
并将其直接耦合到基础架构层。(在Visual Studio项目中,由于循环依赖,最终可能会非常棘手!)
此外,还有什么可以代替收藏家和作品的收藏夹? CQRS?如何抽象一个纯粹的基础架构?
最佳答案
“仓库”,哈哈...
无论如何,您正确了一点,就是不希望将域与EF耦合,这就是为什么存储库接口中的T应该是域聚合根,而不是EF实体(或旨在与EF正常工作的“域”对象) 。
您的域层永远不会与持久性耦合,因为它只知道抽象。当Module2Service需要数据访问时,它要么使用DAO(或者仓库-不一定是DDD版本-如果有意义),或者服务本身是在DAL中实现的(如果它不包含业务逻辑)。
在您的情况下,最好的方法可能是DAO /存储库,它当然会“隐藏” EF部分。如果看起来您编写的代码过多,则实际上并非如此,我认为保持适当的关注点分离最重要的是节省50 LoC(整个5-10分钟)。
CQRS始终是一个具有丰富域的好主意,但是任何解决方案都会带来需要更多代码的缺点(而且我了解每个编码器从定义上讲都是懒惰的,但是我们需要做一个“ fuckton”工作,一个应用本身并不会自行构建,因此可维护的应用在开始时就需要做更多的工作)。
如果通过抽象一个纯粹的基础架构框架意味着隐藏EF,那么存储库是您最好的选择,而您甚至不必将类命名为“存储库”,那么这就是重要的原则,这就是仓库的作用:抽象化域的持久性。