Yulian
Yulian

Reputation: 6769

OData causes wrong ordering in ASP.NET Web API

I'm using OData with ASP.NET Web API because I want to take advantage of its $skip option by using it for paging on the client. However, I face an issue and I'm not sure whether it is a bug or I'm doing something wrong.

I have the following method:

[HttpGet]
[Route("api/people")]
[EnableQuery(PageSize = 10, AllowedQueryOptions = AllowedQueryOptions.Skip)]
public IHttpActionResult GetAll()
{
    // Declare a simple list of Person objects.
    // Every Person object has only 3 properties - Id, Name and DateCreated.
    var peopleList = new List<Person>();

    for (int i = 0; i < 50; i++)
    {
        // Create the list with example Person objects.
        // Start from new Person() { Id = 1, Name = "Person #1", DateCreated = Tomorrow.
        // Continue with Person() { Id = 2, Name = "Person #2", DateCreated = The Day After Tomorrow.
        // Do this till i == 50.
        peopleList.Add(new Person()
        {
            Id = (i + 1),
            Name = "Person #" + (i + 1),
            DateCreated = DateTime.Now.AddDays(i)
        });
    }

    // Get only those Person objects the Ids of which are prime numbers.
    // Order the list by the most recently added, meaning the one that has a most recent DateCreated value.
    var outputList = peopleList
        .Where(p => p.Id % 2 == 0)
        .OrderByDescending(p => p.DateCreated)
        .ToList();

    // Return the list from the method.
    return Ok(outputList);
}

So, written this way I expect that if I make a request to "api/people", I will get the 10 most recent (because of the PageSize = 10 option written in the EnableQuery attribute) People objects with prime Ids. However, the result that I get is:

[
    {
      "id": 2,
      "name": "Person #2",
      "dateCreated": "2015-11-06T10:48:09.1224206+02:00"
    },
    {
      "id": 4,
      "name": "Person #4",
      "dateCreated": "2015-11-08T10:48:09.1224206+02:00"
    },
    ...
    {
      "id": 20,
      "name": "Person #20",
      "dateCreated": "2015-11-24T10:48:09.1224206+02:00"
    }
]

If I exclude this line

[EnableQuery(PageSize = 10, AllowedQueryOptions = AllowedQueryOptions.Skip)]

I get the correct ordering but of course I'm getting the whole set of 50 Person objects, not just 10 as I want.

[
    {
      "id": 50,
      "name": "Person #50",
      "dateCreated": "2015-12-24T10:56:55.7456064+02:00"
    },
    {
      "id": 48,
      "name": "Person #48",
      "dateCreated": "2015-12-22T10:56:55.7456064+02:00"
    },
    ...
    {
      "id": 2,
      "name": "Person #2",
      "dateCreated": "2015-11-06T10:48:09.1224206+02:00"
    }
]

I don't want to let the client order the list, the only thing that I want is to ensure that the maximum size of the returned collection is 10 objects and that the client can specify the number of objects to be skipped (using the $skip option).

So, why is this thing happening like that and how can I fix it?

Upvotes: 2

Views: 1204

Answers (1)

Yulian
Yulian

Reputation: 6769

Okay, I found the solution here. It seems like I have to add EnableStableOrdering = false to my EnableQuery attribute like this:

Solution:

[EnableQuery(PageSize = 10, AllowedQueryOptions = AllowedQueryOptions.Skip, EnsureStableOrdering = false)]

Here's what EnableStableOrdering really does (got from source code):

Summary:

Gets or sets a value indicating whether query composition should alter the original query when necessary to ensure a stable sort order.

Returns:

A true value indicates the original query should be modified when necessary to guarantee a stable sort order. A false value indicates the sort order can be considered stable without modifying the query. Query providers that ensure a stable sort order should set this value to false. The default value is true.

As the default value of this option is true, I just had to set it to false.

Upvotes: 1

Related Questions