繁体   English   中英

WebAPI OData v4查询不是异步?

[英]WebAPI OData v4 queries not async?

我一直在四处寻找这个问题的答案,但我似乎无法找到任何明确的答案。 我们使用OData v4,使用ODataQueryOptions.ApplyTo将OData选项应用于查询。 我们还使用ODataQuerySettings来设置pagesize 当我们设置页面大小时,我们不能再使用从ODataQueryOptions.ApplyTo返回的IQueryable上的ToListAsync()。 错误消息表明IQueryable的提供程序不再来自Entity Framework。

我发现这是因为在使用pagesize时 ,OData通过传递TruncatedCollection来解析IQueryable。 此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中定义了一个pagesize。 定义pagesize会导致ApplyTo中的底层代码从数据库中检索所有数据,然后将检索到的列表作为可查询返回。 这意味着在同步函数中查询数据库。

所以,我的问题是:有没有办法在不放弃异步读取的情况下实现对OData的分页? 或者在尝试这样做时我是否过于复杂?

可以在OData中实现分页而不放弃异步读取。 分页基本上意味着再向I​​Queryable实例应用一个表达式。 在调用IQueryable.Take之后,可以调用IQueryable.ToListAsync(实际上会发生枚举)。

但Microsoft Web Api OData v4实现是这样的,查询枚举是同步发生的。 看到这里 ODataQuerySettings.ApplyTo方法在内部使用TruncatedCollection。 TruncatedCollection继承自System.Collections.Generic.List,在创建时,它将IQueryable构造函数参数传递给List的构造函数 ,该构造函数接受IEnumerable,迭代它并复制到内部数组中。

因此,您可以分叉Web Api OData(因为它是开源的),调整它并使其异步。 或者实现您自己的ODataQuerySettings.ApplyTo版本,它将是异步的。

我不确定你为什么要调用ToListAsync() 应该没有必要。 在您的操作方法中,您应该编写查询,但不实际获取任何数据。 所有这一切都应该是微不足道的,不需要异步。 IQueryable稍后由框架执行。 (框架还应自动将查询字符串中的所有OData过滤器参数应用于您返回的查询, 包括分页 )。

事实上,拥有IQueryable类型的异步结果(或IEnumerable )是没有意义的( 参见这个答案 )。 您不能异步枚举。

理论上你可以异步地将所有结果都放入一个数组中,但Odata会将其过滤器应用于内存而不是查询。 我不确定你为什么要这样做,但是使用Odata的意义非常小。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM