Reputation: 2036
Am I allowed to execute SaveChanges
during an active loop over IAsyncEnumerable
from DbSet
?
The Api remarks "Multiple active operations on the same context instance are not supported. Use await to ensure that any asynchronous operations have completed before calling another method on this context. See Avoiding DbContext threading issues for more information and examples."
But I'm not sure if an open IAsyncEnumerable
loop counts as an active operation.
I'd like to mark my entries so that they are only queried once.
Do I have to use another dbcontext to save the status marker?
while(!cancellationToken.IsCancellationRequested)
{
await using var scope = serviceScopeFactory.CreateAsyncScope();
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
await foreach(var o in db.Orders
.Where(o => o.Status != 1) // and some other conditions
.AsAsyncEnumerable()
.WithCancellation(cancellationToken)
.ConfigureAwait(false))
{
o.Status = 1;
await db.SaveChangesAsync(cancellationToken);
// run fire and forget async work once
}
}
Upvotes: 1
Views: 31
Reputation: 43474
I don't have much experience with the Entity framework, but from what I see there is no concurrency in your code. The C# compiler transforms the await foreach
statement to something like this:
while(!cancellationToken.IsCancellationRequested)
{
await using var scope = serviceScopeFactory.CreateAsyncScope();
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
var enumerator = db.Orders
.Where(o => o.Status != 1) // and some other conditions
.AsAsyncEnumerable()
.GetAsyncEnumerator(cancellationToken);
try
{
while (await enumerator.MoveNextAsync().ConfigureAwait(false))
{
var o = enumerator.Current;
o.Status = 1;
await db.SaveChangesAsync(cancellationToken);
// run fire and forget async work once
}
}
finally
{
await enumerator.DisposeAsync().ConfigureAwait(false);
}
}
The asynchronous operations enumerator.MoveNextAsync()
and db.SaveChangesAsync()
are performed sequentially.
There are of course questions about the code represented by the // run fire and forget async work once
comment, but since we don't see the code I'll just have to assume that you know what you are doing there.
Upvotes: 0