Entity Framework Core Pitfalls: Asynchronous vs Synchronous Calls and Interceptors
Introduction
Another on my EF Core pitfalls series. This time, interceptors and synchronous/asynchronous calls.
Problem
You surely know about EF Core interceptors, a very useful feature that I talked about many times. What's the problem with them? Well, all of the interceptor interfaces define both synchronous as well as asynchronous versions of their methods. This is so that, for example, when we call DbContext.SaveChanges the synchronous version is called, and when it's DbContext.SaveChangesAsync, the asynchronous one instead. I think you get the idea.
So, imagine we added an interceptor, inheriting from SaveChangesInterceptor, to our collection of interceptors. If we then commit the changes in the DbContext through a call to DbContext.SaveChanges, only SavingChanges, SavedChanges, SavedChangesFailed, SaveChangedCanceled and, or, ThrowingConcurrencyException methods will be called, and you may be very surprised because your well-crafted asynchronous one wasn't.
Solution
Two possible solutions:
- Always make sure you call the same version of each operation, synchronous or asynchronous, and implement only the matching method on the interceptors consistently
- Have both versions call the same shared code, for example:
public override InterceptionResult<int> SavingChanges(DbContextEventData eventData, InterceptionResult<int> result)
{
SaveChanges(eventData.Context);
return base.SavingChanges(eventData, result);
}
public override ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData eventData, InterceptionResult<int> result, CancellationToken cancellationToken))
{
SaveChanges(eventData.Context);
return base.SavingChangesAsync(eventData, result, cancellationToken);
}
private void SaveChanges(DbContext context)
{
//where the magic actually happens
}
Conclusion
Hope you find this useful. Stay tuned for more!
Comments
Post a Comment