Orm DDD:存储库契约

Orm DDD:存储库契约,orm,domain-driven-design,repository,ddd-repositories,design-by-contract,Orm,Domain Driven Design,Repository,Ddd Repositories,Design By Contract,我在不同的地方读到,DDD中的一个重要要求是对存储库有一个有约束的契约: findByName(string name) findByEmail(string email) etc. 并且不提供通用查询接口: findBySpecification(Specification spec) 我确实理解为什么这很重要:能够模拟存储库进行测试,或者更改底层持久性框架 虽然这条规则在整个应用程序中并不难执行,但在为用户提供“高级搜索”表单时,我不知道如何执行它 比如说,我有一个表单,可以通过关键字、

我在不同的地方读到,DDD中的一个重要要求是对存储库有一个有约束的契约:

findByName(string name)
findByEmail(string email)
etc.
并且不提供通用查询接口:

findBySpecification(Specification spec)
我确实理解为什么这很重要:能够模拟存储库进行测试,或者更改底层持久性框架

虽然这条规则在整个应用程序中并不难执行,但在为用户提供“高级搜索”表单时,我不知道如何执行它

比如说,我有一个表单,可以通过关键字、日期、作者等搜索博客帖子

这些标准是可以自由组合的,我显然不能为每个用例提供一种方法:

findByKeyword(string keyword)
findByDateRange(Date from, Date to)
findByKeywordAndDateRange(string keyword, Date from, Date to)
findByDateRangeAndAuthor(Date from, Date to, User author)
etc.

我是否遗漏了某些内容,或者这是该规则的例外情况之一?

作为参数传递到存储库没有什么问题。这实际上是解决存储库接口上方法爆炸的一种非常好的方法。看看这个。”对于“高级搜索”场景,“过滤器”的名称可能比“规范”更合适。我认为该代码不会违反任何DDD指南:

Filter filter = new FilterBuilder()
    .WithinDateRange(dateRange)
    .IncludingKeywords("politics", "news")
    .ByAuthor("John Smith")
    .Build();

blogs.FindByFilter(filter);
请注意,创建筛选器的代码可以位于域之外。因为它不会违反任何域规则。如果有一条规则,比如“匿名作者发布的博客应该得到版主的批准”,该怎么办?虽然它可以用过滤器表示,但这样做会使业务逻辑的一部分外部化。将此规则放在域代码中,并有一个专用的存储库方法,如:

blogs.RequireModeratorAttention();

存储库模式有两个主要好处:

  • 它将应用程序与持久层和惯用语分离
  • 它将数据访问集中化并限制到定义良好且易于理解的域段(存储库中的数据访问方法具有定义良好的结果,并且可以合理地进行测试)
  • 如果使用持久性层提供的规范模式的实例(例如NHibernate标准),则否定了一个好处。使用规范模式(即使是您自己使用的模式)也会降低第二个模式的好处

    也就是说,在某些情况下,比如搜索界面,规范是必要的——只需确保并使用自己的规范即可

    虽然这条规则在整个世界范围内并不难执行 应用程序时,我不知道如何在涉及到 向用户提供“高级搜索”表单

    实际上,如果您只需要一个搜索表单,就不必支付所有这些抽象的费用。存储库(至少在DDD的上下文中)设计用于从业务逻辑(应用层)中抽象持久性框架的细微差别

    如果您有一个更改用户地址的命令,那么最好使用finduserbyd方法创建一个存储库,而不是在应用层中使用一些神奇的Hibernate代码。这有两个原因

    • 您可能希望使用持久性层测试应用程序层 (笑声)嘲笑
    • 应用层是您关心的事情 因为这是商业逻辑
    您不需要所有这些来为UI获取一些数据。我建议使用专门的“Finder”类,这些类甚至可能存在于UI层中。它们既可以在抽象的“规范”上运行,也可以(甚至更好)在裸Hibernate(或您最喜欢的ORM)上运行。我已经写了一篇关于这种方法的博客文章