[英]Storing and updating read model in a CQRS + ES system
背景
我有一个使用CQRS + ES的系统,并且在该系统中,聚集了诸如博客文章或问题之类的聚合,这些聚合保留在事件存储中,并将事件发送到查询端,以通过投影保留读取模型。
在创建问题或帖子的情况下,这很简单
如果对问题进行了更改,并且在写端引发了一个适当的事件(例如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.