繁体   English   中英

在CQRS + ES系统中存储和更新读取模型

[英]Storing and updating read model in a CQRS + ES system

背景

我有一个使用CQRS + ES的系统,并且在该系统中,聚集了诸如博客文章或问题之类的聚合,这些聚合保留在事件存储中,并将事件发送到查询端,以通过投影保留读取模型。

在创建问题或帖子的情况下,这很简单

  • 客户端创建命令以创建新问题
  • 命令处理程序创建一个新的问题集合并将更改保存在事件存储中
  • 当聚合应用更改时,它将触发IssueCreatedEvent或类似事件
  • 读取端的投影将侦听此情况,并创建一个问题模型和所需的任何其他非规范化数据(例如用于查询所有问题列表的缩减版IssueListItem)

如果对问题进行了更改,并且在写端引发了一个适当的事件(例如IssueStatusChanged),并在读端进行了相应的处理。 加载读取侧的两个非规范化模型,以更新事件的状态并保存。 简单。

您如何处理诸如评论之类的关系?

我正在实施评论系统,用户可以在其中发布关于问题或博客文章的评论。 我的第一个想法是将这些注释添加到问题中,或者将其汇总发布到写端以保持一致性。 当我想到这一点时,我意识到这可能会引入很多不必要的并发问题,例如有人正在更新问题而其他人来了并发表了新评论。

这使我认为我应该将评论自身建模为自己的汇总根。 这样,发布到博客帖子或问题的评论将不会与问题本身发生冲突。

因此,假设我以这种方式将评论在写端建模为聚合,那么我有两个问题。

1)写侧的问题或后期汇总仍需要存储此关系吗? 评论汇总本身已经存储了带有ID参考的过账项目。

如果是这样,我正在考虑让该问题总计订阅创建评论的事件并添加其自己的引用。

public class Issue : AggregateRoot, IEventHandler<CommentCreatedEvent>
{
      private ICollection<Guid> _Comments;

      public void Handle(CommentCreatedEvent @event)
      {
         _Comments.Add(@event.AggregateId)
      }
}

因为注释已经存储了对其父级的引用,这是否足够? 在写入端并不需要这些数据,而在读取端则更重要,因为它是加载了所有注释的父级。

2)在读取方面,什么是存储此数据的最佳方法?

具体来说,为了使这些数据易于更新,我需要放入另一个表中进行评论,并将它们加入适当的帖子或问题中。 在完成评论后,我将实现一个跟踪系统,用户可以在其中跟踪项目以接收更新。 但是,走这条路会很快使我回到读取端的高度规范化架构,这违背了优化,非规范化读取模型的目的。

为此,我考虑将单个列添加到问题表,例如,将所有注释存储为序列化的JSON Clob或其他内容。 这样,当对注释进行更改时,我仍然可以拉出一条记录来加载问题,对注释进行适当的更改(例如更新现有注释,添加新注释或删除注释)并重新保存记录。 从阅读的角度来看,仍然可以一次性检索整个问题。

我看到的这种方法的问题是,例如,如果用户更改了个人资料图片或个人资料名称,我将必须加载每个问题和/或发布信息,加载评论并在评论信息中进行适当的更改。

我还想知道文档数据库(我在阅读方面一直在考虑的其他方式)如何解决更新嵌套数据的问题?

我参加聚会有点晚了,这是我的第二点。

存储读取模型的最佳方法是易于查询 文档db可能是一个很好的技术解决方案,但如果定义了相关的读取模型架构,它也可以与rdbms一起使用。

您可以将所有评论与帖子一起存储,但是并非总是如此,因为访问量高的站点通过ajax将评论与帖子分开加载。 因此,这实际上取决于读取模型的用例。

问题1:无需在Issue中建立关系。 这里没有特别的一致性要保护。

问题2:我最近正在阅读NoSQL提炼的内容。 像Casandra这样的Column-Family数据库似乎适合于注释。

Row | issueId | name                          | comments   |
    | 1       | comments persistence solution | {c1,c2,c3} | 

您可以使用Casandra api或Casandra查询语言来检索注释的子集或整个注释列。

UPDATE

注释列只是ID的序列化集合,是注释的全部内容吗? 没有注释存储为行中的列。 Casandra支持嵌套列。 所以评论栏可能有这样的结构

| other columns | comments                   |
|  ............ | c1   | c2           | c3   |
                | "+1" | "Nice one"   | "+1" |

如果我没有记错的话,您可以在Casandra中单独获得和设置任何评论。 在这种情况下,您可以更新任何一条评论。 或者,您可以获取评论列以检索所有评论。

问题1:您不会在聚合根目录中处理事件。 违反DDD原则是一个坏主意。 如果注释位于其他汇总中,则最终必须由您所在域中的某种流程管理器,域服务或Saga处理问题汇总中的任何后果。

如果可能的话,您必须声明“问题”对“评论”不了解(我想这是一种自然的思考方式),因此您不应保留任何此类引用。

使用其他方式的注释可以保留与它们相关的问题的参考。

问题2:为什么不在“注释”表中保留“发布/发布”所需的所有字段(处理“发布/发布”更新)? 当您查询读取模型时,这使您不必在这两个表之间联接。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM