在研究了大量材料和示例之后,我目前正在开始第一次尝试DDD/CQRS/ES系统.
1)我已经看到了事件源代码示例,其中Aggregates是事件处理程序,并且每个事件的Handle方法是改变对象实例上的状态(它们为将改变状态的事件实现IHandleEvent <EventType>接口)
2)我还看到了一些例子,其中Aggregates看起来就像是对域建模的普通经典实体类.另一个事件处理程序类涉及改变状态.
当然,当从存储库调用重建聚合时,状态由事件处理程序在聚合上进行突变,该存储库调用获取该聚合的所有先前事件,并且当命令处理程序调用聚合上的方法时.虽然在后者中我看过事件在命令处理程序而不是聚合中发布的例子,但我确信这是错误的.
我的问题是方法(1)和(2)之间的利弊是什么
我正在尝试使用符合我所看到的各种 Greg Young 启发示例的实践和原则来实现一个事件溯源系统。
我了解版本检查逻辑是如何工作的,并且在保存聚合时,如果当前版本与预期版本不匹配,则意味着另一个会话/客户端应用程序在您之前更新了聚合。
我也知道您可以制定一种在保存并发事件时追溯解决冲突的方法,这个问题与这样做无关。
我想了解的是,在使用 nosql 数据库(例如 ravendb)作为事件存储的特定实现中,我将如何确保写入的事件不会因竞争条件而与版本号重叠。
以下代码来自一个示例项目来说明:
在Repository<TAggregate>存储库类中有一个保存方法
public void Save(AggregateRoot aggregate, int expectedVersion)
{
if (aggregate.GetUncommittedChanges().Any())
{
lock (_lockStorage)
{
var item = new T();
if (expectedVersion != -1)
{
//issue if two processes get to this line of code below together
//and both have the same 'version to be expected' then start writing together
item = GetById(aggregate.Id);
if (item.Version != expectedVersion)
{
throw new ConcurrencyException(string.Format("Aggregate {0} has been previously modified",
item.Id));
} …Run Code Online (Sandbox Code Playgroud)