Return Paged Data from an IQueryable

Published on Friday, March 8, 2013

I finally broke down and wrote a standard extension method for IQueryable that returns a single “page” of data from a source set. This method is terminal if it is in an expression tree in that it returns an IEnumerable and not IQueryable. This method works by calling Count() to get the total number of records (which it sends back in the output parameter itemCount), and then uses the normal .Skip() and .Take() method to return a single page. It should work against any IQueryable including LINQ to SQL and Entity Framework sequences.

/// <summary>
/// Gets a single page of items from a sequence.
/// </summary>
/// <typeparam name="T">The data type of the result items.</typeparam>
/// <param name="query">The sequence</param>
/// <param name="pageNumber">The page number to retrieve, starting at 1.</param>
/// <param name="pageSize">The number of items in each page.</param>
/// <param name="pageCount">Provides the total number of pages available.</param>
/// <returns></returns>
public static IEnumerable<T> TakePage<T>(this IQueryable<T> query, int pageNumber, int pageSize, out int pageCount)
{
    int itemCount;
    return TakePage(query, pageNumber, pageSize, out pageCount, out itemCount);
}

/// <summary>
/// Gets a single page of items from a sequence.
/// </summary>
/// <typeparam name="T">The data type of the result items.</typeparam>
/// <param name="query">The sequence</param>
/// <param name="pageNumber">The page number to retrieve, starting at 1.</param>
/// <param name="pageSize">The number of items in each page.</param>
/// <param name="pageCount">Provides the total number of pages available.</param>
/// <param name="itemCount">Provides the total number of items availabe.</param>
/// <returns></returns>
public static IEnumerable<T> TakePage<T>(this IQueryable<T> query, int pageNumber, int pageSize, out int pageCount, out int itemCount)
{
    if (pageNumber < 1)
        throw new ArgumentException("The value for 'page' must be greater than or equal to 1", "pageNumber");

    itemCount = query.Count();

    pageCount = (int)Math.Ceiling((double)itemCount / (double)pageSize);

    if (pageNumber > pageCount)
        pageNumber = pageCount;

    if (pageNumber > 1)
        return query.Skip((pageNumber - 1) \* pageSize).Take(pageSize);
    else
        return query.Take(pageSize);
}