I've been looking at EF Core and I'm trying to see how I can use it to update object graphs with DDD in mind. My first tests are working well for inserts, but now I've got an issue with updates.
The idea is to have the aggregate root entity control if the updates are performed. In practice, what I need is to make sure that EF Core will always check the "top entity's" version field before changing the other tables that are part of my aggregate.
However, it seems like EF Core will always start by updating the "dependent tables" and it will only generate the top "update" statement (that has the version concurrency check) when that entity is updated or when it's explicitly added to the the update list (ex.: by explicitly calling the DbContext
's update
method and passing it to it).
How are you guys solving this? If I was using Dapper, I'd probably try to update the top entity before running the other SQL instructions that affect the other tables (even though that might mean running an update that wouldn't really update anything)...By doing this, I'd make sure that the complete object graph hasn't been changed by another user during my update (which is wrapped in a transaction).
Take a look at Confab solution on Github. Here is a small part of it - an example AggregateRoot
implementation, that could help you solve your problem:
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;
}
}
You would need to call AddEvent
on every Aggregate change. Please check also the rest of the solution.
You can also try to improve it. A possible option would be to use EF ChangeTracker
to search for raised domain events in entities, then increment an aggregate version.
Edit:
Here's an article by Kamil Grzybek worth mentioning.