Domain driven design 在CQRS+中存储和更新读取模型;ES系统
背景 我有一个使用CQRS+ES的系统,在这个系统中有一些聚合,例如博客文章或问题,它们被持久化在事件存储中,并将事件发送到查询端,以通过投影持久化读取模型 对于正在创建的问题或帖子,这是一个相当直截了当的过程Domain driven design 在CQRS+中存储和更新读取模型;ES系统,domain-driven-design,cqrs,event-sourcing,Domain Driven Design,Cqrs,Event Sourcing,背景 我有一个使用CQRS+ES的系统,在这个系统中有一些聚合,例如博客文章或问题,它们被持久化在事件存储中,并将事件发送到查询端,以通过投影持久化读取模型 对于正在创建的问题或帖子,这是一个相当直截了当的过程 客户端创建命令以创建新问题 命令处理程序创建新的问题聚合并将更改保存在事件存储中 当聚合应用更改时,它会触发IssueCreatedEvent或类似命令 读取端的投影将监听此消息,并创建问题模型和它想要的任何其他非规范化数据(例如用于查询所有问题列表的缩减问题列表) 如果对问题进行了
- 客户端创建命令以创建新问题
- 命令处理程序创建新的问题聚合并将更改保存在事件存储中
- 当聚合应用更改时,它会触发IssueCreatedEvent或类似命令
- 读取端的投影将监听此消息,并创建问题模型和它想要的任何其他非规范化数据(例如用于查询所有问题列表的缩减问题列表)
public class Issue : AggregateRoot, IEventHandler<CommentCreatedEvent>
{
private ICollection<Guid> _Comments;
public void Handle(CommentCreatedEvent @event)
{
_Comments.Add(@event.AggregateId)
}
}
如果是这样,我正在考虑让问题聚合订阅CommentCreated事件并添加自己的引用
public class Issue : AggregateRoot, IEventHandler<CommentCreatedEvent>
{
private ICollection<Guid> _Comments;
public void Handle(CommentCreatedEvent @event)
{
_Comments.Add(@event.AggregateId)
}
}
public类问题:AggregateRoot,IEventHandler
{
私人收集意见;
公共无效句柄(CommentCreatedEvent@event)
{
_Comments.Add(@event.AggregateId)
}
}
由于注释已经存储了对其父级的引用,这是否足够?在写端实际上并不需要这些数据,而在读端,当父级加载了所有注释时,这些数据更为重要
Row | issueId | name | comments |
| 1 | comments persistence solution | {c1,c2,c3} |
2)在读取端,存储此数据的最佳方式是什么?
具体来说,为了使这些数据易于更新,我需要在另一个表中添加评论,并将它们加入到适当的帖子或问题中。在我完成评论之后,我将实现一个以下系统,用户可以在其中跟踪某个项目以接收更新。然而,沿着这条路走下去,我很快就会回到读端的高度规范化模式,这违背了优化、非规范化读模型的目的
因此,我考虑在问题表中添加一列,例如将所有注释存储为序列化json clob或其他内容。这样,当评论发生更改时,我仍然可以拉出一条记录来加载问题,对评论进行适当的更改(例如更新现有评论、添加新评论或删除评论)并重新保存记录。从阅读的角度来看,整个问题仍然可以一次性检索
我看到这种方法的问题是,如果用户更改了他们的个人资料图片或个人资料名称,例如,我将不得不加载每个问题和/或帖子,加载评论并在评论信息中进行适当的更改
我还想知道文档数据库(我在阅读方面一直在考虑的其他东西)是如何绕过更新嵌套数据的问题的?问题1:不需要有问题的关系。这里没有需要保护的特定一致性 问题2:我最近在读NoSQL。像卡桑德拉这样的列族数据库似乎适合评论
Row | issueId | name | comments |
| 1 | comments persistence solution | {c1,c2,c3} |
您可以使用Casandra api或Casandra查询语言来检索注释子集或整个注释列
更新
注释列只是ID的序列化集合吗
完整的评论?
否注释作为列存储在一行中。Casandra支持嵌套列。所以comments列的结构可能如下
如果我没弄错的话,你可以在卡桑德拉单独获取和设置任何评论。在这种情况下,您可以更新任何一条注释。或者你可以在评论栏中检索所有评论。我在聚会上迟到了一点,不过,下面是我对第二条的看法
Row | issueId | name | comments |
| 1 | comments persistence solution | {c1,c2,c3} |
存储读取模型的最佳方式是以一种非常容易查询的方式。文档数据库可以是一个很好的技术解决方案,但它也可以与rdbms一起使用,前提是您定义了相关的读取模型模式
您可以将所有评论与帖子一起存储,但情况并非总是如此,因为高流量站点通过ajax将评论与帖子分开加载。因此,这实际上取决于阅读模型用例。问题1:
您不能在聚合根目录中处理事件。打破DDD原则是个坏主意。如果评论存在于不同的聚合中,那么问题聚合中的任何结果最终都必须由域中的某种流程管理器、域服务或Saga来处理
如果可能的话,在你的领域中,你必须声明这个问题不知道评论(我想这是一种自然的思维方式),所以你不应该保留任何评论