关于实体框架和重构的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){

并将现有上下文传递给方法。然而,我认为这对异步/等待性质来说是不好的。

我是不是想多了(多个上下文并不是那么糟糕),还是有更好的方法来实现这一点?我应该注意,这些调用是只读的,我不会以这种方式更新实体。

关于实体框架和重构的Async/Await问题

你认为你的问题都不是问题。

  1. 由于连接池,旋转多个上下文并不是一个真正的问题。创建新上下文实际上不需要创建新的数据库连接,它只需要从池中获取一个。如果在需要一个新连接之前将一个连接放回池中,而不是持有大量并发的连接,则开销非常小。

  2. 如果你在这些方法之间传递上下文,它的仍然不是问题。代码是异步的,但它没有并行地做任何事情。上下文每次只能由单个线程使用。你总是在等待任何可能是异步的操作,这意味着当其他完全与这些方法相关的代码可能正在使用CPU时,无论是另一个响应处理程序(如果这是ASP), UI泵送其他事件(如果这是桌面应用程序),或者其他什么,你仍然没有放在一次从多个线程访问这个上下文的位置