【问题标题】:How to implement CQS with in memory changes?如何通过内存更改实现 CQS?
【发布时间】:2009-09-25 11:57:50
【问题描述】:

在 DDD 上观看了 Greg Yound 的此视频

http://www.infoq.com/interviews/greg-young-ddd

我想知道当内存发生变化时,如何使用 DDD 实现命令-查询分离 (CQS)?

使用 CQS,您有两个存储库,一个用于命令,一个用于查询。 以及两个对象组,命令对象和查询对象。 命令对象只有方法,没有可以暴露对象形状的属性,不能用于在屏幕上显示数据。 另一方面,查询对象用于向屏幕显示数据。

在视频中,命令总是进入数据库,因此您可以使用查询存储库来获取更新的数据并重新显示在屏幕上。

您能否在 ASP.NET 中将 CQS 与类似和编辑屏幕一起使用,其中在内存中进行更改并且屏幕需要在更改持久化到数据库之前多次更新更改?

例如

  1. 我从查询存储库中获取一个查询对象并将其显示在屏幕上
  2. 我点击编辑
  3. 我从查询对象存储库中重新获取查询对象,并以编辑模式将其显示在表单上
  4. 我更改了表单上的一个值,它会自动回发并获取命令对象并发出相关命令
  5. 做什么:我现在需要显示更新的对象,因为命令对计算字段进行了更改。由于命令对象尚未保存到数据库中,我无法使用查询存储库。而对于 CQS,我并不是要公开命令对象的形状以显示在屏幕上。您将如何获取带有更新更改的查询对象以显示在屏幕上。

我能想到的几个可能的解决方案是拥有一个会话存储库,或者一种从命令对象获取查询对象的方法。 还是CQS不适用于这种场景?

在我看来,视频中的更改会直接保存到数据库中,而且我还没有找到一个使用 CQS 的 DDD 示例来解决对域对象进行批量更改并更新已修改视图的问题域对象,然后最终发出命令以保存域对象。

【问题讨论】:

    标签: domain-driven-design repository-pattern cqrs


    【解决方案1】:

    所以听起来你想要的是一个更精细的命令。

    EG:用户与网页交互(比如说用购物车结账)。

    获取信息的多个页面正在构建一个命令。在用户实际上检查所有信息在单个命令中发送到域的位置之前,该命令不会被发送,我们称之为“CheckOut”命令。

    表示模型对于抽象这种类型的交互很有帮助。

    希望这会有所帮助。

    格雷格

    【讨论】:

    • 嗨,格雷格,你有这方面的例子吗?目前,我已经走下获取查询对象的路线,并将其放入“购物车”对象中,该对象序列化查询对象以允许在回发之间进行更改(也可以使用会话)。一旦对象完成更新,它就会被传递给命令对象。如果我有更多时间,那么可以使用与查询对象不同的对象来将这些存储在编辑更改中,例如演示模型。我使用相同的对象来显示和编辑,这与您提出的演示模型相同吗?谢谢
    【解决方案2】:

    如果您真的想为此使用 CQS,我会说 Query repo 和 Write repo 都引用了同一个后备存储。通常此引用是通过外部数据库进行的 - 但在您的情况下,它可能是 List 或类似的。

    【讨论】:

    • 感谢您的回复。我想知道当更改在内存中而不是直接保存到数据库时使用 CQS 的设计有多普遍/好?这基本上是我们想出的是使用会话存储库来允许查询存储库通过会话变量访问命令数据。以后可能需要 HttpContext 存储库。有没有人见过这个实现?想法表示赞赏。
    • 在我看来,你用来操作数据源的方法不应该依赖于数据源的种类。存储库模式允许您将这些差异抽象出来,允许您将任何数据源视为可查询的对象集合。由各个存储库实现来确定目标数据源——所以理论上你会有一个“InMemoryRepository”和一个“DatabaseRepository”——或者你有什么。
    • 是的,我知道您可以将 InMemory 存储库换成 Database 存储库。 CQS 的部分价值在于您向数据库发出命令,并使用查询存储库单独拉回更新的数据。在内存中,命令对象处于会话状态,因此查询存储库只能拉回命令对象中的数据。使用数据库版本,查询对象可能与命令对象完全不同,只是看起来与内存 CQS 的关系更接近。想知道这如何与 CQS 试图实现的目标相吻合
    • 没有规定说您的查询存储库和命令存储库不能共享一个共同的后备存储。这就是您在使用数据库时所做的事情。就这种抽象而言,共享 List 与共享数据库连接几乎相同。
    【解决方案3】:

    也为您的其他顾虑...

    与 CQRS 相比,这些更关注最终的一致性。您不需要最终与 CQRS 保持一致,您可以使命令的处理也以一致的方式写入报告存储(或对两者使用相同的物理存储)。实际上,我建议人们将其作为他们的基础架构,然后在需要时引入最终的一致性,因为这会带来成本。

    【讨论】:

    • 不确定这是否适用于我的情况,到目前为止只有一个数据库,所以不必担心更新报告存储,并且命令对象使用 NHibernate,因此更改会保留回来到数据库。或者这是否适用于我的情况?不确定您指的是哪一个问题?
    【解决方案4】:

    在内存中,您通常会使用Observer design pattern

    实际上,您总是希望使用这种模式,但大多数数据库并没有提供一种有效的方式来在数据库中的某些内容发生变化时调用您的应用程序中的方法。

    【讨论】:

    • 不确定您是否收到我的问题。使用 CQS,您可以将读取与写入分开。查询存储库与写入存储库分开的位置。那么如果我不将域实体保存到存储库中,那么查询存储库如何获取数据呢?我是否需要一种方法从域对象中获取具有更新状态的查询对象,或者您是说查询对象会观察域对象并更新自身?或者可能引入一个会话存储库?
    【解决方案5】:

    Patterns of Enterprise Application Architecture 中的 Unit of Work 设计模式与 CQS 非常匹配 - 它基本上是一个将内容保存在数据库中的大命令。

    【讨论】:

    • 感谢您的链接,但仍然没有回答我的问题。基本上,对于 CQS,你有一个对象,它只有方法(命令),另一个对象包含对象的形状。有两个存储库,一个用于命令对象,一个用于查询对象。因此,您永远不会使用命令对象来重新填充屏幕,而是使用查询对象。在不将命令对象的更改保存到数据库的情况下,如何重新显示调用命令所做的更改?由于更改不在数据库中,因此您无法使用查询存储库。
    【解决方案6】:

    JdonFramework 是 CQRS DDD java 框架,它提供领域事件+异步模式,更多详情https://jdon.dev.java.net/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-19
      相关资源
      最近更新 更多