Possible Duplicate:
Dynamic LINQ OrderBy
I'm using the Entity Framework and would like to create my own dynamic sorting method that will let you enter a string to do your sorting such as query.DynamicSort("Name, Age DESC")
.
I know MS has put out some dynamic linq code but it's more than I need and I'm trying to understand how to write a simplified version of it myself just for sorting.
I've had some luck in getting it to work for a single field...but when I try to sort by multiple fields I get the following error:
The parameter 'x' was not bound in the specified LINQ to Entities query expression.
Here's my code. Can anyone see where I've gone wrong and perhaps suggest some revisions? I'm weak on constructing expressions dynamically.
public static class DynamicQuery
{
private class SortField
{
public Expression Expression;
public bool Descending = false;
public Type Type;
}
public static IOrderedQueryable<T> DynamicSort<T>(this IQueryable<T> source, string sortOrder)
{
var fields = sortOrder.Split(',');
var sortFields = new List<SortField>();
ParameterExpression arg = null;
for (int i = 0; i < fields.Length; i++)
{
var sf = new SortField();
sortFields.Add(sf);
//Handle Descending Sort Fields
if (fields[i].EndsWith(" DESC", StringComparison.OrdinalIgnoreCase))
{
sf.Descending = true;
fields[i] = fields[i].Substring(0, (fields[i].Length - 5)); //Remove " DESC"
}
fields[i] = fields[i].Trim();
//Handle fields that have nested properties
var props = fields[i].Split('.');
sf.Type = typeof(T);
sf.Expression = arg = Expression.Parameter(sf.Type, "x"); //Create an x parameter of type T
foreach (string prop in props)
{
PropertyInfo pi = sf.Type.GetProperty(prop);
sf.Expression = Expression.Property(sf.Expression, pi);
sf.Type = pi.PropertyType;
}
}
//Now that we have the SortFields we can do the sorting
Expression queryExpr = source.Expression;
string methodAsc = "OrderBy";
string methodDesc = "OrderByDescending";
foreach (var sf in sortFields)
{
LambdaExpression lambda = Expression.Lambda(sf.Expression, arg);
queryExpr = Expression.Call(
typeof(Queryable), sf.Descending ? methodDesc : methodAsc,
new Type[] { source.ElementType, sf.Type },
queryExpr, Expression.Quote(lambda));
methodAsc = "ThenBy";
methodDesc = "ThenByDescending";
}
return (IOrderedQueryable<T>)source.Provider.CreateQuery(queryExpr);
}
}
Thanks very much.