CQRS命令和查询 - 它们属于域吗?

时间:2015-08-26 01:03:29

标签: domain-driven-design cqrs

在CQRS中,他们的命令和查询是否属于域?

事件是否也属于域?

如果是这种情况,那么命令/查询处理程序只是在基础架构中实现吗?

现在我把它放在这样的位置:

Application.Common
Application.Domain
  - Model
    - Aggregate
  - Commands
  - Queries
Application.Infrastructure
  - Command/Query Handlers
  - ...
Application.WebApi
  - Controllers that utilize Commands and Queries

另一个问题,你从哪里举起活动?命令处理程序或域聚合?

3 个答案:

答案 0 :(得分:41)

命令事件可能是非常不同的问题。它们可能是技术问题,集成问题,域名问题......

我认为,如果您询问域名,您就会实施域名模型(甚至可能使用域名驱动设计)。

如果是这种情况,我会尽量给你一个非常简化的回复,这样你就可以有一个起点:

  • 命令:是一种商业意图,是您希望系统执行的操作。保持域中命令的定义。从技术上讲,它只是一个纯粹的DTO。命令的名称应该始终是必要的" PlaceOrder "," ApplyDiscount "一个命令仅由一个命令处理程序处理,如果无效则可以丢弃(但是在将命令发送到域之前应该进行所有验证,这样它就不会失败)。
  • 活动:这是过去发生的事情。对于企业而言,这是不可改变的事实。将域事件的定义保留在域中。技术上它也是一个DTO对象。但是,事件的名称应始终在过去" OrderPlaced "," DiscountApplied "。事件通常是pub / sub。一个出版商许多处理程序。
  

如果是这种情况,那么命令/查询处理程序只是在基础架构中实现吗?

命令处理程序在语义上类似于应用程序服务层。通常,应用程序服务层负责编排域。它通常围绕业务用例构建,例如"下订单"。在这些用例中,通过聚合根,查询等来调用业务逻辑(应始终封装在域中)。它也是处理cross cutting concerns的好处,如事务,验证,安全性等。

但是,应用程序层不是必需的。它取决于功能和技术要求以及已经制定的架构选择。 你的发言似乎是正确的。我最好将命令处理程序保留在系统的边界。如果没有合适的应用程序层,命令处理程序可以扮演用例orchestrator的角色。如果将其放在域中,您将无法轻松处理横切问题。这是一种权衡。您应该了解解决方案的利弊。它可以在一个案例中起作用而在另一个案例中起作用。

至于事件处理程序。我一般在

处理它
  • 应用程序层,如果事件触发在同一有界上下文中修改另一个聚合,或者该事件触发某些基础结构服务。
  • 如果需要将事件拆分为多个使用者或集成其他有界上下文,则为基础结构层。

无论如何,你不应盲目遵守规则。总会有权衡,可以找到不同的方法。

  

另一个问题,你从哪里举起活动?命令处理程序或域聚合?

我是从域聚合根目录进行的。因为域负责引发事件。 由于始终存在技术规则,如果在聚合中持续存在更改的问题,则不应发布事件,反之亦然,我采用事件采购中使用的方法,这是务实的。我的聚合根有一组Unpublished个事件。在我的存储库的实现中,我将检查Unpublished事件的集合并将它们传递给负责发布事件的中间件。很容易控制,如果持久存在聚合根,则不会发布事件。有人说它不是存储库的责任,我同意,但是谁在乎。选择是什么。使用所有基础架构问题(事务,异常处理等)进入事件发布的尴尬代码,或者实用并处理Infrastructure层中的所有内容?我已经完成了两个并且相信我,我更愿意务实。

总而言之,没有一种做事方式。始终了解您的业务需求和技术要求(可扩展性,性能等)。而不是基于此做出选择。我已经描述了我在大多数情况下所做的一般工作。这只是我的意见。

答案 1 :(得分:9)

在某些implementations中,命令和处理程序位于Application层中。 In others,他们属于域名。我经常在OO系统中看到前者,后者在功能实现中更多,这也是我自己做的,但是YMMV。

如果事件是指域事件,那么......是的,我建议在域层中定义它们并从域对象中发出它们。领域事件是您无处不在的语言的重要组成部分,如果您练习Event Storming,甚至可以由领域专家直接创造,因此将它们放在那里绝对是有意义的。

我认为你应该记住的是,对于大多数这些技术细节都没有规定,这些细节值得一成不变。关于DDD模板项目以及SO上的分层和代码“地形”存在无数问题,但坦率地说,我认为这些问题在制作强大,高性能和可维护的应用程序时不具有决定性作用,特别是因为它们与上下文有关。您很可能不会为每分钟有数百万次汇总更改的交易系统组织代码,就像50人使用博客发布平台一样,即使两者都采用DDD方法设计。有时你必须根据你的背景为自己尝试一些事情,并一路学习。

答案 2 :(得分:2)

命令和事件是DTO。您可以在任何层/组件中拥有命令处理程序和查询。事件只是通知某些内容发生了变化。您可以拥有所有类型的事件:域,应用程序等。

事件可以由处理程序生成并汇总到您自己。但是,无论它们在何处生成,命令处理程序都应使用服务总线来发布事件。我更喜欢在聚合根目录中生成域事件。

从DDD战略角度来看,只有业务概念和用例。域事件,命令,处理程序是技术细节。但是,所有域用例通常都是作为命令处理程序实现的,因此命令处理程序应该是域的一部分,以及实现域使用的查询的查询处理程序。 UI使用的查询可以是UI的一部分,依此类推。

CQRS的要点是至少有2个模型,命令应该是域模型本身。但是,您可以使用查询模型,专门用于域使用,但它仍然是读取(简化)模型。将命令模型视为仅用于更新,读取模型仅用于查询。但是,您可以拥有多个读取模型(由特定层或组件使用)或只有一个通用(用于所有查询)。

相关问题