问题标签 [command-query-separation]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
3 回答
764 浏览

c# - 单个函数类(命名为动词)

我正在尝试一种新的代码结构,我将我所有的大型存储库和工厂拆分为大量较小的类,每个类都有一个单一的职责。最重要的是,我使用动词作为类名,因为我认为这是准确描述每个类的含义的最佳方式。

每个类只有一个公共方法(称为“Execute”),但通常有私有方法,有时还有一个带参数的构造函数。

例子

前:

后:

这种结构的一个好处是我更愿意将公共方法的功能拆分为多个私有方法(更易于阅读和管理)。在此之前会增加存储库中的混乱,但现在私有方法包含在它们单独的类中。

我一直读到类应该有名词作为名称,但是当一个类只有一个用途时,最好用它的作用来命名它。

问题

这是一个坏主意(分离和命名)?如果是这样,创建这种分离并避免大类的更好方法是什么?

编辑:应该注意的是,我从命令查询的角度得出了这些(奇怪的)想法。因此,将其与存储库进行比较也许最有意义。

0 投票
3 回答
1786 浏览

cqrs - 在 api 平台中实现事件溯源/CQRS 方法

在官方 Api-Platform 网站上有一个通用设计注意事项页面。

最后但同样重要的是,要创建基于事件溯源的系统,一种方便的方法是:

  • 使用自定义数据持久化器将数据持久化到事件存储中
  • 在标准 RDBMS(Postgres、MariaDB...)表或视图中创建投影
  • 用只读的 Doctrine 实体类映射这些投影,并用 @ApiResource 标记这些类

然后,您可以从 API 平台提供的内置 Doctrine 过滤器、排序、分页、自动连接等中受益。

因此,我尝试通过一种简化来实现这种方法(使用一个 DB,但读取和写入是分开的)。

但是失败了...有一个问题,我不知道如何解决,所以请您帮忙!

我创建了一个UserDoctrine 实体和我想用@Serializer\Groups({"Read"}). 我将在此处省略它,因为它非常通用。

User用于 api 平台的 yaml 格式的资源:

因此,如上所示,UserDoctrine 实体是只读的,因为只GET定义了方法。

然后我创建了一个CreateUserDTO:

CreateUser用于 api 平台的 yaml 格式的资源:

因此,在这里您可以看到只POST定义了一种方法,正是用于创建新用户。

路由器显示的内容如下:

我还添加了一个自定义来DataPersister处理. 在我使用 Doctrine 实体来写入数据,但对于这种情况,这并不重要,因为 Api 平台不知道 DataPersister 将如何写入它。因此,从概念上讲 - 它是读取和写入的分离。POST/usersCreateUserDataPersister::persist

读取由 DoctrineDataProvider附带的 Api 平台执行,写入由 custom 执行DataPersister

当我执行创建新用户的请求时:

问题! 我收到400回复... "hydra:description": "No item route associated with the type "App\Dto\User\CreateUser"." ...

但是,一条新记录被添加到数据库中,因此自定义 DataPersister 有效;)

根据一般设计考虑,实现了写入和读取的分离,但没有按预期工作。

我很确定,我可能会遗漏一些需要配置或实现的东西。所以,这就是它不起作用的原因。

很乐意得到任何帮助!

更新 1:

问题出在\ApiPlatform\Core\Bridge\Symfony\Routing\RouteNameResolver::getRouteName(). 在第 48-59 行,它遍历所有路线,试图找到合适的路线:

  • $operationType = 'item'
  • $resourceClass = 'App\Dto\User\CreateUser'

但是只$operationType = 'item'定义 $resourceClass = 'App\Entity\User\User',所以找不到路由并抛出异常。

更新 2:

所以,这个问题听起来像这样:

如何使用 Doctrine 实体进行读取和 DTO 进行写入来实现读取和写入的分离(CQS?),两者都驻留在同一条路线上,但使用不同的方法?

更新 3:

数据持久化

  • 将数据存储到其他持久层(ElasticSearch、MongoDB、外部 Web 服务...)
  • 不通过API公开暴露与数据库映射的内部模型
  • 通过实现 CQRS 等模式,为读取操作和更新使用单独的模型

是的!我想要那个......但是如何在我的例子中实现它?

0 投票
2 回答
176 浏览

asp.net-core-webapi - 对于以下要点,开发 .net core 2.2 web api 有什么建议?

我正在使用.NetCore2.2Autofac4Dapper开发新的 WebApi 。很少有非常基本的问题,因为这是我的第一个 WebApi 项目。作为这个项目的一部分,我必须编写单元测试和集成测试。

我的问题如下(示例代码如下):

  1. “ Task< IActionResult > ”和“ Task<IEnumerable> ”之间推荐的返回类型是什么?

  2. 推荐对象 我的项目的启动类中的依赖项范围?

  3. 对于这个给定的项目结构,我真的需要 UnitOfWork 吗?

  4. 如果我按照这个设计有什么缺陷?

  5. 有没有更好的方法来设计这个 API?

  6. 作为 TDD,我是否还需要为 API 层(控制器)和基础设施层或 Doman 层(它没有任何逻辑)编写测试用例?

  7. 我必须在控制器单元测试中包含哪些场景?

