Sort using Expression builder

719 views Asked by At

I am trying to build generic sort method using Expressions. I came up with the following method. For some reasons the code is breaking at the statement when a nested property is used in the sort expression.

var sortExpression = Expression.Lambda<Func<T, object>>
                (Expression.Convert(Expression.Property(sortParam, sortColumn), typeof(object)), sortParam);


private static IQueryable<T> SortQuery<T>(IQueryable<T> query, string sortColumn)
    {
        if (!string.IsNullOrEmpty(sortColumn))
        {
            var sortParam = Expression.Parameter(typeof(T), "x");

            Expression expr = sortParam;
            foreach (var prop in sortColumn.Split('.'))
            {
                expr = Expression.PropertyOrField(expr, prop);
            }

            var sortExpression = Expression.Lambda<Func<T, object>>
                (Expression.Convert(Expression.Property(sortParam, sortColumn), typeof(object)), sortParam);

                return query.OrderBy(sortExpression);
         }
        return null;
      }

Any idea where I am doing it wrong ?

1

There are 1 answers

0
xanatos On

Try:

private static readonly MethodInfo OrderBy = (from x in typeof(Queryable).GetMethods()
                                              where x.Name == "OrderBy"
                                              let pars = x.GetParameters()
                                              where pars.Length == 2
                                              select x).Single();

private static IQueryable<T> SortQuery<T>(IQueryable<T> query, string sortColumn)
{
    if (!string.IsNullOrEmpty(sortColumn))
    {
        var sortParam = Expression.Parameter(typeof(T), "x");

        Expression expr = sortParam;

        foreach (var prop in sortColumn.Split('.'))
        {
            expr = Expression.PropertyOrField(expr, prop);
        }

        var lambda = Expression.Lambda(expr, sortParam);

        var orderBy = OrderBy.MakeGenericMethod(typeof(T), expr.Type);

        return (IQueryable<T>)orderBy.Invoke(null, new object[] { query, lambda });
    }

    return null;
}

You have to use reflection to invoke the Queryable.OrderBy. In general, casting to object doesn't work very well with Entity Framework/LINQ to SQL, so you can try it, but there is only a very little chance it will work.