WebApi icon indicating copy to clipboard operation
WebApi copied to clipboard

OData PageResult method ignoring count parameter when using EnableQuery attribute

Open LianwMS opened this issue 10 years ago • 7 comments

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

LianwMS avatar Jan 12 '15 02:01 LianwMS

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.

LianwMS avatar Jan 12 '15 02:01 LianwMS

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.

LianwMS avatar Jan 12 '15 02:01 LianwMS

Follow up to investigate if need to improve the implementation and updated the document. To ignore EnableQuery when there are ODataQueryOption exists.

LianwMS avatar Jan 13 '15 07:01 LianwMS

Any fix or workaround for this? This is very annoying and time consuming

egbertn avatar Jul 21 '17 12:07 egbertn

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;
        }
    }

graemechristie avatar Apr 15 '19 05:04 graemechristie

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

pakico avatar Mar 16 '22 19:03 pakico

@corranrogue9 -- may be related to the count issues you have been looking into recently.

mikepizzo avatar Mar 16 '22 19:03 mikepizzo