在 DDD/CQRS 中,ReadModel 是否应该充当 ViewModel,如果不是,那么映射的责任在哪里?

2024-03-03

假设读取模型ProductCatalogueItem由聚合/写入模型构建,与写入模型分开存储,并包含每个可供销售的产品,并具有以下属性:

  • basics: product_code, name, price, number_of_available_stock,
  • 文档:short_description, description,...
  • 产品特点:weight, length, depth, width, color,...

并且,有两种观点:

  • 产品列表包含可用产品报价的列表/表格/网格,并且视图仅需要以下基本属性:product_code, name, price, number_of_available_stock,
  • 显示所有属性的产品详细信息 - 基础知识、文档、产品特性。

自然地,想到了两个 ViewModel:

  • ProductCatalogueListItem仅包含基本属性,
  • ProductCatalogueItemDetails包含所有属性。

现在,..有两个选择(我可以看到)。


  1. ViewModel 是 ReadModel 的 1:1 表示

因此,这是两种读取模型,而不是一种,ProductCatalogueListItem and ProductCatalogueItemDetails。并且,读取服务将有两种方法:

  • List<ProductCatalogueListItem> searchProducts(FilteringOptions),
  • ProductCatalogueItemDetails getProductDetails(product_code).

并且,控制器直接返回这些模型(或者映射到传输层的 dto)。

这里的问题是过滤,.. 读取服务是否应该在不同的读取模型上执行搜索查询,而不是从方法调用返回的模型?因为,ProductCatalogueListItem 没有足够的信息来执行过滤。


  1. ViewModels 是 ReadModels 的另一个项目

读取服务有两种方法:

  • List<ProductCatalogueItem> searchProducts(FilteringOptions),
  • ProductCatalogueItem getProduct(product_code).

并且,从 ReadModels 到 ViewModels 的映射是由上层(可能是控制器)完成的。

过滤没有问题,...但是,还有另一个问题,即离开域层的数据多于实际需要的数据。而且,控制器会随着更多的逻辑而增长。由于不同的传输技术可能有不同的控制器,因此映射代码可能会在这些控制器中重复。


根据 DDD/CQRS 或完全不同的方式,哪种组织职责的方法是正确的?

重点是:

  • 我应该构建两个读取模型,并使用其中一个进行搜索,然后返回另一个吗?
  • 我应该构建使用的单一读取模型,然后映射到有限视图以仅包含视图的基本信息吗?

首先,你的断言是错误的:

...读取模型 ProductCatalogueItem 是从聚合/写入模型构建的...

读取模型不知道聚合或任何有关写入模型的信息,您直接从数据库构建读取模型,返回 UI 所需的数据。

因此,视图模型是读取模型,它不涉及写入模型。这就是 CQRS 存在的原因:使用不同的模型(读取模型)来优化查询以返回客户端所需的数据。

Update

我会尽力更好地解释自己:

CQRS 只是根据方法类型将一个对象分成两个。有两种方法类型:命令(任何改变状态的方法)和查询(任何返回值的方法)。就这样。

当您将此模式应用于应用程序的服务边界时,您将拥有写入服务和读取服务,因此您可以以不同的方式扩展命令和查询处理,并且还可以拥有两种模型。

但 CQRS 没有两个数据库,不是消息传递,不是最终一致性,不是从写入模型更新读取模型,不是事件源。您可以在没有它们的情况下执行 CQRS。我这样说是因为我发现你的断言中有一些误解。

也就是说,读取模型的设计是根据用户希望在 UI 中看到什么信息来完成的,即读取模型是视图模型,它们之间没有映射,它们都是相同的模型。您可以在下面的参考文献(3)和(6)中阅读相关内容。我认为这回答了你的整个问题。我不明白的是过滤问题。

一些很好的参考

(1) http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-commerce-agh/ http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/

(2) http://www.cqrs.nu/Faq/command-query-responsibility-segregation http://www.cqrs.nu/Faq/command-query-responsibility-segregation

(3) 《实现领域驱动设计》一书,作者:Vaughn Vernon。第 4 章:架构,“命令查询职责分离,或 CQRS”部分

(4) https://kalele.io/really-simple-cqrs/ https://kalele.io/really-simple-cqrs/

