SingingEels : Development Community & Resource

Login

Articles

  • ADO.NET (2)
  • ASP.NET (36)
  • LINQ (5)
  • Security (2)
  • Silverlight (3)
  • SQL (7)
  • Standards (5)
  • WCF (2)

Syndication

  • Articles RSS
  • Blogs RSS

Contribute

  • Our Authors List
  • Member Sign-Up
  • Suggestions Box

Dynamic LINQ OrderBy using String Names!

(Mar 26 2008 - 07:34:31 AM by Timothy Khouri) - [print blog post]

Quick Overview of LINQ and Lambda Expressions

LINQ is a new enhancement to the .NET framework (version 3.5 and up) that gives powerful query capabilities against any enumerable object. This means that no matter what the data source (whether SQL, XML, or objects such as a generic list or ArrayList) you can do things like sorting (OrderBy), selecting, joining etc.

If you're not already familiar with LINQ, then you can Learn the Basics of LINQ from that article. Also, to appreciate this new gem that I discovered (actually, I've been trying to do this since I first started using LINQ), you'll need to understand lambda expressions with LINQ.

How To Sort using LINQ and Lamdba

First, let's look at a quick example of a data source that you would possibly want to sort, perhaps in a GridView. For the sake of simplicity, I'm just going to populate a generic list in code. If the code that I'm using looks funny, it's probably because you're not familiar with automatic properties (a new C# 3 only feature), lambda (a new language feature in C# 3 and VB9) or anonymous types.

Try not to get lost in the code about how to build my person class. The good stuff is at the end with the dyanmic LINQ! Here is my basic "Person" class that will hold our data:

public class Person
{
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public DateTime DateOfBirth { get; set; }
}

Now I'll create a list with 3 people in there. Then I'll show how to sort it using regular old LINQ. After that, I'll show you how to make your own Expression Tree to dynamically sort it using LINQ (it's exciting)! By the way, it took a lot of reverse engineering and reflecting to figure this out... and in case you're wondering, this is NO WHERE else on the internet right now.

// Here's my list that I am going to sort.
List<Person> people = new List<Person>();

people.Add(new Person { FirstName = "Moses",
   LastName = "McRoses",
   DateOfBirth = new DateTime(1801, 1, 23) });

people.Add(new Person { FirstName = "Timothy",
   LastName = "Khouri",
   DateOfBirth = new DateTime(1985, 6, 20) });

people.Add(new Person { FirstName = "Jonathan",
   LastName = "Carter",
   DateOfBirth = new DateTime(1984, 6, 12) });

As you can see, our list has 3 people that are not in any particular order. Now, I'll sort them by age:

// To do this, you have to have using System.Linq and must
// reference the System.Core assembly.


Person[] sortedPeople = people.OrderBy(person =>
   person.DateOfBirth).ToArray();

That was simple enough. But what if you bound your "people" list to a GridView that had sorting turned on. The problem here is that you are going to get a STRING that is the NAME of the field that the user wants to sort by. So what do we do?

// This won't work!

Person[] sortedPeople = people.OrderBy(person =>
   "DateOfBirth").ToArray();

The reason why the above won't work is because you're trying to sort by a literal string "DateOfBirth". Since "DateOfBirth" and "DateOfBirth" and "DateOfBirth" are all the same words, then LINQ will ignore this OrderBy alltogether. To achieve what we want, you have to create your own expression tree.

// First we define the parameter that we are going to use
// in our OrderBy clause. This is the same as "(person =>"

// in the example above.

var param = Expression.Parameter(typeof(Person), "person");

// Now we'll make our lambda function that returns the

// "DateOfBirth" property by it's name.

var mySortExpression = Expression.Lambda<Func<Person, object>>(Expression.Property(param, "DateOfBirth"), param);

// Now I can sort my people list.

Person[] sortedPeople = people.OrderBy(mySortExpression).ToArray();

Dynamic Expression Explaination

The code sample above does exactly what the original lambda expression was doing. The reason why I chose to do "Person, object" for my types instead of "Person, DateTime" is because if this was truely dynamic, I wouldn't know the data type of the column being sorted.

Actually, I should mention that I also wouldn't know the "Person" datatype, so I'd have to use "object, object"... but I'm not going to get into that right now as you'd have to do a pretty hefty chunk of reflection to get the right parameters.

The more I look into LINQ and expression trees, the more I like it. This stuff may look daunting at first, but when you "get it", you'll really see and appreciate the power it brings.

  • Jul 17 2008 - 12:23:33 PM Tawl

    This is a great article Tim and exactly what I was looking for to sort out the sorting (pun intended) on my LINQ data layer. However, I think there are limitations. The lamda function can only cast object-based properties, so if you try and sort on a DateTime, Int32, Guid etc, you get an invalid argument exception, e.g.

    System.ArgumentException: Expression of type 'System.DateTime' cannot be used for return type 'System.Object'

    I've been trying to find a way to use reflection to determine the property type based of the string property name, then pass this type to the lamda expression so it is always casting correctly, but I can't find a way to get it to work. Have you had any issues with this?

  • Jul 17 2008 - 01:09:38 PM Tawl

    Actually I just found an alternative solution - see http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

  • Jul 17 2008 - 04:11:38 PM Timothy Khouri

    I ran into the same wall for a while, and also tried using reflection to solve the issue... I eventually succeeded :)

    http://www.singingeels.com/Articles/Self_Sorting_GridView_with_LINQ_Expression_Trees.aspx

You must be logged in to add comments. If you have not already done so, you can create an account here. If you already are a member, you first need to login before you can comment.

Developer / Architect / Author

Blog Archives

  • June 2009 - (1)
  • January 2009 - (1)
  • November 2008 - (1)
  • October 2008 - (2)
  • September 2008 - (2)
  • August 2008 - (3)
  • July 2008 - (1)
  • June 2008 - (3)
  • May 2008 - (2)
  • April 2008 - (2)
  • March 2008 - (4)
  • February 2008 - (2)
  • December 2007 - (2)
  • November 2007 - (1)
  • October 2007 - (4)
  • September 2007 - (9)
  • August 2007 - (7)

Related Ads

SingingEels.com as of Mar 15 2010 - 02:59:21 PM - (0.0937536)