In my ODATA-v4 controller, I have the following code:
var fn = reportModelBuilder.EntityType<CurrentTestResult>()
.Collection.Function("Breakdown").Returns<int>();
In the CurrentTestResultController.cs, I have the deceptively simple:
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
[HttpGet]
public IHttpActionResult Breakdown()
{
var count = dataService.GetAll()
.Select(x => x.TestResultTypeId)
.Distinct()
.Count();
return Ok(count);
}
Essentially, for all the CurrentTestResult entities in the collection, it returns the distinct TestResultTypeId occuring in the set. (This is a trivial operation, but I simplified a really life scenario that's much more complex)
That was easy to do - but I can't seem to first filter the collection of CurrentTestResult it should operate on.
This request, which by default operates on all CurrentTestResult entities
localhost/app/odatareport/CurrentTestResult/Default.Breakdown
returns
{
@odata.context: "http://localhost/app/odatareport/$metadata#Edm.Int32",
value: 5
}
(A correct result, there's 5 distinct types)
However, this request, which tries to simply filter it down first - fails
localhost/app/odatareport/CurrentTestResult/Default.Breakdown?$top=2
returns
{
error: {
code: "",
message: "The query specified in the URI is not valid. The requested resource is not a collection. Query options $filter, $orderby, $count, $skip, and $top can be applied only on collections.",
innererror: {
message: "The requested resource is not a collection. Query options $filter, $orderby, $count, $skip, and $top can be applied only on collections.",
type: "Microsoft.OData.ODataException",
stacktrace:
" at System.Web.OData.EnableQueryAttribute.ValidateSelectExpandOnly(ODataQueryOptions queryOptions) at System.Web.OData.EnableQueryAttribute.ExecuteQuery(Object response, HttpRequestMessage request, HttpActionDescriptor actionDescriptor, ODataQueryContext queryContext) at System.Web.OData.EnableQueryAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)"
}
}
}
As far as I understand the ODATA pipeline, why this fails makes sense. The controller method will return an IQueryable and then the ODATA $filter, $top, etc.. will be applied.
I would like a function to operate on a set that's already been filtered down.
Is what I am trying to do even possible?
I get that the Breakdown method itself has .GetAll() in it, but there mut be a way to apply the filtering before the method -
Otherwise, this is all quite pointless....