I’m trying to run two queries in parallel, which then get loaded into a view.
I’m doing something like this:
Task<IEnumerable<MyClass>> someData;
Task<IEnumerable<MyOtherClass>> someOtherData;
using (MyContext ctx1 = new())
{
someData = ctx1.MyClass.Where(x => x.ID == id);
}
using (MyContext ctx2 = new())
{
someOtherData = ctx2.MyOtherClass.Where(x => x.ID == id);
}
await Task.WhenAll(someData, someOtherData);
//Do stuff with someData.Result, someOtherData.Result
However, I am getting an ObjectDisposedException
.
I understand that DbContext is not thread-safe, but this should be creating and using two different instances… So how comes they appear to be using the same one (and thus it is getting disposed before/during the second call)?
The DbContext looks like this:
public partial class MyContext : DbContext
{
public MyContext ()
{
}
public MyContext(DbContextOptions<MyContext> options)
: base(options)
{
}
//Plus OnConfiguring, OnModelCreating, etc
}
>Solution :
First of all, your code will not compile at all because the Where
method has an IQueryablye
output and not a Task
type.
Assuming that we correct your code. Your problem goes back to the when you use Curly braces for scope, and practically, since your code is executed outside of those scopes, DbContext
is no longer available.
Beginning with C# 8.0, the using keyword can be used as an attribute in the variable declarations of disposable objects (Reference). The semantics is as you would expect — the objects are auto-disposed at the end of the scope.
The following code is modified from your code and the best practice is to use Using
Statement
await using MyContext ctx1 = new();
await using MyContext ctx2 = new();
var someData = ctx1.MyClass.Where(x => x.ID == id).ToListAsync();
var someOtherData = ctx2.MyOtherClass.Where(x => x.ID == id).ToListAsync();;
await Task.WhenAll(someData, someOtherData);