简化的 CQRS 和 DDD - zilor-net/eShopOnContainers-CN-Wiki GitHub Wiki

本页面探索了一些在 eShopOnContainers 中使用简化的 CQRS 和 DDD 方法相关的代码细节。

概念总览

CQRS 是一种用于命令和查询责任隔离的模式,用非常简单的术语来说,它有两种不同的方法来处理应用程序模型。

命令负责更改应用状态,即创建、更新和删除实体(数据)。

查询负责读取应用程序状态,例如显示信息给用户。

命令与领域规则、限制和事务边界有关。

查询与表示层、客户端 UI有关。

当处理命令时,应用模型通常用 DDD 结构来表示,例如 聚合根、实体、值对象等,并且通常有一些规则来限制允许的状态变化,例如在配送之前必须支付订单。

当处理查询时,应用程序模型通常由实体和关系表示,可以像SQL查询一样读取并显示信息。

查询不会改变状态,所以它们可以根据需要运行,并且总是返回相同的值(只要应用程序状态没有改变),也就是说查询是“幂等的”。

为什么要分离?因为修改模型的规则可能会对读取模型施加不必要的约束,例如,你可能只想让订单项在配送之前才能更改,这样订单就像看门人(根聚合)一样访问订单项,但你可能还想查看某些商品项的所有订单,因此,因此,你必须能够首先访问订单项(以只读方式)。

在这个简化的 CQRS 方法中,DDD 模型和查询模型都使用同一个数据库。

命令查询位于应用层,原因如下:

  1. 它是领域聚合根聚集的地方(命令)
  2. 它接近 UI 需求,并且可以访问微服务的整个数据库(查询)。

理想情况下,聚合根彼此不知到对方,应用层的职责是通过领域事件组合协调操作,因为它知道所有的聚合根。

关于查询,也是同样的分析,除了聚合根的限制外,应用层知道数据库中的所有实体和关系。

代码细节

CQRS

可以在购物服务中查看 CQRS 模式:

Commands and queries are clearly separated in the application layer (Ordering.API).

命令和查询在应用层(Ordering.API)中是明确分离的。

解决方案浏览器 [Ordering.API]:

命令基本上都是只读的数据传输对象(DTO),包含执行操作所需的所有数据。

CreateOrderCommand:

每个命令都有一个特定的命令处理程序,该处理程序负责执行为该命令准备的操作。

CreateOrderCommandHandler:

在这种情况下:

  1. 创建一个 Order 对象(聚合根)
  2. 使用聚合根方法添加订单项
  3. 通过存储库添加订单
  4. 保存订单

另一方面,查询只返回 UI 需要的内容,可以是领域对象或特定 DTO 的集合。

IOrderQueries:

它们被实现为普通的 SQL 查询,在本例中使用Dapper

OrderQueries:

甚至可以使用特定的视图模型或 DTO 来获取查询结果。

OrderViewModel:

DDD

DDD 模式可以在领域层中查看 (Ordering.Domain)

解决访问浏览器 [Ordering.Domain + Ordering.Infrastructure]:

在这里,你可以看到 Buyer(买方)聚合和 Order(订单)聚合,以及 Ordering.Infrastructure 中的仓储实现。

应用层的命令处理程序通过依赖注入,使用领域层的聚合根和基础设施层的仓储来实现处理逻辑。

附加资源