本文是使用实体框架版本6.2。
的上下文好吧,所以我有一个相当慢的端点,本质上是以下内容:
public IHttpActionResult GetCounts()
{
int count1 = service.GetCount1();
int count2 = service.GetCount2();
Models.Counts ret = new Counts()
{
Count1 = count1,
Count2 = count2,
};
return Ok(ret);
}
在DBContext的同一实例上执行了每个对服务的调用:
//In the service
public class Service
{
private MyDbContext context;
public Service()
{
context = new MyDbContext();
}
public int GetCount1()
{
return context.coll1.Count();
}
public int GetCount2()
{
return context.coll2.Count();
}
}
最好将每个服务呼叫视为单独的工作单位,并为每个服务创建上下文,然后利用EF的异步方法,如下:
public async Task<IHttpActionResult> GetCountsAsync()
{
var tcount1 = service.GetCount1Async();
var tcount2 = service.GetCount2Async();
await Task.WhenAll(tcount1, tcount2);
int count1 = tcount1.Result;
int count2 = tcount2.Result;
Models.Counts ret = new Counts()
{
Count1 = count1,
Count2 = count2
};
return Ok(ret);
}
服务的变化为
//In the service
public class Service
{
public Service()
{
}
public async Task<int> GetCount1()
{
using(var context = new MyDbContext())
{
return await context.coll1.CountAsync();
}
}
public async Task<int> GetCount2()
{
using(var context = new MyDbContext())
{
return await context.coll2.CountAsync();
}
}
}
有弊端吗?它有效,并且绝对改善了查询的性能。
我对线程的新手(在这种情况下为异步/等待),所以不熟悉潜在的弊端,或者我上面的是一个对抗者,但是我的一部分觉得在使用EF的dbContext时,这种结构可能存在问题?希望这只是我创造这种感觉的无知。
也要注意,我最初将服务重写为上下文作为服务类的字段;但是,最终遇到了错误:
在以前的异步操作完成之前,在此上下文中开始了第二个操作。使用"等待"来确保在此上下文调用另一种方法之前,任何异步操作都已完成。任何实例成员都不能保证是线程安全的。
将上下文的生命周期更改为方法调用修复了这一问题,但是看到这个错误使我对这种一般策略感到紧张。
在我看来,您正在以正确的方式进行此操作,
- 您不应该缓存
DbContext
,SQL连接已被缓存为您的引擎盖下。这样做会导致您已经遇到的各种微妙错误。 - 上下文不是安全的。
- 它们是相当轻的重量,因此性能并不应该是一个问题。
- 最好将其放置在用小包工作的使用语句中
全能,将每个GetCount
放置似乎是最好的方法