Using Entity Framework 4, I'm trying to implement dynamic sorting based on a collection of member names. Basically, the user can select fields to sort and the order of the sorting. I've looked at expression tree examples and can't piece this together. Here are some details:
Collection of column names:
public List<string> sortColumns;
sortColumns = new List<string>();
/// Example subset of video fields. The collection will vary.
sortColumns.Add("Width");
sortColumns.Add("Height");
sortColumns.Add("Duration");
sortColumns.Add("Title");
The video class is defined as follows:
public class Video
{
public string Title { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public float Duration { get; set; }
public string Filename { get; set; }
public DateTime DateCreated { get; set; }
.
.
.
}
public List<Video> Videos;
What I would like to do is enumerate through the sortColumns collection to build an expression tree at run time. Also, the user could specify either ascending or descending sorting and the expression tree should handle either.
I tried the Dynamic LINQ library for VS 2008, but it doesn't appear to work in VS 2010. (I could be doing something wrong.)
The bottom line is I need an expression tree to dynamically sort the Videos collection based on user input. Any help would be appreciated.
Each node in an expression tree is an expression. For example, an expression tree can be used to represent mathematical formula x < y where x, < and y will be represented as an expression and arranged in the tree like structure. Expression tree is an in-memory representation of a lambda expression.
A particular form of a binary tree, known as binary expression tree is used to represent expressions. Operands are stored in leaves of a binary expression tree and operators are stored in non-leaf nodes.
First you need the OrderBy
extension method that @Slace wrote here. All credit to Slace for an awesome piece of code and by far the most difficult part of the solution! I made a slight modification for it to work with your specific situation:
public static class QueryableExtensions
{
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string sortProperty, ListSortDirection sortOrder)
{
var type = typeof(T);
var property = type.GetProperty(sortProperty);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExp = Expression.Lambda(propertyAccess, parameter);
var typeArguments = new Type[] { type, property.PropertyType };
var methodName = sortOrder == ListSortDirection.Ascending ? "OrderBy" : "OrderByDescending";
var resultExp = Expression.Call(typeof(Queryable), methodName, typeArguments, source.Expression, Expression.Quote(orderByExp));
return source.Provider.CreateQuery<T>(resultExp);
}
}
Create a method to sort the list. A couple of things to note in the method below:
List<string>
is converted to an IQueryable<string>
since Enumerable
operators don't take expression trees..
private void PrintVideoList(IEnumerable<string> sortColumns, ListSortDirection sortOrder)
{
var videos = this.GetVideos();
var sortedVideos = videos.AsQueryable();
foreach (var sortColumn in sortColumns.Reverse())
{
sortedVideos = sortedVideos.OrderBy(sortColumn, sortOrder);
}
// Test the results
foreach (var video in sortedVideos)
{
Console.WriteLine(video.Title);
}
}
You should then be able to use the method like this:
// These values are entered by the user
var sortColumns = new List<string> { "Width", "Title", "Height" };
var sortOrder = ListSortDirection.Ascending;
// Print the video list base on the user selection
this.PrintVideoList(sortColumns, sortOrder);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With