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