benjrb
benjrb

Reputation: 826

Entity Framework: combining paging with Dynamic LINQ OrderBy

I am retriveing some data using Entity Framework like so:

var items = GetItems(storeNumber);

Sort(items);

Page(items);

return await items.ToListAsync();

I have these private helper methods:

private IQueryable<Item> GetItems(string storeNumber)
{
    return _dbContext.Items.Where(x => x.StoreNumber == storeNumber);
}

I sort the results using Dynamic LINQ.

private void Sort(IQueryable<Item> items, string fieldToSort, string sortDirection)
{
    items = items.OrderBy($"{fieldToSort} {sortDirection}");
}

In my Page method I get the exception

The method 'OrderBy' must be called before the method 'Skip'

private void Page(IQueryable<Item> items, int skip, int take)
{
    items = items.Skip(skip).Take(take);
}

I had suspected that the reason for the error was because items needs to be IOrderedQueryable<Item> but there is no overload for the Dynamic LINQ OrderBy which returns IOrderedQueryable<T>. If I extract the Sort and Page code into the same method, using var it's no longer an issue, it infers the type. The problem seems to be using the IQueryable interface when sorting and paging. Is there a way I can break up this logic into separate methods but still use Dynamic LINQ for sorting?

Any help is much appreciated.

Upvotes: 1

Views: 1178

Answers (1)

Akos Nagy
Akos Nagy

Reputation: 4350

You should return the newly constructed IQueryable from the Sort() and the Page() methods, just as you do for GetItems(). If you "rewrite" a parameter value inside a method like this, it has no effect on the value originally passed in to the parameter, because C# uses by-value parameter passing semantics

See this for more reference: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-parameters

Upvotes: 2

Related Questions