我正在为一个项目使用 OData 和 Web API。 ASP 中默认生成的 EF Controller 提供如下所示的端点/操作:
// GET: api/Users
[HttpGet]
public async Task<ActionResult<IEnumerable<User>>> GetUsers()
{
return await _context.Users.ToListAsync();
}
据我所知,这会返回一个 User 对象列表,这些对象被序列化为 JSON 并作为一个大 JSON 数组返回给消费者。它是异步的,允许服务器在 EF 在后台查询数据库时服务其他请求。服务请求的管理由 ASP 和 ControllerBase 类在上游进行。
按照此处的示例:https://learn.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。
但是,这让我思考:这是最佳解决方案吗?如果我有 100 万个用户,但消费者只调用前 100 个用户,那么在 OData 开始查询仅 100 条记录以返回给消费者之前,获取操作是否会等待获取完整的用户 DbSet?我应该以 DbSet 的形式返回 IQueryable 吗?:
// GET: api/Users
[HttpGet]
[EnableQuery]
public ActionResult<IQueryable<User>> GetUsers()
{
return _context.Users;
}
由于操作不再异步,这是否会改变传统 API 调用或 OData 调用?是否有其他最佳或推荐的解决方案来返回可跨传统 API 和 OData API 运行的查询?
最佳答案
IQueryable 和 IEnumerable 之间存在巨大差异。
IQueryable 是一个允许 LINQ to SQL 的接口(interface),这意味着它将在数据库中运行筛选的查询,而 IEnumerable 是 LINQ to Object,这意味着它在数据库中执行查询,然后在内存中过滤掉。
例如,就您而言
public async Task<ActionResult<IQueryable<User>>> GetUsers()
{
return await _context.Users;
}
这将从数据库返回所有用户,因此 IQueryable 和 IEnumerable 之间没有太大区别,但正如您提到的,您有 100 万条记录,而您只需要 100 条记录,那么您的查询将变为
public async Task<ActionResult<IQueryable<User>>> GetUsers()
{
return await _context.Users.Take(100);
}
现在,返回 IEnumerable 将加载要加载到内存中的所有百万条记录,然后为您提供前 100 条记录,而 IQueryable 只会从数据库中获取 100 条记录。
关于c# - 适用于 ASP.NET Core 和 OData 的 REST Web API 中的 IQueryable、IEnumerable 和异步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72515393/