实体框架核心2.0引入了DbContext Pooling。 在我的代码中,我在Tasks中做了很多工作,因为我在数据库上做了一些独立的繁重操作。
我的老方法是:
Task.Run(() =>
{
AppDbContext c = new AppDbContext(this.config);
如何从EF Core 2.0 DbContext池中获取实例?
编辑:
我正在使用DI:public CategoryController(AppDbContext context, ...
这样做的原因是更快地执行Rest API方法。
例如,我认为这应该更快完成
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
然后这个:
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
在第二个示例中,第二个查询在第一个完成后执行
如果在第一个示例方法中,每个查询都需要150ms
,请执行大约150ms
,但大约在450ms
中执行。我是对的吗?
唯一的问题是如何在第一种方法中从连接池获取上下文。
答案 0 :(得分:2)
支持连接池的ASP.NET Core 2.0和Entity Framework Core 2.0的功能 - 不以任何方式 - 阻止您一次执行耗时的查询。池的整个概念是允许在多个请求中重用连接,而不是每次新请求进入时都必须重新创建实例。有时,它可以带来好处,有时可能会有垮台。现在,对于您的问题,有两种途径,
Startup
类中汇集连接,然后在您需要的任何地方重用这些对象。您可以在操作中捕获它们,以及您拥有的任何其他私有或本地函数。Startup
类中注册数据库上下文。但是你必须注意创建实例,手动处理实例。 由于许多原因,第二种方法不适合,也不是一种好的方法。如果要考虑第一种方法,则可以将控制器更改为接受类型数据库上下文的属性,例如,
public class YourController : Controller {
public AppDbContext c { get; set; }
public YourController (AppDbContext c) {
this.c = c;
}
}
现在,如果你有了这个,那么你可以在你的任务中使用这个c
变量,并在该函数中运行耗时的查询 - 这在任何方面都是无用的。你可以这样做,
Task.Run(() =>
{
// Use c here.
});
请记住以下几点:
ToListAsync()
- ToList()
可能不合适,请考虑使用ToListAsync()
并应用await
关键字异步捕获数据。 ToList
或任何类似的函数时,您的查询仅在数据库服务器上执行。 在您的情况下,为了更好地练习,您可能需要考虑将代码包装在using
块中,
Task.Run(() => {
using (var context = new AppDbContext) {
// use context here.
}
}
这是我能说的最好的帮助,因为你还没有分享1)不使用DI的目的,2)你的查询样本(为什么不使用LINQ构建查询然后在服务器上执行?) 3)要使用的任何示例代码。我希望这会让你知道为什么你应该考虑使用DI并使用从那里返回的实例。