Domain driven design CQRS命令和查询-它们是否属于域?

Domain driven design CQRS命令和查询-它们是否属于域?,domain-driven-design,cqrs,Domain Driven Design,Cqrs,在CQR中,它们的命令和查询是否属于域 这些事件是否也属于该域 如果是这种情况,那么命令/查询处理程序是否只是基础结构中的实现 现在我把它布置成这样: Application.Common Application.Domain - Model - Aggregate - Commands - Queries Application.Infrastructure - Command/Query Handlers - ... Application.WebApi -

在CQR中,它们的命令和查询是否属于域

这些事件是否也属于该域

如果是这种情况,那么命令/查询处理程序是否只是基础结构中的实现

现在我把它布置成这样:

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

另一个问题,你从哪里提出事件?命令处理程序或域聚合?命令和事件是DTO。您可以在任何层/组件中使用命令处理程序和查询。一个事件仅仅是一个通知,表明某些事情发生了变化。您可以拥有所有类型的事件:域、应用程序等

事件可以由处理程序和聚合程序生成,具体取决于您。但是,不管它们是在哪里生成的,命令处理程序都应该使用服务总线来发布事件。我更喜欢在聚合根目录中生成域事件

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


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

命令事件可能是非常不同的关注点。它们可以是技术问题、集成问题、领域问题

我假设,如果您询问域,您正在实现一个域模型(甚至可能使用域驱动设计)

如果是这种情况,我将尝试给你一个非常简单的回答,这样你就可以有一个起点:

  • 命令:是一种业务意图,是您希望系统执行的操作。在域中保留命令的定义。从技术上讲,这只是一个纯粹的DTO。命令的名称应始终为命令式“PlaceOrder”,“ApplyDiscount”一个命令仅由一个命令处理程序处理,如果无效,则可以将其丢弃(但是,在将命令发送到域之前,应进行所有验证,以使其不会失败)
  • 事件:这是过去发生的事情。对于企业来说,这是一个不可改变的事实。将域事件的定义保留在域中。从技术上讲,它也是一个DTO对象。但是,事件名称应始终为过去的“OrderPlaced”、“DiscountApplied”。事件通常是发布/订阅的。一个发布者有多个处理程序
如果是这种情况,那么命令/查询处理程序是否只是基础结构中的实现

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

但是,应用程序层不是强制性的。这取决于功能和技术要求以及已做出的架构选择。 你的说法似乎正确。我最好将命令处理程序保留在系统的边界上。若并没有合适的应用层,则命令处理程序可以扮演用例编排器的角色。如果您将其放在域中,您将无法非常轻松地处理横切关注点。这是一种权衡。您应该了解解决方案的利弊。它可能在一种情况下有效,而在另一种情况下无效

至于事件处理程序。我一般都是在家里处理的

  • 应用程序层,如果事件触发同一有界上下文中另一个聚合的修改,或者如果事件触发某些基础结构服务
  • 如果事件需要拆分为多个使用者或集成其他有界上下文,则为基础结构层
无论如何,你不应该盲目地遵守规则。总是有权衡,可以找到不同的方法

另一个问题,你从哪里提出事件?是命令处理程序还是域聚合

我正在从域聚合根目录执行此操作。因为域负责引发事件。 由于始终有一条技术规则,即如果在聚合中持续更改存在问题,则不应发布事件,反之亦然。我采用了事件源中使用的方法,这是务实的。我的聚合根目录有一组
未发布的
事件。在我的存储库的实现中,我将检查
未发布的
事件的集合,并将它们传递给负责发布事件的中间件。很容易控制,如果有异常持久化聚合根,则不会发布事件。有人说这不是存储库的责任,我也同意,但谁在乎呢。选择是什么。有笨拙的事件发布代码潜入您的领域,涉及所有的基础架构问题(事务、异常处理等),还是务实并在基础架构层处理所有问题?我两者都做过,相信我,我更喜欢务实

总而言之,做事没有单一的方式。始终了解您的业务需求和技术要求(可扩展性、性能等)。而不是基于此做出选择。我已经