Andrew Kibalnikov
Andrew Kibalnikov

Reputation: 73

Can't apply $select when using ODataQueryOptions

I am trying to implement querying to Sql Server via EF Core and OData(7.1.0).

Action method looks like follows:

[HttpGet]
public IEnumerable<UserInfoDto> Get(ODataQueryOptions ops)
{
     return this.service.GetUserInfos(ops);
}

Service code:

public List<UserInfoDto> GetUserInfos(ODataQueryOptions ops)
{
    using (var context = new EFContext())
    {
        var query = context.Users.Join(context.Customers, x => x.CustomerId, y => y.Id, (x, y) => new UserInfoDto
        {
            Id = x.Id,
            Name = x.Name,
            Age = x.Age,
            CustomerId = x.CustomerId,
            CustomerTitle = y.Title,
            CustomerDescription = y.Description
        });

        var result = ops.ApplyTo(query).Cast<UserInfoDto>().ToList();
        return result;
    }
}

Startup Configute method:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
     app.UseMvc(b => 
     {
         b.Count().Filter().OrderBy().Select().MaxTop(null);
         b.EnableDependencyInjection();
     });
}

However, when I am having $select in query (e.g https://localhost:5001/api/userinfos?$select=id), instead of projected result I am getting an error:

InvalidOperationException: No coercion operator is defined between types 'Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectSome`1[Oda taApp.UserInfoDto]' and 'OdataApp.UserInfoDto'.



What am I missing? Any help is appreciated.

Upvotes: 4

Views: 3814

Answers (1)

Rodrigo G Rodrigues
Rodrigo G Rodrigues

Reputation: 461

When you using $select query option for OData, you need an IQueryable of dynamic .

For example, imagine the following class:

public class Person {
    public int Id { get; set }
    public string Name { get; set; }
}

So, if you have a query without $select, the IQueryable will generate a collection of Person, with all properties (id and name) in each item.

But, if you use a $select=id query, each item will have only the ID property and you cant Cast a dynamic type to a Person type.

In other words, you cant use $select and return a List<UserInfoDto>, you need to return a List<dynamic> without the Cast method, just like this:

    var result = ops.ApplyTo(query) as IQueryable<dynamic>;
    return result.ToList();

EDIT:

the full implementation of method will be:

// changing the return type
public List<dynamic> GetUserInfos(ODataQueryOptions<UserInfoDto> ops)
{
    using (var context = new EFContext())
    {
        var query = context.Users.Include(Customers, x => x.CustomerId, y => y.Id, (x, y) => new UserInfoDto
        {
            Id = x.Id,
            Name = x.Name,
            Age = x.Age,
            CustomerId = x.CustomerId,
            CustomerTitle = y.Title,
            CustomerDescription = y.Description
        });
        // casting the applyto result
        var result = ops.ApplyTo(query) as IQueryable<dynamic>;
        return result.ToList();
    }
}

Upvotes: 3

Related Questions