Entity Framework dynamic sorting

I have a fairly common requirement to enable user-defined sorting, for example using a querystring like so:

?page=2&sort=name&desc=true

This isn’t really catered for using LINQ, due to type-safety (you need to use an expression based on a property of your object to do sorting). To enable dynamic sorting on an IQueryable object, try this:

private static readonly MethodInfo OrderByMethod =
    typeof(Queryable).GetMethods()
    .Where(method => method.Name == "OrderBy")
    .Where(method => method.GetParameters().Length == 2)
    .Single();

private static readonly MethodInfo OrderByDescendingMethod =
    typeof(Queryable).GetMethods()
    .Where(method => method.Name == "OrderByDescending")
    .Where(method => method.GetParameters().Length == 2)
    .Single();

public static IQueryable DynamicOrderBy(this IQueryable source, string sortBy, bool sortDescending = false)
{
    if (string.IsNullOrWhiteSpace(sortBy))
        return source;

    if (sortBy.Contains(','))
    {
        foreach (var sort in sortBy.Split(','))
        {
            source = source.DynamicOrderBy(sort, sortDescending);
        }

        return source;
    }
    else
    {
        var type = typeof(TSource);
        var parameter = Expression.Parameter(type, sortBy);
        var propertyRef = Expression.Property(parameter, sortBy);
        var lambda = Expression.Lambda(propertyRef, new[] { parameter });

        MethodInfo genericMethod = (sortDescending ? OrderByDescendingMethod : OrderByMethod)
            .MakeGenericMethod(new[] { typeof(TSource), propertyRef.Type });
        object ret = genericMethod.Invoke(null, new object[] { source, lambda });

        return (IQueryable)ret;
    }
}

Putting this in your code allows you to write something like this:

IQueryable data = GetData();
var sortedByNameDescending = data.DynamicOrderBy("Name", true);
Advertisements