同步dbContext查询的列表在单独的上下文上重写为async



本文是使用实体框架版本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时,这种结构可能存在问题?希望这只是我创造这种感觉的无知。

也要注意,我最初将服务重写为上下文作为服务类的字段;但是,最终遇到了错误:

在以前的异步操作完成之前,在此上下文中开始了第二个操作。使用"等待"来确保在此上下文调用另一种方法之前,任何异步操作都已完成。任何实例成员都不能保证是线程安全的。

将上下文的生命周期更改为方法调用修复了这一问题,但是看到这个错误使我对这种一般策略感到紧张。

在我看来,您正在以正确的方式进行此操作,

  1. 您不应该缓存DbContext,SQL连接已被缓存为您的引擎盖下。这样做会导致您已经遇到的各种微妙错误。
  2. 上下文不是安全的。
  3. 它们是相当轻的重量,因此性能并不应该是一个问题。
  4. 最好将其放置在用小包工作的使用语句中

全能,将每个GetCount放置似乎是最好的方法

最新更新