entity framework可查询asynchronous

我正在使用entity framework6一些Web API的东西,我的控制器方法之一是“Get All”,希望从IQueryable<Entity>从我的数据库接收表的内容。 在我的存储库中,我想知道是否有任何有利的原因asynchronous做这个,因为我是新来使用EF与asynchronous。

基本上归结为

  public async Task<IQueryable<URL>> GetAllUrlsAsync() { var urls = await context.Urls.ToListAsync(); return urls.AsQueryable(); } 

VS

  public IQueryable<URL> GetAllUrls() { return context.Urls.AsQueryable(); } 

asynchronous版本实际上会在这里产生性能优势,还是我通过首先投影到列表(使用asynchronous介意你)然后去IQueryable?

这个问题似乎是你误解了如何asynchronous/等待与entity framework的工作。

关于entity framework

所以,让我们看看这个代码:

 public IQueryable<URL> GetAllUrls() { return context.Urls.AsQueryable(); } 

和它的用法的例子:

 repo.GetAllUrls().Where(u => <condition>).Take(10).ToList() 

那里发生了什么?

  1. 我们正在使用repo.GetAllUrls()获取IQueryable对象(不访问数据库repo.GetAllUrls()
  2. 我们使用.Where(u => <condition>创build一个具有指定条件的新的IQueryable对象
  3. 我们使用.Take(10)创build一个新的具有指定分页限制的IQueryable对象。
  4. 我们使用.ToList()从数据库检索结果。 我们的IQueryable对象被编译为sql(就像select top 10 * from Urls where <condition> )。 和数据库可以使用索引,SQL服务器从您的数据库只发送10个对象(不是所有的数据库中存储的十亿个URL)

好吧,让我们看看第一个代码:

 public async Task<IQueryable<URL>> GetAllUrlsAsync() { var urls = await context.Urls.ToListAsync(); return urls.AsQueryable(); } 

用同样的例子,我们得到了:

  1. 我们正在使用await context.Urls.ToListAsync();在内存中加载存储在数据库中的所有十亿个URL await context.Urls.ToListAsync();
  2. 我们有内存溢出。 正确的方式来杀死你的服务器

关于asynchronous/等待

为什么asynchronous/等待是首选使用? 让我们看看这个代码:

 var stuff1 = repo.GetStuff1ForUser(userId); var stuff2 = repo.GetStuff2ForUser(userId); return View(new Model(stuff1, stuff2)); 

这里发生了什么?

  1. 从第1行开始var stuff1 = ...
  2. 我们发送请求到sql服务器,我们不想得到一些stuff1 userId
  3. 我们等待(当前线程被阻止)
  4. 我们等待(当前线程被阻止)
  5. Sql服务器发给我们回应
  6. 我们移动到第2行var stuff2 = ...
  7. 我们发送请求到SQL服务器,我们不能得到一些stuff2 userId
  8. 我们等待(当前线程被阻止)
  9. 然后再次
  10. Sql服务器发给我们回应
  11. 我们渲染视图

所以我们来看看它的一个asynchronous版本:

 var stuff1Task = repo.GetStuff1ForUserAsync(userId); var stuff2Task = repo.GetStuff2ForUserAsync(userId); await Task.WhenAll(stuff1Task, stuff2Task); return View(new Model(stuff1Task.Result, stuff2Task.Result)); 

这里发生了什么?

  1. 我们发送请求到SQL服务器获取stuff1(第1行)
  2. 我们发送请求到SQL服务器获取stuff2(第2行)
  3. 我们等待来自sql server的响应,但是当前线程没有被阻塞,他可以处理来自其他用户的查询
  4. 我们渲染视图

正确的方法来做到这一点

这么好的代码在这里:

 using System.Data.Entity; public IQueryable<URL> GetAllUrls() { return context.Urls.AsQueryable(); } public async Task<List<URL>> GetAllUrlsByUser(int userId) { return await GetAllUrls().Where(u => u.User.Id == userId).ToListAsync(); } 

请注意,为了使用IQueryable的ToListAsync()方法,必须添加using System.Data.Entity

请注意,如果您不需要过滤和分页以及其他东西,则不需要使用IQueryable 。 您可以使用await context.Urls.ToListAsync()并使用物化List<Url>

你发布的例子有一个巨大的差异,第一个版本:

 var urls = await context.Urls.ToListAsync(); 

这是不好的 ,它基本上select * from tableselect * from table ,将所有结果返回到内存中,然后应用内存集合中的where一个,而不是对数据库执行select * from table where...

第二种方法直到查询被应用到IQueryable (实际上可能通过一个只返回与查询相匹配的db值的linq。

如果您的示例具有可比性,则每个请求的async版本通常会稍慢一些,因为编译器生成的允许asyncfunction的状态机的开销更大。

然而,主要的区别(和好处)是, async版本允许更多的并发请求,因为它在等待IO完成(db查询,文件访问,web请求等)时不阻塞处理线程。