(5) https://martinfowler.com/bliki/CQRS.html https://martinfowler.com/bliki/CQRS.html

(6) http://udidahan.com/2009/12/09/clarified-cqrs/ http://udidahan.com/2009/12/09/clarified-cqrs/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 DDD/CQRS 中,ReadModel 是否应该充当 ViewModel,如果不是,那么映射的责任在哪里? 的相关文章

  • 使用领域驱动设计的node.js

    我正在将应用程序从 C 迁移到 Node js 我一边学习一边学习node js 所以我是一个node js 新手 我正在阅读 领域驱动设计的模式 原则和实践 一书 发现我当前的项目可以从中受益的很多重要信息 例如 书中有一个示例电子商务应
  • 为什么域模型不应该用作 REST API 中的资源?

    我遇到过这样一种说法 按照 DDD 设计的领域模型不应该用作 REST API 中的资源 source https www thoughtworks com insights blog rest api design resource mo
  • 领域驱动设计中的 WCF 序列化和值对象模式

    Eric Evans 所著的 领域驱动设计 一书描述了称为值对象的模式 值对象的重要特征之一是它是不可变的 作为一个例子 我有一个值对象 Clinic 其中must有名字和id 为了使其成为值对象 我不提供名称和 ID 的设置器 另外 为了
  • 什么属于聚合根

    这是一个实用的领域驱动设计问题 从概念上讲 我认为我得到了聚合根 直到我去定义一个聚合根 我有一个 Employee 实体 它已作为聚合根出现 在商业领域 some员工可以记录与工作相关的违规行为 员工 违规行为 由于并非所有员工都受到此限
  • 领域驱动设计和安全

    这与此相关question https stackoverflow com questions 3006808 security implementation in domain driven design这似乎是不久前问过的 项目中的安全
  • 通过 MediatR PipelineBehavior 进行单元测试验证

    我正在使用 FluentValidation 和 MediatR PipelineBehavior 来验证 CQRS 请求 我应该如何在单元测试中测试这种行为 Use the 测试扩展 https docs fluentvalidation
  • 如何在领域层使用工作单元

    我正在尝试在 我的服务 类中使用工作单元模式 我有我的 CompanyService 课程 public class CompanyService ICompanyService private readonly ICompanyRepos
  • 领域驱动设计和聚合参考

    我正在设计领域模型 但有些东西似乎不太好 我从一个主要的聚合开始 它引用了其他聚合 而其他聚合也引用了更多聚合 我可以从主聚合开始遍历孔域模型 我看到的问题是我将在内存中保存聚合的所有实例 这是一个好的设计吗 我可以通过延迟加载解决内存问题
  • DDD和应用层

    我在DDD中添加 Stateful Stateless WebService等是应用层 应用服务 吗 从下面的链接来看 这似乎是正确的 第二个问题 我创建了一个存储库类 所有涉及存储库的方法调用都应该包装在应用程序服务中吗 或者我可以直接在
  • 实现领域驱动设计的函数式方法

    我在使用 C 编写领域驱动应用程序方面拥有丰富的经验 我编写的应用程序越多 我就越发现我想要采用一种不太适合标准 C OO 技术的方法 我想编写尽可能多的纯函数 因为它们真的很容易测试 我想以更具声明性的方式编写我的业务逻辑 所以我一直在研
  • 有界上下文、子域和通用语言

    a 对于包含两个或多个子域的 BC 存在概念重叠的可能性 甚至更糟糕的是 相同的概念 由其中几个子域使用 可能会被每个子域以不同的方式解释 理解 无论如何 如果 BC 确实包含许多子域 它是否应该提供几种通用语言 每个子域一种 或者所有子域
  • 事件源和 SQL Server 多个关系表

    我们使用 SQL Server 2016 的事件源 我们有完整的客户产品应用程序 每个应用程序都标记为CustomerId并在事件商店中获取单个指南行项目 这是写入事件存储指南的主要标识符 产品应用程序附带许多不同的关系事物 没有引导 但有
  • 使用流程管理器(又名 saga)在同一有界上下文中跨聚合根实现最终一致性

    假设您的有界上下文中有两个聚合 它们之间存在一些约束 使用 DDD 这些内部聚合约束不能在同一事务中强制执行 即聚合边界是事务边界 您是否会考虑使用 Microsoft CQRS 旅程中所谓的 流程管理器 来协调同一有界上下文中的两个聚合
  • DDD 聚合和值对象

    我想问一下关于DDD功能的问题 假设我们有两个聚合 每个聚合都包含值对象地址 根据 Eric Evans DDD 我们应该将聚合彼此隔离 因此第一个聚合的聚合根不能有指向 Address 的链接 坦白说 这对我来说似乎没有意义 所以问题是如
  • 身份验证和用户任务

    我正在考虑开发一个具有明确定义域的系统 主要基于网络 域的一部分包括像这样的实体Diary Booking Customer etc 不过我创建了另一个名为User其目的仅用于身份验证和授权 污染Customer具有特定于身份验证的数据的实
  • 寻找领域事件的例子

    有谁知道在哪里可以找到域事件实现的示例代码 如乌迪 达汉 http www udidahan com in 领域事件 救赎 http www udidahan com 2009 06 14 domain events salvation 在
  • 如何使用 Spring Crud/Jpa Repository 实现 DDD

    我想通过使用 Spring 实现 DDD 来创建一个应用程序 假设我有一个业务实体 Customer 和一个接口 CustomerRepository 由于春天提供了CrudRepository and JpaRepository默认情况下
  • 领域驱动设计和工厂类的作用

    我不清楚工厂类的角色和职责是什么 我知道工厂类应该负责创建域对象 聚合根 及其关联的实体和值对象 但我不清楚 DDD 架构的工厂 层 在哪里 工厂应该直接调用存储库来获取其数据还是服务库 工厂在以下框架中的位置 UI gt 应用程序 gt
  • ASP.NET Web Api 的事件发布者

    我已经开始使用微服务 我需要创建一个事件发布机制 我计划使用 Amazon SQS 这个想法很简单 我将事件存储在与聚合相同的事务中的数据库中 如果用户更改他的电子邮件 事件UserChangedEmail将被存储在数据库中 我还有事件处理
  • 使用实体框架时是否应该使用部分类作为业务层?

    我正在开发一个使用实体框架的项目 使用EF生成的类的部分类作为业务层可以吗 我开始认为这就是 EF 的用途 我尝试使用 DTO 模式 很快意识到我只是创建了一堆映射类 这重复了我的工作 而且还导致更多的维护工作和额外的层 我想使用自我跟踪实

