2013-10-18 21 views
0

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

我有一个使用CQRS + ES在这个系统中有骨料,比如那些在事件持续的博客文章或问题的系统存储事件并将其发送到查询端以通过预测持续读取模型。

在一个问题的情况下,或交的创建是一个相当简单的

  • 客户创建命令来创建一个新的问题
  • 的命令处理程序创建一个新的问题在事件存储中汇总并保存更改
  • 当聚合应用更改时,它会触发IssueCreatedEvent或类似的操作
  • r EAD方将侦听此,并创建一个问题模型的,那就是了(如切开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或其他东西。这样,当对评论进行更改时,我仍然可以提取一条记录来加载问题,对评论进行适当更改(例如更新现有评论,添加新评论或删除评论)并重新保存记录。从阅读角度看,整个问题仍然可以一次性检索。

我用这种方法看到的问题是,如果用户更改其个人资料图片或个人资料名称,例如,我将不得不加载每一个问题和/或帖子,加载注释并进行适当的更改评论信息。

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

回答

0

问题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" | 

您可以获取和设置单独的任何意见在卡桑德拉,如果我没有记错的结构。在这种情况下,您可以更新任何一条评论。或者您可以获取评论栏以检索所有评论。

+0

Question1)谢谢。这就是我所倾向的。 由于我的问题的大部分是2左右,你能否详细阐述/扩展你的答案? 不太清楚你的意思是列家庭数据库,是评论专栏只是一个序列化的ids集合,整个评论?我不知道这是如何解决我有关更新评论,评论作者信息等问题。我并不想将自己绑定到特定的持久性框架和/或API,如果可能的话。 谢谢。 –

+0

@JoshuaHayes对不起,我没有让自己明白,我不是这方面的专家。请参阅我的更新。 – Hippoom

+0

嗨Hippoom。 我会看看Casandra,但我真的希望找到一个更一般的解决方案来存储和更新读取模型中的非规范化数据,而不是像使用Casandra这样的其他框架。我欣赏这个建议。 –

2

我是有点晚但在党,这是我需要大约否2.

存储读取模型的最好方法就是在某种程度上,它是很容易查询。文档db可以是一个很好的技术解决方案,但它也可以与rdbms一起使用,前提是您已定义了相关的读取模型模式。

您可以将所有评论与帖子一起存储,但事实并非总是如此,因为高流量网站正在通过ajax单独加载评论。所以它实际上取决于读取的模型用例。

+0

好的结论“存储读取模型的最佳方式是以一种非常容易查询的方式”。 – Hippoom

+0

我同意MikeSW,保持简单和可用。无论如何,阅读模型是'一次性英雄',必须符合你的要求。 –

-1

问题1: 您无法处理聚合根中的事件。打破DDD原则是一个坏主意。如果评论存在于不同的聚合中,则问题聚合中的任何后果必须最终由域中的某种流程管理器,域服务或Saga处理。

如果可能在你的域名中,你必须说明问题不知道评论(我猜这是一种自然的思维方式),所以你不应该保留任何这样的参考。

另一种方式的评论可以保留对它们相关问题的参考。

问题2:你为什么不把你需要的所有字段放在你的评论表中(处理问题/文章更新)?当您查询您的读取模型时,您可以免费加入这两个表格。

+1

“*你不能在你的AR中处理事件,这是违反DDD原则的坏主意*” - 只是为了澄清,我认为你的意思是它无法处理*另一个AR的事件?如果AR不能处理它自己的事件,那么它如何更新它自己的状态? – James

+0

这就是主意! –