C# 在不同上下文上重写为异步调用的同步dbcontext查询列表
这篇文章是在使用实体框架版本6.2的背景下发表的 好的,我有一个相当慢的端点,基本上如下所示:C# 在不同上下文上重写为异步调用的同步dbcontext查询列表,c#,entity-framework,async-await,C#,Entity Framework,Async Await,这篇文章是在使用实体框架版本6.2的背景下发表的 好的,我有一个相当慢的端点,基本上如下所示: public IHttpActionResult GetCounts() { int count1 = service.GetCount1(); int count2 = service.GetCount2(); Models.Counts ret = new Counts() { Count1
public IHttpActionResult GetCounts()
{
int count1 = service.GetCount1();
int count2 = service.GetCount2();
Models.Counts ret = new Counts()
{
Count1 = count1,
Count2 = count2,
};
return Ok(ret);
}
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);
}
对服务的每个调用都在同一个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 IHttpActionResult GetCounts()
{
int count1 = service.GetCount1();
int count2 = service.GetCount2();
Models.Counts ret = new Counts()
{
Count1 = count1,
Count2 = count2,
};
return Ok(ret);
}
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);
}
公共异步任务GetCountsAsync()
{
var tcount1=service.GetCount1Async();
var tcount2=service.GetCount2Async();
等待任务。WhenAll(t计数1,t计数2);
int count1=t计数1.结果;
int count2=t计数2.结果;
Models.Counts ret=新计数()
{
Count1=Count1,
Count2=Count2
};
返回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();
}
}
}
//在服务中
公务舱服务
{
公共服务()
{
}
公共异步任务GetCount1()
{
使用(var context=new MyDbContext())
{
返回wait context.coll1.CountAsync();
}
}
公共异步任务GetCount2()
{
使用(var context=new MyDbContext())
{
返回wait context.coll2.CountAsync();
}
}
}
这有什么坏处吗?它可以工作,并且无疑提高了查询的性能
我对线程(在本例中为异步/等待)相当陌生,因此不熟悉潜在的缺点,或者我上面提到的是反模式,但我的一部分感觉在使用EF的dbcontext时,这种结构可能会有问题??希望这只是我的无知造成的那种感觉
还要注意的是,我最初将上下文作为服务类的一个字段来重写服务;但是,最终得到了错误:
在上一个异步操作完成之前,在此上下文上启动了第二个操作。使用“await”确保在此上下文上调用另一个方法之前已完成任何异步操作。任何实例成员都不能保证线程安全
将上下文的生命周期更改为方法调用解决了这一问题,但看到这个错误,我对这个总体策略感到紧张。在我看来,您这样做是正确的
DbContext
,sql连接已经为您缓存好了。这样做可能会导致您已经遇到的各种细微错误GetCount
放在一起似乎是最好的方法