WebApi
WebApi copied to clipboard
OData PageResult method ignoring count parameter when using EnableQuery attribute
Lets assume you have the following function in an OData controller that calls
a stored procedure / function in Entity Framework and the the function has
"EnableQuery" attribute.
Also, assume that the stored procedure supports paging and will only return a
subset of data along with an output parameter that contains the "true total"
row count.
[HttpPost]
[EnableQuery]
public PageResult<SomeObject> SomeFunction(ODataQueryOptions<SomeObject> options, ODataActionParameters parameters)
{
// Get the paging settings from ODataActionParameters since they are not shown on the ODataQueryOptions. Maybe there will be some fix for this in the future.
int pageSize = (int)parameters["pageSize"];
int take = (int)parameters["take"];
int skip = (int)parameters["skip"];
int page = (int)parameters["page"];
// Apply page size settings
ODataQuerySettings settings = new ODataQuerySettings();
settings.PageSize = pageSize;
// Create a temp result set to hold the results from the stored procedure
var totalRows = new System.Data.Entity.Core.Objects.ObjectParameter("TotalRows", typeof(Int64));
var tempResults = db.SomeStoredProc(skip, take, totalRows).ToList(); // ToList is required or you will receive an enumeration more than once error on the PageResult
// Apply the query options. For now this is only needed to get the correct count since the options does not seem to contain the TOP / SKIP when using OData parameters.
IQueryable results = options.ApplyTo(tempResults.AsQueryable(), settings);
// Custom paging. EXAMPLE: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options
return new PageResult<SomeObject>(tempResults,
Request.ODataProperties().NextLink,
(Int64)totalRows.Value);
}
In the above code the "tempResults" returned 20 rows and the "totalRows" returned 100.
So PageResult received "100" as the count parameter but something under the hood change it back to "20".
I need so way of telling SQL to return "20" rows "which my stored procedure is already doing" and then telling the client / caller that there are more than 20 rows on the PageResult / "OData.Count".
If PageResult is modifying the overall "OData.Count" in the JSON returned to the client, then is there some other way of for custom paging?
Work Item Details
Original CodePlex Issue: Issue 2164 Status: Proposed Reason Closed: Unassigned Assigned to: Unassigned Reported on: Oct 22, 2014 at 6:21 PM Reported by: goroth Updated on: Oct 22, 2014 at 10:34 PM Updated by: danroth27
On 2014-10-23 01:35:29 UTC, goroth commented:
Found the problem. If I and "EnableQuery" to the function attribute then the "count" parameter does not work.
I still think the "count" parameter should return what I tell it to return even if I "EnableQuery" on my function.
On 2014-10-23 01:36:54 UTC, goroth commented:
EDIT: added correction. changed "and" to "add"
Found the problem. If I add "EnableQuery" to the function attribute then the "count" parameter does not work.
I still think the "count" parameter should return what I tell it to return even if I "EnableQuery" on my function.
Follow up to investigate if need to improve the implementation and updated the document. To ignore EnableQuery when there are ODataQueryOption exists.
Any fix or workaround for this? This is very annoying and time consuming
While awaiting the offical fix, I have found that creating my own EnableQuery attribute and overriding ApplyQuery to do nothing works.
// (So For e.g. you will get Top and Skip applied again on your results that have already had top and skip applied
// this is a workaround the disables client side queries until this is fixed.
// https://github.com/OData/WebApi/issues/159
public class EnableCustomQueryAttribute : EnableQueryAttribute
{
public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions)
{
return queryable;
}
}
I found the problem. In ODataResourceSetSerializer line 223: PageResult odataResourceSetAnnotations = resourceSetInstance as PageResult; if (odataResourceSetAnnotations != null)
the condition es always null. I cant create PageResult, only PageResult T
@corranrogue9 -- may be related to the count issues you have been looking into recently.