我一直在努力解决与 DDD 相关的规范问题,并且我已经阅读了很多关于 DDD 和规范以及存储库的内容。
但是,如果在不破坏领域驱动设计的情况下尝试将所有这 3 种结合起来,就会出现问题。归结为如何在考虑性能的情况下应用过滤器。
首先是几个明显的事实:
到目前为止,很容易。当/如果我们尝试将规范应用于存储库而不破坏 DDD 模式或出现性能问题时,就会出现问题。
应用规范的可能方法:
1)经典方式:在领域层使用领域模型的规范
应用传统的规范模式,带有
IsSatisfiedBy
方法,返回 bool
和复合规范组合多个规范。这让我们可以在领域层中保留规范,但是......
AutoMapper
)可以轻松解决此问题。 . 2) 使用持久性模型的规范
这类似于 1),但在规范中使用持久性模型。这允许直接使用规范作为我们
.Where
的一部分谓词将被转换为查询(即 TSQL),过滤将在持久性存储(即 SQL Server)上执行。3) 与 2) 类似,但将规范作为持久层的一部分
4) 与 3 类似,但将规范抽象为接口(interface)
我们将在我们的领域层中有规范接口(interface),在持久层中有规范的具体实现。现在我们的领域层只会与接口(interface)交互,而不依赖于持久层。
5) 将表达式树从领域模型转化为持久性模型
这当然解决了问题,但这是一项重要的任务,但它会将规范保留在我们的领域层中,同时仍然受益于 SQL 优化,因为规范成为存储库 Where 子句的一部分并转换为 TSQL
我尝试采用这种方法,但存在几个问题(从实现方面来看):
6) Query Builder like API
最后一个是制作某种查询 API,该 API 被传递到规范中,并且 Repository/Persistence 层将从其中生成一个表达式树以传递给
.Where
子句,它使用一个接口(interface)来声明所有可过滤的字段。我也朝这个方向做了一些尝试,但对结果不太满意。就像是
public interface IQuery<T>
{
IQuery<T> Where(Expression<Func<T, T>> predicate);
}
public interface IQueryFilter<TFilter>
{
TFilter And(TFilter other);
TFilter Or(TFilter other);
TFilter Not(TFilter other);
}
public interface IQueryField<TSource, IQueryFilter>
{
IQueryFilter Equal(TSource other);
IQueryFilter GreaterThan(TSource other);
IQueryFilter Greater(TSource other);
IQueryFilter LesserThan(TSource other);
IQueryFilter Lesser(TSource other);
}
public interface IPersonQueryFilter : IQueryFilter<IPersonQueryFilter>
{
IQueryField<int, IPersonQueryFilter> ID { get; }
IQueryField<string, IPersonQueryFilter> Name { get; }
IQueryField<int, IPersonQueryFilter> Age { get; }
}
在规范中,我们会传递一个 IQuery<IPersonQueryFilter> query
到规范构造函数,然后在使用或组合它时将规范应用到它。IQuery<IGridQueryFilter> query = null;
query.Where(f => f.Name.Equal("Bob") );
我不太喜欢这种方法,因为它使得处理复杂的规范有点困难(比如和或如果链接),而且我不喜欢 And/Or/Not 的工作方式,尤其是从这个“API”创建表达式树.我一直在找周 网上到处看了几十篇关于DDD和规范的文章,但他们总是只处理简单的情况,没有考虑性能,或者违反了DDD模式。
在不进行内存过滤或将持久性泄漏到域层的情况下,您如何在实际应用程序中解决这个问题?
是否有任何框架可以通过两种方式之一解决上述问题(类似于表达式树的语法的查询生成器或表达式树翻译器)?
最佳答案
我认为规范模式不是为查询条件设计的。实际上,DDD 的整个概念也不是。如果查询需求过多,请考虑 CQRS。
规范模式有助于开发无处不在的语言,我认为它就像一种 DSL。它声明要做什么而不是如何做。例如,在订购环境中,如果已下订单但未在 30 分钟内付款,则订单被视为逾期。使用规范模式,您的团队可以使用一个简短但独特的术语:OverdueOrderSpecification。想象一下下面的讨论:
情况1
Business people: I want to find out all overdue orders and ...
Developer: I can do that, it is easy to find all satisfying orders with an overdue order specification and..
案例-2
Business people: I want to find out all orders which were placed before 30 minutes and still unpaid...
Developer: I can do that, it is easy to filter order from tbl_order where placed_at is less that 30minutes before sysdate....
你更倾向哪个?
通常,我们需要一个 DSL 处理程序来解析 dsl,在这种情况下,它可能在持久性适配器中,将规范转换为查询条件。这种依赖(infrastructure.persistence => domain)不违反架构原则。
class OrderMonitorApplication {
public void alarm() {
// The specification pattern keeps the overdue order ubiquitous language in domain
List<Order> overdueOrders = orderRepository.findBy(new OverdueSpecification());
for (Order order: overdueOrders) {
//notify admin
}
}
}
class HibernateOrderRepository implements orderRepository {
public List<Order> findBy(OrderSpecification spec) {
criteria.le("whenPlaced", spec.placedBefore())//returns sysdate - 30
criteria.eq("status", spec.status());//returns WAIT_PAYMENT
return ...
}
}
关于repository - 领域驱动设计中的规范模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25953828/