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