PagedList Sorted Edition

by mosessaur| 04 November 2008| 10 Comments

Me and Amr Elsehemy are working together in something and he requested a feature in some APIs I built. In fact he liked the Rob Conery's PagedList that had been modified by Troy Goode. He used it on his jBlogMVC post series about building Blog Engine using MVC.

That was pretty simple and I noticed something missing on the PagedList that I wished to add! What about sorting. I mean build a PagedList that is sorted. So I made slight changes to the enhanced PagedList made by Troy to support sorting.

Prerequisites:

It is required that you refer to Rob Conery's PagedList and the modified version by Troy Goode before you proceed in order to understand how this PagedList is useful and helpful with MVC and LINQ to SQL as well as LINQ to Entities.

Summary of changes:

To summarize the changes I made, simply I used Lambda Expressions to enable sorting. And had to modify Class declaration (with constructors) and the Initialize method. Sorting is provided by OrderBy extension method. Please return to method documentation for more details.

SortedPagedList Implementation:

Troy enhanced an interface called IPagedList introduced in Rob's post. So I am going to build a class  SortedPagedList and implement IPagedList interface. For interface implementation kindly refer to the source code attached and for further explanation refer to Troy's post:

public interface IPagedList<T> : IList<T>
{
 int PageCount { get; }
 int TotalItemCount { get; }
 int PageIndex { get; }
 int PageNumber { get; }
 int PageSize { get; }
 bool HasPreviousPage { get; }
 bool HasNextPage { get; }
 bool IsFirstPage { get; }
 bool IsLastPage { get; }
}

public class SortedPagedList<T, TResult> : List<T>, IPagedList<T>
{
	public SortedPagedList(IEnumerable<T> source, int index, int pageSize, 
			System.Linq.Expressions.Expression<Func<T, TResult>> keySelector, bool asc)
	{
		if( source is IQueryable<T> )
			Initialize( source as IQueryable<T>, index, pageSize, keySelector, asc );
		else
			Initialize(source.AsQueryable(), index, pageSize, keySelector, asc);
	}

	public SortedPagedList(IQueryable<T> source, int index, int pageSize, 
			System.Linq.Expressions.Expression<Func<T, TResult>> keySelector, bool asc)
	{
		Initialize(source, index, pageSize, keySelector, asc);
	}
}

As you noticed I am using predicate Expression<Func<T,TRestult>> function in the constructor declaration and on Initialize method call. Basically this predicate is a strongly typed lambda expression to test each element for a condition. You can pass a Lambda Expression here. So the usage would be like this:

SortedPagedList prods=SortedPagedList<T,TResult>(source,index,pageSize,p=>p.Price,true);

The last parameter is to specify if you want to sort Ascending or Descending.

Initilaize method implementation is the same but it has a slight changes as the following:

protected void Initialize(IQueryable<T> source, int index, int pageSize, 
			System.Linq.Expressions.Expression<Func<T, TResult>> keySelector, bool asc)
{
   // Method code omitted......
   //### add items to internal list
   if (TotalItemCount > 0)
   {
	if (asc)
	{
	  AddRange( source.OrderBy(keySelector).Skip(index * pageSize).Take(pageSize));
	}
	else
	{
	  AddRange(source.OrderByDescending(keySelector).Skip(index * pageSize).Take(pageSize));
	}
   }
}

Attached source code include a test class made with xUnit.Net. Also I've tested it against LINQ to Entities and I might post a sample using it soon so keep tuned.

kick it on DotNetKicks.com

Comments (10) -

Emad Ibrahim
Emad Ibrahim United States on 10/24/2008 3:05 AM I just wrote code to sort a paged list but I used dynamic linq instead.  I used the Dynamic LINQ Library which is downloadable from MSDN and then just wrote my expression like

repository.Get().OrderBy(fieldname + ' ' + sortDir).ToPagedList();

I had to do that because I wanted users to click on a grid header to sort the data which will then retrieve one page of the grid sorted, so I couldn't use strongly type linq expressions.  

If dynamic LINQ is not a requirement then this is a good implementation.  Good job.

PS: I might post my solution soon (if I have time).
mosessaur
mosessaur Egypt on 10/24/2008 5:47 AM @Emad Ibrahim Thank you for the comment and for poiting out the Dynamic LINQ. Could you please submit a link to the Library. I never looked at it actually. Hope you will have time to post about it Emad. Sound like all of us have no time to do anything these days.
Janko
Janko Serbia on 10/24/2008 9:33 AM Great article. Too bad I haven't played with LINQ that much (yet).
mosessaur
mosessaur Egypt on 10/24/2008 7:55 PM @Janko I guess none of us got time to look at the things he/she interested in. I want to play with some silverlight, but I got no time Smile Are we lazy?! ;)
Ray
Ray United States on 10/25/2008 10:55 AM Dynamic link is part of some linq examples on msdn: msdn.microsoft.com/en-us/vcsharp/bb894665.aspx However if you're just after sorting by string column/property name then this does the job: technoesis.wordpress.com/.../
mosessaur
mosessaur Egypt on 10/26/2008 6:13 AM @Ray Thank you for Dynamic LINQ download link. I should try it and maybe modify this sample with another edition that is using Dynamic LINQ.
Not sure if this will work with LINQ to Entities or not, myself had hard times with LINQ to Entities not supporting manythings.
Another thing that I might found intereting is the performance, already LINQ to SQL or LINQ to Entities spend sometime building Dynamic SQL that is why CompiledQueries is there. Not sure how far Dynamic LINQ will affect the performance.
I should try it anyway.
Daniel
Daniel United States on 10/27/2008 11:33 PM One thing I've never quite gotten about PagedList:  Shouldn't it be PagedEnumerable?  You're never going to call Add() or Delete() on the list.
mosessaur
mosessaur Egypt on 10/29/2008 11:01 PM @Daniel Yes that makes sense actually. I should look at that. But for the time being it can be like that Smile
Confused
Confused United Kingdom on 12/10/2008 1:43 AM This is an interesting concept and illustrates well how a linq key selector can be passed as a parameter. BEWARE however that this won't help you embed sort expressions into your web page in the same way that PagedList did for paging. In fact it doesn't really add any more functionality over doing a .OrderBy(...).ToPagedList () with the original PagedList class Smile

Would be nice to have an equivalent implementation of sorting. I guess that would involve serializing the linq expressions to/from a form that could be displayed on a web page.




This article highlights nicely the feature of being able to pass methods  method of passing A useful Interesting method of passing
Michael
Michael Denmark on 7/1/2009 9:39 AM Thanks a lot for this post

Pingbacks and trackbacks (3)+

Comments are closed