0

I have a WebAPI that is written in C# on the top of ASP.NET Core/5 framework.

I enabled odata for my API. I am trying to manually apply the odata filter, order by clause, select columns and the expands.

Here is how I am trying to manually build the query using the ODataQueryOptions

protected IQueryable<TModel> BuildQuery(ODataQueryOptions<TModel> queryOptions, ODataQuerySettings settings)
{
    IQueryable<TModel> query = DbSet;

    if (queryOptions.SelectExpand != null)
    {
        var queryable = queryOptions.SelectExpand.ApplyTo(query, settings);

        query = queryable.Cast<TModel>(); // this causes an error
    }

    if (queryOptions.Filter != null)
    {
        query = queryOptions.Filter.ApplyTo(query, settings) as IQueryable<TModel>;  // this works!
    }

    if (queryOptions.OrderBy != null)
    {
        query = queryOptions.OrderBy.ApplyTo(query); // this works!
    }

    return query;
}

Everything above works great up until I try to expand a navigation property. When I do I get the following error

System.InvalidOperationException: 'No coercion operator is defined between types 'Microsoft.AspNetCore.OData.Query.Wrapper.SelectAllAndExpand`1[MyModel]' and 'MyModel'.'

Is there some sort of mapping that I need to do when defining the IEdmModel to build the navigation relations?

How can I correctly convert/cast IQueryable<Microsoft.AspNetCore.OData.Query.Wrapper.SelectAllAndExpand<TEntity>> to IQueryable<TEntity>?

Here is the code behind SelectAllAndExpand

Jay
  • 1,168
  • 13
  • 41
  • probably a duplicate of https://stackoverflow.com/questions/55636167/cant-apply-select-when-using-odataqueryoptions/ you cant convert a selectexpand query to a defined model, you need to cast it to dynamic, imagine a LINQ expression when `query` is a IEnumerable, like `query.Select(t => new { t.Id, t.Name })` this query cannot be cast to IEnumerable, because it generates an anonymous dynamic type, the selectexpand does the same, so you need to change your method to consider an IQueryable return. – Rodrigo G Rodrigues Jan 25 '22 at 22:56

1 Answers1

0

You can't directly cast

var queryable = queryOptions.SelectExpand.ApplyTo(query, settings);

to IQueryable<TModel>, because it different type of object.

If there is no Projection (Select) or Expand - you will get a regular object, but after Projection and Expand - it's a completely different thing. Depending on your tasks, you should handle SelectAllAndExpand<TModel> or remove SelectExpand.ApplyTo(..).

Vladimir
  • 2,082
  • 1
  • 13
  • 27