I want to get a list of distinct values from my OData endpoint. But distinct or group by isn't supported yet.
My URI query looks something like this
GET /odata/Products?$select=foo & $top=10 & $count=true & distinct=true
My Controller
[EnableQuery]
public IQueryable<FooBarBaz> Get(ODataQueryOptions<FooBarBaz> queryOptions, bool distinct)
{
//I've tried the following
return Repository.AsQueryable().Distinct();
// and
return Repository.AsQueryable().GroupBy(x => x.Foo);
// and
IQueryable query = queryOptions.ApplyTo(Repository.AsQueryable());
return query.Distinct(); // Can't call .Distinct() here
}
None work :(
The best solution to solve the problem by defining an collection Action on the resource.
First Step : configure the 'Distinct' action in WebApiConfig.cs
Second Step : Add the Action in FooBarBazsController.cs which returns the collection of distinct entities
Third Step : Add a static method which returns an Expression for groupby on the basis of Property Name.
Now Build the project and You can query the Resource like this
And can also use the $select and $expend like this
I hope this solve the problem. +1 if it do.
Because you have specified the EnableQuery attribute, you can use $apply to groupby your distinct fields, without having to add any custom functions or parameters, you get this for free out of the box:
This is simple OData v4 standard syntax that doesn't require any code modification to implement. Don't go changing each controller that you want to support a distinct query on, you can't know 100% in advance which controllers your client apps might want this functionality on, so use the functionality that is provided before you start customisations.
Of course there is a caveat to this approach that do not make it viable 100% of the time:
This may require you to include additional fields into your grouping statement and for some complex filtering the resultant dataset may not be satisfactory, in cases such as these we found it easier to support passing in an additional pre-filter parameter through HTTP header that can be applied to the query before the passed in query options are applied, note that this was only necessary because our filter conditions were tenancy and security related and so the resultant data set had many more duplicate entries if you ignored the security descriptors.
Just for fun, here is our custom GET function that applies the pre-filter if it is passed in:
The following is implemented in a base class so that we don't have it in each controller:
If nothing else, it's cheaper that trying to sell AdaptiveLINQ to your manager :)