使用对象图时的 EF Core 并发性
EF Core concurrency when using object graph
我一直在研究 EF Core,并试图了解如何使用它来更新对象图,同时考虑到 DDD。我的第一个测试对于插入很有效,但现在我遇到了更新问题。
这个想法是让聚合根实体控制是否执行更新。实际上,我需要确保 EF Core 在更改属于我的聚合的其他表之前始终检查“顶级实体”的版本字段。
但是,似乎 EF Core 总是从更新“从属表”开始,并且它只会在该实体更新或显式更新时生成最上面的“更新”语句(具有版本并发检查)添加到更新列表(例如:通过显式调用 DbContext
的 update
方法并将其传递给它)。
你们是怎么解决这个问题的?如果我使用的是 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 值得一提。
我一直在研究 EF Core,并试图了解如何使用它来更新对象图,同时考虑到 DDD。我的第一个测试对于插入很有效,但现在我遇到了更新问题。
这个想法是让聚合根实体控制是否执行更新。实际上,我需要确保 EF Core 在更改属于我的聚合的其他表之前始终检查“顶级实体”的版本字段。
但是,似乎 EF Core 总是从更新“从属表”开始,并且它只会在该实体更新或显式更新时生成最上面的“更新”语句(具有版本并发检查)添加到更新列表(例如:通过显式调用 DbContext
的 update
方法并将其传递给它)。
你们是怎么解决这个问题的?如果我使用的是 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 值得一提。