Get Context instance from DbContextPool (EF Core 2.0) to use it in Task

entity-framework entity-framework-core

Question

Entity framework core 2.0 introduce DbContext Pooling. In my code I do a lot of jobs in Tasks because I do some independent heavy operations on database.

My old approach was:

Task.Run(() =>
{
    AppDbContext c = new AppDbContext(this.config); 

How can I get instance from EF Core 2.0 DbContext Pooling?

Edited:

I am using DI: public CategoryController(AppDbContext context, ... Reason for doing this is quicker execute Rest API method.

For example, I think this should complete quicker

    List<AppUser> users;
    List<DbGroup> groups;
    Task task1 = Task.Run(async() => {
        users = await ContextFromConnectionPool.Users.Where(t => t.Id == 1).ToListAsync();
    });
    Task task2 = Task.Run(async () => {
        groups = await ContextFromConnectionPool.Groups.Where(t => t.Id == 1).ToListAsync();
    });
    var tags = await this.context.Tags.ToListAsync();
    Task.WaitAll(task1, task2);
    //process all 3 results

then this:

    List<AppUser> users = await this.context.Users.Where(t => t.Id == 1).ToListAsync();
    List<DbGroup> groups = await this.context.Groups.Where(t => t.Id == 1).ToListAsync();
    var tags = await this.context.Tags.ToListAsync();
    //process all 3 results

In second example second query executes after first is completed.
If every query takes 150ms in first example method execute in approx 150ms, but second in approx 450ms. Am I right?
Only problem is how to get context from connection pool in first approach.

1
2
9/4/2017 5:18:24 AM

Accepted Answer

The feature of ASP.NET Core 2.0 and Entity Framework Core 2.0, to support connection pooling, is not — in any way — preventing you from doing the time consuming queries at once. The entire concept of pooling is to allow the connection to be reused in multiple requests, instead of having to recreate an instance each time a new request comes in. Sometimes, it can have benefits and sometimes it might have downfalls. Now, for your question, there are two pathways,

  1. Allow the framework to pool the connection in Startup class and then reuse those objects everywhere you need. You can capture them inside the actions, and any other private or local functions that you have.
  2. Do not use DI and database context pooling and instead keep doing what you were doing. Note that, you were never using DI and thus there is no need to register your database context in the Startup class. But you must take care of creation of instance, manually disposing the instance as well.

Second approach is not suitable, and not a good approach as well, for many reasons. If you want to consider the first approach you can then change your controller to accept a property of the type database context, such as,

public class YourController : Controller {
    public AppDbContext c { get; set; }

    public YourController (AppDbContext c) {
        this.c = c;
    }
}

Now if you have got that, you can then use this c variable inside your tasks, and run the time consuming queries inside that function — which in any way would be too useless. You can do this,

Task.Run(() => 
{
    // Use c here.
});

Just remember a few points:

  1. It is good to build your query, and then call ToListAsync()ToList() may not be suitable, consider using ToListAsync() and apply await keyword for asynchronously capturing the data.
  2. Your query only gets executed on the database server, when you call ToList or any similar function.
  3. While running tasks in parallel, you must also handle any cases where your query might break the policies, such as data integrity or similar cases in database. It is always a best practice to catch the exceptions.

In your case, for just better practicing you might want to consider wrapping your code inside using block,

Task.Run(() => {
    using (var context = new AppDbContext) {
        // use context here.
    }
}

This is the best that I can state to help you, since you have not shared 1) purpose of not using DI, 2) the sample of your query (why not using LINQ to build query and then executing on server?) 3) any sample code to be used. I hope this would give you an idea of, why you should consider using DI and using the instances returned from there.

2
9/1/2017 5:18:26 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow