Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IOrderedQueryable Skip and Take

I have the following abstract class which all of my Repositories inherit from:

abstract class RepositoryBase<T> {
    void Add();
    void Delete();
    void SaveChanges();
}

I wanted to add another method for automatically paging an IQueryable<T> and returning a List<T> from the results:

protected List<T> Paginate(IQueryable<T> content, int? skip, int? take)
{
    if (skip.HasValue) content = content.Skip(skip.Value);
    if (skip.HasValue && take.HasValue) content = content.Take(take.Value);
    return content.ToList();
}

But, Skip requires that the source by IOrderedQueryable<T>. I tried changing the method signature to:

Paginate(IOrderedQueryable<T> content, int? skip, int? take)

But Skip returns an IQueryable<T> so I receive the error Cannot convert source type 'System.Linq.IQueryable<T>' to target type 'System.Linq.IOrderedQueryable<T>'

How do I force the implementing class to send my method an IOrderedQueryable<T> and get my paginate method to work?

like image 651
CodingIntrigue Avatar asked Feb 20 '26 05:02

CodingIntrigue


2 Answers

It sounds like you should might want to make Paginate still take an IOrderedQueryable<T> to validate at compile-time that you've started with something that's ordered - but you don't then need to assign back to the same variable. For example:

protected List<T> Paginate(IOrderedQueryable<T> content, int? skip, int? take)
{
    // Different variable type so that we can assign to it below...
    IQueryable<T> result = content;
    if (skip.HasValue) result = result.Skip(skip.Value);
    if (skip.HasValue && take.HasValue) result = result.Take(take.Value);
    return result.ToList();
}

And as Marc notes, it would probably be better to change the Take line to:

if (take.HasValue) result = result.Take(take.Value);
like image 94
Jon Skeet Avatar answered Feb 22 '26 20:02

Jon Skeet


The Queryable.Skip and Queryable.Take methods do not require this, but some providers (I'm thinking "EF" mainly) do insist on it; in which case the solution is simply: make sure the original query has an order. For example:

var query = {whatever}.OrderBy(x => x.Id); // identity column? why not...
var page = Paginate(query, ...);
like image 35
Marc Gravell Avatar answered Feb 22 '26 20:02

Marc Gravell



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!