关于实体框架和重构的Async/Await问题
本文关键字:重构 Async 问题 Await 框架 于实体 实体 | 更新日期: 2023-09-27 18:02:47
我正在开始一个新项目,我想利用。net中的async/await项目以及实体框架(6.1版)中的新async操作。然而,我好奇的是如何重构应用程序的某些部分以减少代码重复,以及考虑到EF的非线程安全特性,实现这一目标的最佳方法是什么。
示例,我有几个方法在我的服务层看起来像这样
public async Task<MyViewModel> GetProgramIndexAsync(long programId){
using (var db = new DbEntities())
{
var program = await db.Programs.FirstOrDefaultAsync(x => x.Id == programId && x.Active);
if (program == null)
{
throw new ApplicationException("Cannot find the requested program");
}
//more code to populate the view model
}
}
到目前为止,一切顺利。但是我发现自己在这个服务层的多个地方做这个检查。理想的做法是将其提取到单独的函数
中private async Task<Program> GetProgramAsync(long programId){
using (var db = new DbEntities())
{
var program = await db.Programs.FirstOrDefaultAsync(x => x.Id == programId && x.Active);
if (program == null)
{
throw new ApplicationException("Cannot find the requested program");
}
return program;
}
}
现在,我的公共服务层调用可以简单地调用这个函数,而不必每次都重复这个检查。
var program = await GetProgramAsync(programId);
我担心的是这些请求中的每一个都有多个上下文。在过去(同步),我可以简单地使用第二个函数参数,如
private async Task<Program> GetProgramAsync(long programId, DbContext db){
并将现有上下文传递给方法。然而,我认为这对异步/等待性质来说是不好的。
我是不是想多了(多个上下文并不是那么糟糕),还是有更好的方法来实现这一点?我应该注意,这些调用是只读的,我不会以这种方式更新实体。
你认为你的问题都不是问题。
-
由于连接池,旋转多个上下文并不是一个真正的问题。创建新上下文实际上不需要创建新的数据库连接,它只需要从池中获取一个。如果在需要一个新连接之前将一个连接放回池中,而不是持有大量并发的连接,则开销非常小。
-
如果你在这些方法之间传递上下文,它的仍然不是问题。代码是异步的,但它没有并行地做任何事情。上下文每次只能由单个线程使用。你总是在等待任何可能是异步的操作,这意味着当其他完全与这些方法相关的代码可能正在使用CPU时,无论是另一个响应处理程序(如果这是ASP), UI泵送其他事件(如果这是桌面应用程序),或者其他什么,你仍然没有放在一次从多个线程访问这个上下文的位置
。