DDD - 聚合根 - 处理效率和并发

时间:2013-02-01 00:15:33

标签: c# mongodb domain-driven-design aggregateroot

首先,我承认我是DDD的新手,需要阅读“blue book”。

我正在构建一个具有“匹配”类型的AggregateRoot的系统。每个Match都有一个“Votes”集合,并且还有一个只读“VoteCount”属性,当用户向选票投票或向下投票时,该属性会增加。

由于许多用户可能同时对Match进行投票,因此必须在Match中添加/删除Votes,并且VoteCount必须递增/递减为一个涉及写锁的原子操作(由DB处理锁) )。 (我需要将VoteCount作为数据库中的静态值,以便其他进程/组件有效地查询。)

在我看来,如果我坚持严格的DDD,我会这样编码:

应用程序服务将收到一个投票请求对象 然后,该服务将从Match Repository中检索Match对象 然后,该服务将在Match对象上调用某种方法,以将Vote添加到集合中并更新VoteCount。 然后,存储库会将Match实例持久化回DB 但是,正如我所看到的那样,这种方法对我的应用来说是不可行的,主要有两个原因:

我在后端使用MongoDB,无法将此读写操作包装到事务中,以防止对Match数据及其关联的Votes和VoteCount进行脏读。

这是非常低效的。我正在拉回整个对象图,只是为了添加一个投票并增加VoteCount。虽然这在文档数据库中比在关系数据库中更有效,但我仍在进行不必要的读取操作。

问题1&将单个Vote对象发送到存储库并对Mongo执行一个原子更新语句时,2不是问题。

可以投票,在这种情况下被视为“聚合”并且应该得到自己的存储库和聚合状态吗?

2 个答案:

答案 0 :(得分:2)

  

可以投票,在这种情况下被视为“聚合”并且值得   它自己的存储库和聚合状态?

我认为这可能是正确的答案。聚合应该是事务一致性边界。比赛投票之间是否存在一致性要求?匹配聚合上的投票集合的呈现将表明存在。然而,似乎一票与下一票无关。

相反,我会单独存储每个投票。通过这种方式,您可以使用MongoDB的聚合功能来获取计数,但我不确定它是否仍然很慢。如果是,则可以使用Map / Reduce功能进行聚合。

更一般地说,这可能不适合DDD。如果域不包含复杂行为,则几乎没有理由尝试将DDD战术模式(实体,agreggate)调整到此域。

答案 1 :(得分:1)

是的,您可以将投票建模为自身的聚合。在现实世界中,人们经常会同时投票支持几件事。然后聚合将被称为 Ballot 而不是投票。你只有一个特殊情况,一次只有一个项目可以投票。

我不能代表MongoDB(也许其他人可以) - 但你可以很容易地在RavenDB中做这件事:

public class Match
{
    public string Id { get; set; }
    public string Name { get; set; } // or whatever
}

public class Vote
{
    public string Id { get; set; }
    public string MatchId { get; set; }
    public string UserId { get; set; }
    public bool YeaOrNay { get; set; } // or whatever
}

然后你只需在你的投票上建立一个map / reduce索引来计算结果。