user4071723
user4071723

Reputation:

Order by must be called before calling a skip

I'm getting an Error when trying to execute the skip method. The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip'.

I'm well aware that the orderby must be called prior to calling the skip and I am calling it prior to the skip in another function directly preceding the call.

AddOrderBy(AdvTitleResults, ColumnNumber, OrderByDesc);

var SearchTitles = AdvTitleResults.Skip(PageNum * NumberOfResults)
                                  .Take(NumberOfResults).ToList();

The order by function looks like this the default assures that it is always assigned:

private void AddOrderBy(IQueryable<Title> Results, int ColumnNumber, bool OrderByDesc)
{
    switch (ColumnNumber)
    {
        case 1:
            if (OrderByDesc)
                Results = Results.OrderByDescending(t => t.FK_ContentType);
           else
                Results = Results.OrderBy(t => t.FK_ContentType);
            break;
        case 2:
            if (OrderByDesc)
                Results = Results.OrderByDescending(t => t.TitleFullName);
            else
                Results = Results.OrderBy(t => t.TitleFullName);
            break;
        default:
            if (OrderByDesc)
                Results = Results.OrderByDescending(t => t.ID);
            else
                Results = Results.OrderBy(t => t.ID);
            break;
    }
}

Could anyone explain why this doesn't work?

Upvotes: 1

Views: 1683

Answers (1)

Selman Gen&#231;
Selman Gen&#231;

Reputation: 101701

Because you are not actually changing the AdvTitleResults, you are changing the value of your parameter. You need to use ref keyword to make it work:

AddOrderBy(ref AvTitleResults, ColumnNumber, OrderByDesc);

private void AddOrderBy(ref IQueryable<Title> Results, 
                        int ColumnNumber, 
                        bool OrderByDesc)

Or you can use the LINQ style and make it an extension method, and return the query:

private IOrderedQueryable<Title> AddOrderBy(this IQueryable<Title> Results, int ColumnNumber, bool OrderByDesc)
{
    switch (ColumnNumber)
    {
        case 1:
            if (OrderByDesc)
                return Results.OrderByDescending(t => t.FK_ContentType);
           else
                return Results.OrderBy(t => t.FK_ContentType);
            break;
        case 2:
            if (OrderByDesc)
                return Results.OrderByDescending(t => t.TitleFullName);
            else
                return Results.OrderBy(t => t.TitleFullName);
            break;
        default:
            if (OrderByDesc)
                return Results.OrderByDescending(t => t.ID);
            else
                return Results.OrderBy(t => t.ID);
            break;
    }
}

This way you can call it like any other LINQ method:

var SearchTitles = AdvTitleResults
      .AddOrderBy(ColumnNumber, OrderByDesc)
      .Skip(PageNum * NumberOfResults)
      .Take(NumberOfResults)
      .ToList();

Edit:

isn't IQueryable a class shouldn't this be pass by ref by default?

IQueryable<Title> is not a class but yes it's a reference type. But reference types are not actually passed by reference.When you pass a referece type, the reference value that your variable holds will be copied into a new variable.It's something like this:

string foo = "Foo";
string bar = foo; // copy foo's reference into bar

Now if you assign a new reference to bar it won't change the foo:

bar = "bar";

Because they are distinct variables that holds a reference to same address.But when you use ref keyword the reference value is not copied.Instead you can think like the variable itself is passed.That's the easiest way to understand that. I don't know how to reproduce this behaviour in C# syntax.

Upvotes: 2

Related Questions