实体框架可查询异步 [英] Entity Framework Queryable async
问题描述
IQueryable<实体GT;
。在我的存储库中,我想知道是否有任何有利的理由像异步使用EF这样做是异步的。 基本上归结为
public async任务< IQueryable< URL>> GetAllUrlsAsync()
{
var urls = await context.Urls.ToListAsync();
return urls.AsQueryable();
}
vs
public IQueryable< URL> GetAllUrls()
{
return context.Urls.AsQueryable();
}
异步版本是否会在这里实际产生性能优势,或者我会产生不必要的开销首先投射到列表(使用异步头脑),然后转到IQueryable?
问题似乎是你有误解了实体框架的异步/等待工作。
关于实体框架
所以,让我们看看这个代码:
public IQueryable< URL> GetAllUrls()
{
return context.Urls.AsQueryable();
}
及其用法示例:
$ b $($)$($)$($)$($)$($)$($)$($)$ >
发生什么事?
- 我们正在使用
IQueryable
对象(不访问数据库) $ c> repo.GetAllUrls() - 我们使用指定的条件创建一个新的
IQueryable
code> .Where(u =>< condition> - 我们创建一个新的
IQueryable
具有指定分页限制的对象,使用.Take(10)
- 我们使用
从数据库中检索结果。 ToList()
。我们的IQueryable
对象被编译为sql(如从Urls中选择前10个*,其中< condition>数据库可以使用索引,sql server只发送数据库中的10个对象(并不是数据库中存储的所有十亿个URL)
好的,我们来看看第一个代码:
public async任务< IQueryable< URL>> GetAllUrlsAsync ()
{
var urls = await context.Urls.ToListAsync();
return urls.AsQueryable();
}
与我们得到的使用情况相同:
- 我们正在使用
await context.Urls.ToListAsync();
。 - 加载内存中存储在您的数据库中的所有十亿个URL溢出。杀死你的服务器的正确方法
关于异步/等待
/等待优先使用?我们来看看这个代码:
var stuff1 = repo.GetStuff1ForUser(userId);
var stuff2 = repo.GetStuff2ForUser(userId);
return View(new Model(stuff1,stuff2));
这里发生了什么?
- 从第1行开始
var stuff1 = ...
- 我们向sql server发送请求,我们不要获得一些东西1
userId
- 我们等待(当前线程被阻止)
- 我们等待(当前线程被阻止)
- ...
- Sql server发送给我们回复
- 我们移动到第2行
var stuff2 = ...
- 我们发送请求到sql server,我们不会得到一些stuff2为
userId
- 我们等待(当前线程被阻止)
- 再次
- ...
- Sql server发送给我们回复
- 我们呈现视图
所以让我们来看看它的异步版本:
var stuff1Task = repo.GetStuff1ForUserAsync(userId);
var stuff2Task = repo.GetStuff2ForUserAsync(userId);
等待Task.WhenAll(stuff1Task,stuff2Task);
return View(new Model(stuff1Task.Result,stuff2Task.Result));
这里发生了什么?
- 我们向sql server发送请求以获取stuff1(第1行)
- 我们向sql server发送请求以获取stuff2(第2行)
- 我们等待sql server的响应,但是当前线程不被阻止,他可以处理来自其他用户的查询。
- 我们呈现视图
- We are getting
IQueryable
object (not accessing database yet) usingrepo.GetAllUrls()
- We create a new
IQueryable
object with specified condition using.Where(u => <condition>
- We create a new
IQueryable
object with specified paging limit using.Take(10)
- We retrieve results from database using
.ToList()
. OurIQueryable
object is compiled to sql (likeselect top 10 * from Urls where <condition>
). And database can use indexes, sql server send you only 10 objects from your database (not all billion urls stored in database) - We are loading in memory all billion urls stored in your database using
await context.Urls.ToListAsync();
. - We got memory overflow. Right way to kill your server
- Starting on line 1
var stuff1 = ...
- We send request to sql server that we wan't to get some stuff1 for
userId
- We wait (current thread is blocked)
- We wait (current thread is blocked)
- ...
- Sql server send to us response
- We move to line 2
var stuff2 = ...
- We send request to sql server that we wan't to get some stuff2 for
userId
- We wait (current thread is blocked)
- And again
- ...
- Sql server send to us response
- We render view
- We send request to sql server to get stuff1 (line 1)
- We send request to sql server to get stuff2 (line 2)
- We wait for responses from sql server, but current thread isn't blocked, he can handle queries from another users
- We render view
正确的方法
这里很好的代码:
使用System.Data.Entity;
public IQueryable< URL> GetAllUrls()
{
return context.Urls.AsQueryable();
}
public async任务<列表< URL>> GetAllUrlsByUser(int userId){
return await GetAllUrls()。其中(u => u.User.Id == userId).ToListAsync();
}
请注意,不要使用System.Data添加 .Entity
为了使用IQueryable的方法 ToListAsync()
。注意,如果您不需要过滤和分页和东西,则不需要使用 IQueryable
。您可以使用等待context.Urls.ToListAsync()
并使用实例化的列表< Url>
。
I'm working on some some Web API stuff using Entity Framework 6 and one of my controller methods is a "Get All" that expects to receive the contents of a table from my database as IQueryable<Entity>
. In my repository I'm wondering if there is any advantageous reason to do this asynchronously as I'm new to using EF with async.
Basically it boils down to
public async Task<IQueryable<URL>> GetAllUrlsAsync()
{
var urls = await context.Urls.ToListAsync();
return urls.AsQueryable();
}
vs
public IQueryable<URL> GetAllUrls()
{
return context.Urls.AsQueryable();
}
Will the async version actually yield performance benefits here or am I incurring unnecessary overhead by projecting to a List first (using async mind you) and THEN going to IQueryable?
The problem seems to be that you have misunderstood how async/await work with Entity Framework.
About Entity Framework
So, let's look at this code:
public IQueryable<URL> GetAllUrls()
{
return context.Urls.AsQueryable();
}
and example of it usage:
repo.GetAllUrls().Where(u => <condition>).Take(10).ToList()
What happens there?
Okay, let's look at first code:
public async Task<IQueryable<URL>> GetAllUrlsAsync()
{
var urls = await context.Urls.ToListAsync();
return urls.AsQueryable();
}
With the same example of usage we got:
About async/await
Why async/await is preferred to use? Let's look at this code:
var stuff1 = repo.GetStuff1ForUser(userId);
var stuff2 = repo.GetStuff2ForUser(userId);
return View(new Model(stuff1, stuff2));
What happens here?
So let's look to an async version of it:
var stuff1Task = repo.GetStuff1ForUserAsync(userId);
var stuff2Task = repo.GetStuff2ForUserAsync(userId);
await Task.WhenAll(stuff1Task, stuff2Task);
return View(new Model(stuff1Task.Result, stuff2Task.Result));
What happens here?
Right way to do it
So good code here:
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();
}
Note, than you must add using System.Data.Entity
in order to use method ToListAsync()
for IQueryable.
Note, that if you don't need filtering and paging and stuff, you don't need to work with IQueryable
. You can just use await context.Urls.ToListAsync()
and work with materialized List<Url>
.
这篇关于实体框架可查询异步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!