I've been looking around to find an answer to this question, but I can't seem to find any definitive answer. We use OData v4, using ODataQueryOptions.ApplyTo to apply the OData options to a query. We also use ODataQuerySettings to set the pagesize. When we set a page size, we cannot use ToListAsync() anymore on the IQueryable that is returned from ODataQueryOptions.ApplyTo. The error message says that the provider of the IQueryable is no longer from Entity Framework.
I found this is because when using a pagesize, OData resolves the IQueryable by passing it through a TruncatedCollection. This TruncatedCollection retrieves all (pagesize + 1) results from the database to check if there were more than pagesize results. However, ApplyTo is not an async method, so I can safely assume this database query is not performed asynchronously.
Is there something I can do to make sure the query is performed asynchronously? Surely the OData team has thought of this? Or is it fine to keep it synchronous as it is? To me it seems asynchronous IO is nearly a necessity nowadays, as we want our API to scale well and not have all our threads blocked while waiting for IO.
Thanks for the help!
Edit 1:
I was asked to give some code to explain what I mean.
In 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));
}
}
In 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);
}
}
As I said above though, the issue is in the underlying code of ApplyTo. This is a method from OData itself. The line:
IQueryable result = options.ApplyTo(query, DefaultSettings);
already executes the database query, due to the fact that we define a pagesize in the DefaultSettings. Defining a pagesize causes the underlying code in ApplyTo to retrieve all the data from the database, and then returns the retrieved list as a queryable. This means the database is queried in a synchronous function.
So, my question is: Is there a way to implement paging into OData without giving up on async reads? Or am I overcomplicating things when attempting to do this?