Parallel Queries in EF Core with PostgreSQL: Why It Fails and How to Fix It
You may have faced an interesting error trying to run queries in parallel with EF Core and Postgres: "A command is already in progress" which isn't very specific but refers to parallel execution failure. This piece of code represents an intention of parallel query execution: var city = db.Cities.ExecuteDeleteAsync(); var forecasts = db.WeatherForecasts.ExecuteDeleteAsync(); await Task.WhenAll(city, forecasts); Seems that it should work, so what's wrong? Let's get a little bit into the details of what's going on here. ExecuteDeleteAsync() runs the SQL query in DB immediately, so there is no need to call SaveChangesAsync(). Also, EF Core doesn't track any changes as entities are not loaded into memory. Task.WhenAll() allows tasks to be awaited concurrently. When dealing with I/O-bound operations, such as database interactions, they are expected to be parallelized, as in our case. Please note that city and forecast entities are not connected with a foreign key. It looks like they should be, however, for testing purposes, I intentionally avoid that. If they are connected with a foreign key and have a CASCADE restriction, then this call will work because forecasts will be deleted along with the cities. What have we missed? It turned out that Postgres doesn't support parallel query execution within the same connection, unlike the SQL Server.

You may have faced an interesting error trying to run queries in parallel with EF Core and Postgres: "A command is already in progress" which isn't very specific but refers to parallel execution failure.
This piece of code represents an intention of parallel query execution:
var city = db.Cities.ExecuteDeleteAsync();
var forecasts = db.WeatherForecasts.ExecuteDeleteAsync();
await Task.WhenAll(city, forecasts);
Seems that it should work, so what's wrong?
Let's get a little bit into the details of what's going on here.
ExecuteDeleteAsync()
runs the SQL query in DB immediately, so there is no need to call SaveChangesAsync()
. Also, EF Core doesn't track any changes as entities are not loaded into memory.
Task.WhenAll()
allows tasks to be awaited concurrently. When dealing with I/O-bound operations, such as database interactions, they are expected to be parallelized, as in our case.
Please note that city and forecast entities are not connected with a foreign key. It looks like they should be, however, for testing purposes, I intentionally avoid that. If they are connected with a foreign key and have a CASCADE restriction, then this call will work because forecasts will be deleted along with the cities.
What have we missed?
It turned out that Postgres doesn't support parallel query execution within the same connection, unlike the SQL Server.