在单独的上下文中重写为异步调用的同步dbcontext查询列表

时间:2019-03-20 06:48:55

标签: c# entity-framework async-await

本文是在使用Entity Framework版本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时此结构可能存在问题??希望那只是我对这种感觉的无知。

还要注意,我最初使用上下文将服务重写为服务类的字段;但是,最终出现错误:

在先前的异步操作完成之前,第二个操作在此上下文上开始。使用“ await”来确保在此上下文上调用另一个方法之前,所有异步操作都已完成。不能保证任何实例成员都是线程安全的。

将上下文的生命周期更改为方法调用可以解决此问题,但是看到该错误通常会使我对这种通用策略感到不安。

1 个答案:

答案 0 :(得分:1)

我认为您的做法正确,

  1. 您不应该缓存DbContext,sql连接已经为您缓存了。这样做会导致各种细微的错误,这些错误您已经遇到过。
  2. 上下文不是线程安全的。
  3. 它们重量很轻,因此性能并不是真正的问题。
  4. 最好放在带有少量工作包的using语句中

总之,将每个GetCount放在这似乎是最好的方法