[英]IQueryable, IEnumerable and async in REST Web API for ASP.NET Core and OData
I'm playing around w/ OData and Web API for a project.我正在为一个项目使用 OData 和 Web API。 The default generated EF controller in ASP gives endpoints/actions that look like : ASP 中默认生成的 EF 控制器提供如下所示的端点/操作:
// GET: api/Users
[HttpGet]
public async Task<ActionResult<IEnumerable<User>>> GetUsers()
{
return await _context.Users.ToListAsync();
}
From what i can gather, this returns a list of User objects that are serialized into JSON and returned to the consumer as a big JSON array.据我所知,这将返回一个用户对象列表,这些对象被序列化为 JSON 并作为一个大的 JSON 数组返回给消费者。 It is async to allow the server to serve other requests while EF queries the database in the background.当 EF 在后台查询数据库时,允许服务器处理其他请求是异步的。 The management of serving requests happens upstream by ASP and the ControllerBase class.服务请求的管理由 ASP 和 ControllerBase 类在上游进行。
Following the example here: https://docs.microsoft.com/en-gb/shows/on-net/supercharging-your-web-apis-with-odata-and-aspnet-core?wt.mc_id=ondotnet-c9-cephilli , I can maintain a conventional REST API w/ Swagger/OpenAPI support by simply adding a Queryable
attribute above the Get
action.按照此处的示例: https ://docs.microsoft.com/en-gb/shows/on-net/supercharging-your-web-apis-with-odata-and-aspnet-core?wt.mc_id=ondotnet-c9 -cephilli ,我可以通过简单地在Get
操作上方添加一个Queryable
属性来维护带有 Swagger/OpenAPI 支持的传统 REST API。
However, this got me thinking: is this the optimal solution?然而,这让我思考:这是最佳解决方案吗? If I have 1 million users, but the consumer is only calling a Top 100, will the Get Action wait to get the full Users DbSet before OData starts to query it for only 100 records to return to the consumer?如果我有 100 万用户,但消费者只调用前 100 个用户,那么在 OData 开始查询它以仅返回 100 条记录返回给消费者之前,获取操作是否会等待获取完整的用户 DbSet? Should I be returning an IQueryable in the form of the DbSet?:我应该以 DbSet 的形式返回 IQueryable 吗?:
// GET: api/Users
[HttpGet]
[EnableQuery]
public ActionResult<IQueryable<User>> GetUsers()
{
return _context.Users;
}
Will this change either conventional API calls or OData calls now that the Action is no longer async?现在 Action 不再是异步的,这是否会改变传统的 API 调用或 OData 调用? Is there some other optimal or recommended solution for returning queries that works across both conventional and OData APIs?是否有其他一些最佳或推荐的解决方案来返回适用于传统 API 和 OData API 的查询?
There is a massive difference between IQueryable and IEnumerable. IQueryable 和 IEnumerable 之间存在巨大差异。
IQueryable is an interface that allows LINQ to SQL meaning that it will run filtered query runs in the database whereas IEnumerable is LINQ to Object meaning it executes the query in the database, then filters out in the memory. IQueryable 是一个允许 LINQ to SQL 的接口,这意味着它将运行在数据库中运行的过滤查询,而 IEnumerable 是 LINQ to Object,这意味着它在数据库中执行查询,然后在内存中过滤。
For example, In your case例如,在您的情况下
public async Task<ActionResult<IQueryable<User>>> GetUsers()
{
return await _context.Users;
}
this will return all users from the database so not much of a difference between IQueryable and IEnumerable, but as you mentioned you have 1 million records and you need only 100 records, then your query becomes这将返回数据库中的所有用户,所以 IQueryable 和 IEnumerable 之间没有太大区别,但是正如你提到的,你有 100 万条记录,你只需要 100 条记录,那么你的查询就变成了
public async Task<ActionResult<IQueryable<User>>> GetUsers()
{
return await _context.Users.Take(100);
}
Now, returning IEnumerable will load all of your million records to be loaded in memory and then give you the top 100, whereas IQueryable will get you only 100 from the database.现在,返回 IEnumerable 将加载所有要加载到内存中的百万条记录,然后为您提供前 100 条记录,而 IQueryable 只会从数据库中获取 100 条记录。
Yes, you should return an IQueryable
to translate your OData query into a database query:是的,您应该返回一个IQueryable
以将您的 OData 查询转换为数据库查询:
Returning System.Linq.IQueryable or ActionResult enables OData to translate queries to SQL queries using ef core capabilities.返回 System.Linq.IQueryable 或 ActionResult 使 OData 能够使用 ef 核心功能将查询转换为 SQL 查询。 Returning other types such as IEnumerable causes OData to perform queries in the app.返回其他类型(例如 IEnumerable)会导致 OData 在应用程序中执行查询。
https://docs.microsoft.com/en-us/odata/webapi/first-odata-api#update-the-controller https://docs.microsoft.com/en-us/odata/webapi/first-odata-api#update-the-controller
Since support for IQueryable
(and ef core) is baked into OData I would assume your action is still async, the difference is that the calls to ToListAsync
and similar methods are now handled by the OData library.由于对IQueryable
(和 ef 核心)的支持已融入 OData,因此我假设您的操作仍然是异步的,不同之处在于对ToListAsync
和类似方法的调用现在由 OData 库处理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.