领域层:

基础设施层:

API层:

启动.cs:

0 投票
1 回答
44 浏览

c# - 命令查询分离 - 返回值的异步命令

我在一个项目中采用了命令查询分离原则。

但是,我并没有严格遵守它,因为我们需要命令来返回值。

许多人参考这篇文章,这是对这个概念的一个很好的解释:

但是,这里的一个声明无法解释:

https://blogs.cuttingedge.it/steven/posts/2012/returning-data-from-command-handlers/

“...从命令返回值确实意味着命令永远不能异步执行”

谁能详细说明这一点?

为什么从 Command 返回值意味着它们不能再异步执行?

0 投票
1 回答
926 浏览

design-patterns - 如何从现有的写入数据库生成 CQRS 中的读取数据?

目前我们有一个 Asp.net 应用程序,它使用 SQL 服务器进行写入和读取查询,就像一个普通的单体应用程序一样。

现在我们要转移到 CQRS。

在 CQRS 中,读取模型是基于事件生成的。

但是对于我的应用程序之前的事务数据,我们没有任何事件或日志。

那么我们如何从我们现有的 SQL Server 数据库的数据中生成 NoSql 数据库中的读取模型。

0 投票
2 回答
625 浏览

design-patterns - 如何在 CQRS 模式中更新写入模型数据库的模式更改中的读取模型?

在使用带有域事件的 CQRS 模式来生成读取模型时。

如果我们使用一些默认数据在数据库中添加新列或直接从 sql 查询手动插入新行,在这种情况下不会生成任何事件,那么如何更新现有生成的读取模型?

0 投票
1 回答
175 浏览

domain-driven-design - CQRS 和工作单元 - 一个命令用于所有更改,还是多个命令 + 一个保存命令?

在显示多个订单明细行的屏幕中,用户可以添加、更新或删除行或列,然后单击“保存”按钮将所有订单更改保存在一个事务中。

选项 1:创建一个命令(将由Clicking按钮的事件创建),说UpdateOrderCommand,它具有用于所有更改的复杂内部数据结构。该命令会将更改应用到数据库表。(因此 UI 部分代码将需要跟踪命令的所有更改。)

选项 2:创建AddOrderLineCommandDeleteOrderLineCommandUpdateOrderLineCommandSaveOrderCommand。UI 上的每个操作都会创建一个请求,并且“保存”按钮将调用SaveOrderCommand. 但是,它需要一些有状态的服务来保存所有未保存的更改。

哪一种是 CQRS 惯用的方法?

0 投票
1 回答
28 浏览

cqrs - 在 CQ(R)S 中,可以使用 Command 作为模型构造函数的参数吗?

假设我有一个CreateUser命令:

如果我的User模型接受这个命令作为构造函数参数可以吗?

即而不是这样:

并让命令处理程序将命令数据映射到模型,我可以简单地让模型构造函数接受命令作为参数并提取他们需要的数据:

这是一种正确的方法,还是有缺点?

0 投票
1 回答
173 浏览

architecture - Vertical Slice Architecture - Controller、Command/Query、Response、CommandHandler 中应该包含哪些内容?

经过一番思考和考虑,我决定将我现有的应用程序目录结构重组为垂直切片方法,该应用程序当前是水平切片的(分层)。

为了匹配所需的结构,我在这个问题中更改了我的项目文件以匹配下面的链接示例并使事情变得清晰。

因此,经过一些研究,我得出的结论是,如果我使用 Vertical Slices 对我的应用程序结构进行建模并找到一个清晰的示例,事情会变得更容易。

带洋葱,带垂直切片

我面临的问题是我将什么委托给这四个文件中的每一个。

我的大致理解如下。

控制器 - 处理请求并调用命令/查询,还是这个 CommandHandler?

命令/查询 - 这有插入/更新命令,或数据库查询,在我的情况下,这将通过像 Doctrine 这样的对象关系映射框架来促进

响应 - 将所需信息或命令状态结果以 JSON 形式返回给用户

CommandHandler - 不清楚这里有什么......

寻找一些示例片段,或一些澄清开始。描述四个组件中的每一个的功能会有所帮助。

0 投票
1 回答
72 浏览

domain-driven-design - CQS:谁负责数据缓存,何时负责?

何时以及由谁负责在基于 CQS 的用例的 DDD 架构中将来自 API GET 请求的数据缓存到本地数据存储中?


首先想到的是:

启动查询以从本地数据存储中获取一些数据,如果为空,则从 API 获取所需数据 -> 将其缓存到本地数据存储中 -> 将其返回

该解决方案似乎没有正确遵循 CQS,因为查询不应该改变数据存储(或者它们可以吗?)。


想到的第二件事:

执行命令以从 API 获取新数据 -> 更新数据存储 -> 引发数据更新事件 -> 事件处理程序侦听数据更新事件并执行新查询以获取新数据


第二种解决方案似乎更好地遵循 CQS 模式,但我不确定这些解决方案中的任何一个是否是在基于 CQS 的架构中处理数据缓存的正确方法。