Home > Software engineering >  How to get an IOrderedQueryable<T> after calling Skip() and Take()?
How to get an IOrderedQueryable<T> after calling Skip() and Take()?

Time:12-16

I have a paging class that includes an ApplyFilter() method, which filters rows for the current page. Since paging generally only makes sense in sorted results, this method accepts and returns an IOrderedQueryable<T> (instead of just a IQueryable<T>).

I use it like this:

var query = DbContext.Items
            .Where(i => i.Value > 0)
            .OrderBy(i => i.SortColumn);

query = pagination.ApplyFilter(query);

But there's a problem with my ApplyFilter() method.

public IOrderedQueryable<T> ApplyFilter<T>(IOrderedQueryable<T> query)
{
    return query.Skip((CurrentPage - 1) * PageSize).Take(PageSize);
}

The Skip() and Take() methods both return an IQueryable<T>, so I get an error that the return value cannot be converted from IQueryable<T> to IOrderedQueryable<T>.

How can I use Skip() and Take() and still have an IOrderedQueryable<T>?

CodePudding user response:

You could do something cheesy, like

public IOrderedQueryable<T> ApplyFilter<T>(IOrderedQueryable<T> query)
{
    return query.Skip((CurrentPage - 1) * PageSize).Take(PageSize).OrderBy(i=>1);
}

At least for SQL Server the codegen was smart enough to ignore the OrderBy.

Or change the return type to IQueryable<T>, and don't reuse the query variable:

var q = db.Set<User>().OrderBy(u => u.id);
var q2 = ApplyFilter(q);

Or change the argument and return type to IQueryable<T> and throw an ArgumentException if someone passes one that isn't an IOrderedQueryable<T>

public IQueryable<T> ApplyFilter<T>(IQueryable<T> query)
{
    if (query is IOrderedQueryable<T> oq )
    {
        return oq.Skip((CurrentPage - 1) * PageSize).Take(PageSize);
    }
    else
    {
        throw new ArgumentException("Query must be IOrderdQueryable<T>");
    }
}
  • Related