使用对象图时的 EF Core 并发性

EF Core concurrency when using object graph

我一直在研究 EF Core,并试图了解如何使用它来更新对象图,同时考虑到 DDD。我的第一个测试对于插入很有效,但现在我遇到了更新问题。

这个想法是让聚合根实体控制是否执行更新。实际上,我需要确保 EF Core 在更改属于我的聚合的其他表之前始终检查“顶级实体”的版本字段。

但是,似乎 EF Core 总是从更新“从属表”开始,并且它只会在该实体更新或显式更新时生成最上面的“更新”语句(具有版本并发检查)添加到更新列表(例如:通过显式调用 DbContextupdate 方法并将其传递给它)。

你们是怎么解决这个问题的?如果我使用的是 Dapper,我可能会尝试在影响其他表的 运行 其他 SQL 指令之前更新顶级实体(即使这可能意味着 运行 更新不会并没有真正更新任何东西)...通过这样做,我将确保在我的更新期间完整的对象图没有被其他用户更改(这被包装在一个事务中)。

看看Confab solution on Github。这是它的一小部分 - 一个示例 AggregateRoot 实现,可以帮助您解决问题:

public abstract class AggregateRoot<T>
{
    public T Id { get; protected set; }
    public int Version { get; protected set; }
    public IEnumerable<IDomainEvent> Events => _events;
    
    private readonly List<IDomainEvent> _events = new();
    private bool _versionIncremented;

    protected void AddEvent(IDomainEvent @event)
    {
        if (!_events.Any() && !_versionIncremented)
        {
            Version++;
            _versionIncremented = true;
        }
        
        _events.Add(@event);
    }

    public void ClearEvents() => _events.Clear();

    protected void IncrementVersion()
    {
        if (_versionIncremented)
        {
            return;
        }
        
        Version++;
        _versionIncremented = true;
    }
}

您需要在每次聚合更改时调用 AddEvent。另请检查解决方案的其余部分。

您也可以尝试改进一下。一个可能的选择是使用 EF ChangeTracker 在实体中搜索引发的域事件,然后增加聚合版本。

编辑:

这里有一个 article by Kamil Grzybek 值得一提。