我是域驱动设计的新手,所以如果这个问题很简单,请原谅。我正在阅读规范模式,我相信理解它的意图。 Web上的大多数示例都显示了它在两个地方的用法:
内部存储库方法
内部域服务/应用程序服务。
但这只有在EF实体和Domain对象相同时才有效。我想这不是一个好的做法(使用域名对象的EF实体)。 现在我的问题是 -
我们是否应该为域对象和EF实体编写不同的规范规则,或者有两种方法可以重用相同的规则吗?我想如果我们不使用c#表达式并使用反射,我们可以以某种方式实现。
答案 0 :(得分:0)
请记住,在使用EF存储库时,您可以使用默认选项 - 让存储库返回IQueryable<T>
而不是IEnumerable<T>
。许多程序员都对此感到担心,但如果以这种方式完成,那么LINQ将成为您在Infrastructure层中的规范。
然后,在域层中,您可以应用规范和规则模式来封装应该针对域对象进行测试的条件和规则。
还有其他技术,但这种组合是我通常在我的项目中应用的。
答案 1 :(得分:0)
这是我的内心深爱的话题。 (下面是直接答案)规范模式是不可知的。它所做的只是确定是否满足您定义(指定)的条件。在两个地方都有用。我看到了规范的两个主要好处:它为您的业务规则命名,并且隐藏(加密)您的实现。后续好处是,您可以根据需要锁定存储库,或者提供易于理解的查询或规则列表。
应用于域对象的规范与用作查询的规范稍有不同,但是非常接近。 “ QuerySpecification”应具有查询语言,目标存储库实现(EF)可以在数据库中采用并执行 ,并返回0个或多个匹配项。
应用于域对象,它通常用于检查特定对象是否“符合规范”或过滤列表中的适用对象(排除或包含)。用法看起来不同,或者是同一概念的不同方面。
我很尊重佐兰的建议。返回IQueryable意味着您为应用程序代码(可能是其他人的应用程序)提供了直接查询数据存储的功能。懒惰vs渴望加载也变成了真正的纠结。我认为,您将失去封装以及实现隔离。
还请记住, EF代表存储库和UnitOfWork 的实现。 DbContext是工作单元,而DbSet是存储库。应用自己的DDD接口的目的是确保您的域不依赖于EF实施,因此您的集成代码应该很小。
直接回答。
我建议向您的Repository接口添加一个方法,该方法接受IQuerySpecification并返回T。您的实际规范是域的一部分。这些是组织所需数据组合的规则。您可以将它们放在“共享内核”(库)中,或者根据需要将它们驻留在应用程序中。
请注意,理想情况下,通过使用查询规范,您可以消除经常弹出的所有专用存储库功能,因为规范将查询的事物与查询分开。埃里克·埃文斯(Eric Evans)写得更好:
规范的中心思想是将关于如何 从匹配的候选对象中匹配候选对象 反对。除了在选择方面有用之外,它也很有价值 用于验证和按订单生产 (https://www.martinfowler.com/apsupp/spec.pdf)
另请参阅https://matt.berther.io/2005/03/25/the-specification-pattern-a-primer/