Open Mek7 opened 9 months ago
Hi, since the LINQ methods in IQueryable
for OData are only constructing the query string on the client side, there's no real benefit to leverage asynchronous operations until Execute
is called. Because of this, we suggest to use the LINQ methods, and then to create a new instance of DataServiceQuery<T>
calling ExecuteAsync
on that instance. We will add a helper method for this adapter, but until then, you can do something like this:
var queryable = container.ApplicationMessage.Where(a => a.Severity == ApplicationMessageSeverity.None);
var query = new DataServiceQuery<ApplicationMessage>(queryable.Expression, queryable.Provider as DataServiceQueryProvider);
var result = await query.ExecuteAsync();
Thank you, this really helped. To make it easier to use, I implemented an extension method. Maybe it helps someone else.
using Microsoft.OData.Client;
/// <summary>
/// Extension of IQueryable with custom methods
/// </summary>
public static class QueryableExtensions
{
/// <summary>
/// Executes OData query that has been composed via LINQ
/// https://github.com/OData/odata.net/issues/2839
/// </summary>
/// <typeparam name="TSource">Type of current IQueryable instance</typeparam>
/// <param name="originalQuery"></param>
/// <returns></returns>
public static async Task<IEnumerable<TSource>> ExecuteODataQueryAsync<TSource>(this IQueryable<TSource> originalQuery)
{
var query = new DataServiceQuery<TSource>(originalQuery.Expression, originalQuery.Provider as DataServiceQueryProvider);
return await query.ExecuteAsync();
}
}
Calling odata query synchronously is possible by LINQ .Where and .FirstOrDefault call on the entity set IQueryable. Calling the same query with async/await is not possible using LINQ, but you have to call AddODataQueryOption and then write odata filter syntax as a string. Or is there a better way to convert sync queries to async queries? What is the recommended way to do it?
Assemblies affected
Microsoft.OData.Client 7.20
Reproduce steps
For the context of following steps, there is ApplicationMessage entity set that has a Get operation exposed on the server. The purpose of these queries is to filter on Severity property that is of type enum. Container is the proxy class generated from server metadata.
This works (sync call):
This does not work (async call) - probably because ToListAsync is an extension method of Entity Framework. There is an exception - The source IQueryable doesn't implement IAsyncEnumerable.
This works:
But it is very ugly having to compose OData query in a string like this. It would be best to leverage existing LINQ possibilities on the IQueryable and OData client would translate the query to OData query options.
Expected result
Something like this should work to make async query as simple as sync query:
Actual result
See above in Reproduce steps.