简化的 CQRS 和 DDD - zilor-net/eShopOnContainers-CN-Wiki GitHub Wiki
本页面探索了一些在 eShopOnContainers 中使用简化的 CQRS 和 DDD 方法相关的代码细节。
概念总览
CQRS 是一种用于命令和查询责任隔离的模式,用非常简单的术语来说,它有两种不同的方法来处理应用程序模型。
命令负责更改应用状态,即创建、更新和删除实体(数据)。
查询负责读取应用程序状态,例如显示信息给用户。
命令与领域规则、限制和事务边界有关。
查询与表示层、客户端 UI有关。
当处理命令时,应用模型通常用 DDD 结构来表示,例如 聚合根、实体、值对象等,并且通常有一些规则来限制允许的状态变化,例如在配送之前必须支付订单。
当处理查询时,应用程序模型通常由实体和关系表示,可以像SQL查询一样读取并显示信息。
查询不会改变状态,所以它们可以根据需要运行,并且总是返回相同的值(只要应用程序状态没有改变),也就是说查询是“幂等的”。
为什么要分离?因为修改模型的规则可能会对读取模型施加不必要的约束,例如,你可能只想让订单项在配送之前才能更改,这样订单就像看门人(根聚合)一样访问订单项,但你可能还想查看某些商品项的所有订单,因此,因此,你必须能够首先访问订单项(以只读方式)。
在这个简化的 CQRS 方法中,DDD 模型和查询模型都使用同一个数据库。
命令和查询位于应用层,原因如下:
- 它是领域聚合根聚集的地方(命令)
- 它接近 UI 需求,并且可以访问微服务的整个数据库(查询)。
理想情况下,聚合根彼此不知到对方,应用层的职责是通过领域事件组合协调操作,因为它知道所有的聚合根。
关于查询,也是同样的分析,除了聚合根的限制外,应用层知道数据库中的所有实体和关系。
代码细节
CQRS
可以在购物服务中查看 CQRS 模式:
Commands and queries are clearly separated in the application layer (Ordering.API).
命令和查询在应用层(Ordering.API)中是明确分离的。
解决方案浏览器 [Ordering.API]:
命令基本上都是只读的数据传输对象(DTO),包含执行操作所需的所有数据。
CreateOrderCommand:
每个命令都有一个特定的命令处理程序,该处理程序负责执行为该命令准备的操作。
CreateOrderCommandHandler:
在这种情况下:
- 创建一个 Order 对象(聚合根)
- 使用聚合根方法添加订单项
- 通过存储库添加订单
- 保存订单
另一方面,查询只返回 UI 需要的内容,可以是领域对象或特定 DTO 的集合。
IOrderQueries:
它们被实现为普通的 SQL 查询,在本例中使用Dapper。
OrderQueries:
甚至可以使用特定的视图模型或 DTO 来获取查询结果。
OrderViewModel:
DDD
DDD 模式可以在领域层中查看 (Ordering.Domain)
解决访问浏览器 [Ordering.Domain + Ordering.Infrastructure]:
在这里,你可以看到 Buyer(买方)聚合和 Order(订单)聚合,以及 Ordering.Infrastructure 中的仓储实现。
应用层的命令处理程序通过依赖注入,使用领域层的聚合根和基础设施层的仓储来实现处理逻辑。