Question

This example is with entity framework, but the question is more about how to await multiple async tasks within a loop. Say I have the following method on a custom DbContext class:

public async Task DiscardChangesAsync()
{
    foreach (var entry in ChangeTracker.Entries().Where(x => x != null))
    {
        switch (entry.State)
        {
            case EntityState.Added:
                entry.State = EntityState.Detached;
                break;
            case EntityState.Modified:
                entry.State = EntityState.Unchanged;
                break;
            case EntityState.Deleted:
                await entry.ReloadAsync(); // <-- only async method
                break;
        }
    }
}

The above compiles and runs, but I'm not sure how efficient it is. For example, if the context contains 10 deleted entity entries, the thread stops and waits at each ReloadAsync before it continues the loop, right? Is there any way to let the loop execution continue, and return a new Task that won't complete until all 10 of the ReloadAsync calls have completed?

Was it helpful?

Solution

To answer your question strictly:

public Task DiscardChangesAsync()
{
    List<Task> tasks = new List<Task>();
    foreach (var entry in ChangeTracker.Entries().Where(x => x != null))
    {
        switch (entry.State)
        {
            case EntityState.Added:
                entry.State = EntityState.Detached;
                break;
            case EntityState.Modified:
                entry.State = EntityState.Unchanged;
                break;
            case EntityState.Deleted:
                tasks.Add(entry.ReloadAsync());
                break;
        }
    }

    return Task.WhenAll(tasks);
}

May be more efficient, though, to let EF handle reloading all of them at once:

public Task DiscardChangesAsync()
{
    List<DbEntityEntry> deleted = new List<DbEntityEntry>();

    foreach (var entry in ChangeTracker.Entries().Where(x => x != null))
    {
        switch (entry.State)
        {
            case EntityState.Added:
                entry.State = EntityState.Detached;
                break;
            case EntityState.Modified:
                entry.State = EntityState.Unchanged;
                break;
            case EntityState.Deleted:
                deleted.Add(entry);
                break;
        }
    }

    return ctx.RefreshAsync(RefreshMode.StoreWins, deleted);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top