随机推荐

  • 谷歌地图 myoptions 不起作用

    我正在尝试自定义马萨诸塞州地图 以显示 10 个区 我已将链接添加到在 我的地点 中创建的地图 但无法使地图居中 缩放或标题 中心 LatLng 是伍斯特 没有任何效果 帮助 Thanks
  • 如何查看 PHP SOAP 客户端类生成的实际 XML?

    考虑以下 SOAP 客户端脚本示例 SOAP new SoapClient WDSL Create a SOAP Client from a WSDL Build an array of data to send in the reques
  • Ionic 3 Native:文件:{代码:5,消息:“ENCODING_ERR”}

    我正在使用文件 API 插件中的 checkFile 函数 https ionicframework com docs native file checkFile在 Ionic 3 中检查文件是否存在于本地 Promise 被拒绝并出现以下
  • 如何以安全的方式为 HTTPS 配置 OpenSSL?

    每个月 网络上都会有一些文章介绍某些应用程序或平台在 SSL 实施中使用过时的加密配置 这让我担心 我自己的实现怎么样 当我在应用程序中使用 OpenSSL 来提供和 或使用 HTTPS 时 我到底应该做什么才能以最安全的方式配置 Open
  • Heroku 上的 ffmpeg:无法识别的选项“预设”

    我在本地 Rails 应用程序中使用 ffmpeg 版本 1 2 4 来转换视频文件 当我在本地运行应用程序时 一切都按预期工作 当我部署到heroku时 我添加了ffmpeg的构建包 https github com shunjikoni
  • 反序列化 JSON 日期(无时区)

    从昨天开始 我遇到了一个让我头疼的问题 不知道如何处理 我的数据库中有一个日期字段 其中包含以下值 然后我的应用程序获取该值并将其发送到我的网络表单 价值仍然相同 没关系 在客户端 我使用 javascript 警报进行中断 以查看来自 J
  • 从 tkinter 中的文本小部件复制格式化文本

    我正在使用 tkinter 在 Python 中开发 APA 引文制作器 我使用文本小部件在生成引文后显示引文 但每当我复制文本 目前使用 ctrl c 快捷方式 时 它都会丢失其格式 是否有某种方法可以从文本小部件复制格式化文本 例如斜体
  • 在 Gallery 中嵌入 ListView

    目标是实现一个 Gallery 其适配器返回 ListView 换句话说 嵌入水平滚动 Gallery 中的垂直滚动 ListView 经过一些工作后它就可以工作了 但是当尝试水平滚动时 ListView 看起来非常不稳定 就像居中时有一些
  • 更智能的“ff-find-other-file”

    我正在开发一个项目 其中源代码组织在以下目录结构中 source include source include analysis source include tools source include utils source includ
  • 如何在 Google App Engine Java 应用程序的模块之间共享会话?

    当我通过以下方式在会话中存储某些内容时HttpSession在模块A中 HttpSession session req getSession true session setAttribute username Eng Fouad 然后我尝
  • 需要帮助找到正确的 T-SQL 查询

    我不太确定该怎么做 基本上我有一张这样的桌子 UserId DateRequested Approved ApprovedBy Notes 1 2011 05 26 0 NULL NULL 1 2011 05 27 0 NULL NULL
  • 如何使用键绑定使矩形在屏幕上移动?

    我试图创建的游戏是贪吃蛇 到目前为止我已经弄清楚如何使用paint Graphics g 一点JPanel 鼠标侦听器 现在我正在尝试创建一个将在屏幕上移动并使用键绑定或键侦听器的矩形 但我不知道应该如何处理此问题 这是到目前为止我的代码
  • Rust 如何在运行时存储类型?

    A u32占用4字节内存 String在堆栈上占用 3 个指针大小的整数 用于位置 大小和保留空间 再加上堆上的一些数量 对我来说 这意味着 Rust 不知道当代码执行时 什么类型存储在特定位置 因为这些知识需要更多内存 但与此同时 它是否
  • 一类 SVM libSVM

    假设我的特征向量是 x1 x2 xn 谁能给我一个使用 libSVM 训练一类 SVM 的代码 我应该如何使用交叉验证来学习参数 这可能对你有帮助 label ones Number Of your training instances 1
  • 使用 JavaScript 将对象的特定属性合并在一起

    所以我有一个像这样的对象数组 name Joe Smith job Custodian age 35 id 3421 name George Henderson job CEO age 43 id 5098 name Joe Smith j
  • IE中Json响应下载(7~10)

    我正在尝试上传文件并返回有关文件属性 名称 大小等 的 json 响应 除了 IE 之外 它在所有浏览器中都可以正常工作 IE 尝试将 JSON 作为文件下载 我有 IE10 并通过从调试器更改浏览器模式和文档模式在 IE7 到 10 上进
  • 在 Windows 上使用 Perl,如何确保在 chdir 之后获得正确大小写的路径?

    考虑以下代码 print cwd n str source note the lower case s chdir str print cwd n 如果我当前的目录是c parentdir Source 注意大写 S 其输出将是 c par
  • React Native 发送消息到特定的 Whatsapp 号码

    我正在尝试从反应本机应用程序向 WhatsApp 联系人发送短信 我发现我可以通过链接来做到这一点 Linking openURL whatsapp send text hello 上面的代码仅打开什么应用程序 我需要打开与特定号码的聊天是
  • 如何使用内联 JavaScript 或 CSS 隐藏 TD 标签?

    我怎样才能隐藏一个 td 使用 JavaScript 或内联 CSS 标记 hide visibility hidden td class hide td Edit 只为你 显示和可见性的区别就在于此 展示 具有许多属性或值 但您关注的是
  • 在 DDD/CQRS 中,ReadModel 是否应该充当 ViewModel,如果不是,那么映射的责任在哪里?

    假设读取模型ProductCatalogueItem由聚合 写入模型构建 与写入模型分开存储 并包含每个可供销售的产品 并具有以下属性 basics product code name price number of available s