【发布时间】:2016-06-25 10:34:50
【问题描述】:
我一直在四处寻找这个问题的答案,但我似乎找不到任何明确的答案。 我们使用 OData v4,使用 ODataQueryOptions.ApplyTo 将 OData 选项应用于查询。我们还使用 ODataQuerySettings 来设置 pagesize。当我们设置页面大小时,我们不能再对从 ODataQueryOptions.ApplyTo 返回的 IQueryable 使用 ToListAsync()。错误消息说 IQueryable 的提供者不再来自实体框架。
我发现这是因为当使用 pagesize 时,OData 通过将 IQueryable 传递给 TruncatedCollection 来解析它。此 TruncatedCollection 从数据库中检索所有 (pagesize + 1) 个结果,以检查是否有超过 pagesize 个结果。但是,ApplyTo 不是异步方法,所以我可以放心地假设这个数据库查询不是异步执行的。
我可以做些什么来确保异步执行查询吗? OData 团队肯定想到了这一点吗?还是可以保持同步?在我看来,现在异步 IO 几乎是必需品,因为我们希望 API 能够很好地扩展,并且在等待 IO 时不会阻塞所有线程。
感谢您的帮助!
编辑 1:
我被要求提供一些代码来解释我的意思。
在 BaseController.cs 中:
public class BaseController : ODataController
{
private static readonly ODataQuerySettings DefaultSettings = new ODataQuerySettings() { PageSize = 60 };
protected Task<IHttpActionResult> ODataResult<T>(IQueryable<T> query, ODataQueryOptions<T> options)
{
IQueryable result = options.ApplyTo(query, DefaultSettings);
return Task.FromResult(ODataOk(result));
}
}
在 CustomerController.cs 中:
public class CustomerController : BaseController
{
ICustomerService customerService;
public async Task<IHttpActionResult> Get(ODataQueryOptions<Customer> options)
{
var query = customerService.Query();
return await ODataResult(query, options);
}
}
正如我上面所说,问题出在 ApplyTo 的底层代码中。这是 OData 本身的一种方法。 行:
IQueryable result = options.ApplyTo(query, DefaultSettings);
由于我们在 DefaultSettings 中定义了页面大小,因此已经执行了数据库查询。定义页面大小会导致 ApplyTo 中的底层代码从数据库中检索所有数据,然后将检索到的列表作为可查询列表返回。这意味着在同步函数中查询数据库。
所以,我的问题是:有没有办法在不放弃异步读取的情况下实现对 OData 的分页?还是我在尝试这样做时过于复杂了?
【问题讨论】:
-
你能提供一些代码吗?根据您的解释,我认为在查询末尾添加
.AsQueryable()可能会解决问题 -
不确定您是要解决
IQueryable .ToListAsync问题还是要异步ODataQueryOptions.ApplyTo。 -
指定了我的问题并提供了我们的一些代码。可悲的是, AsQueryable() 不起作用。当 ApplyTo 返回时,数据已经从数据库中检索出来了。
-
我也被这个问题难住了。我认为症结在于,任何地方都没有可以利用的 IQueryableAsync 接口。 .ToListAsync() 是 EF 中的 IQueryable 扩展,我敢肯定 OData 的人不想耦合到 EF。如果只有一个他们可以共享的通用接口,比如 IQueryableAsync 或其他东西,这将允许提供者允许异步执行,并允许消费者调用它。事实上,我们的 Get 似乎必须同步,这很不幸,因为我们通常得到的不仅仅是 Save。
-
@AndriiLitvinov 在使用分页的时候肯定会枚举出来。当我自己查看源代码时,我就知道了这一点。我没有设法解决这个问题。解决它的唯一方法是编写我自己的 ApplyTo 实现,我不愿意花时间在上面。我们决定采用更简单的路线,简单地使用控制器上的 EnableQuery 属性,让 OData 完成它的工作。生成的 SQL 查询远非理想,但就这样吧。性能和可扩展性还不是我们关心的问题。
标签: c# entity-framework asynchronous asp.net-web-api odata