Call OrderBy() with a field name as a string

c# entity-framework linq

Accepted Answer

Thank to everybody. Rob, I think the answer you came up with was quite similar to mine.

Using your suggestions, I conducted additional research and discovered Marc Gravel's response here, OrderBy using dynamic LINQ on an IEnumerableT> (second post).

As an extra bonus, it imparted dynamics.

0
5/23/2017 12:31:37 PM

Popular Answer

This will function:

public static class LinqExtensions 
{
    private static PropertyInfo GetPropertyInfo(Type objType, string name)
    {
        var properties = objType.GetProperties();
        var matchedProperty = properties.FirstOrDefault (p => p.Name == name);
        if (matchedProperty == null)
            throw new ArgumentException("name");

        return matchedProperty;
    }
    private static LambdaExpression GetOrderExpression(Type objType, PropertyInfo pi)
    {
        var paramExpr = Expression.Parameter(objType);
        var propAccess = Expression.PropertyOrField(paramExpr, pi.Name);
        var expr = Expression.Lambda(propAccess, paramExpr);
        return expr;
    }

    public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> query, string name)
    {
        var propInfo = GetPropertyInfo(typeof(T), name);
        var expr = GetOrderExpression(typeof(T), propInfo);

        var method = typeof(Enumerable).GetMethods().FirstOrDefault(m => m.Name == "OrderBy" && m.GetParameters().Length == 2);
        var genericMethod = method.MakeGenericMethod(typeof(T), propInfo.PropertyType);     
        return (IEnumerable<T>) genericMethod.Invoke(null, new object[] { query, expr.Compile() });
    }

    public static IQueryable<T> OrderBy<T>(this IQueryable<T> query, string name)
    {
        var propInfo = GetPropertyInfo(typeof(T), name);
        var expr = GetOrderExpression(typeof(T), propInfo);

        var method = typeof(Queryable).GetMethods().FirstOrDefault(m => m.Name == "OrderBy" && m.GetParameters().Length == 2);
        var genericMethod = method.MakeGenericMethod(typeof(T), propInfo.PropertyType);     
        return (IQueryable<T>) genericMethod.Invoke(null, new object[] { query, expr });
    }
}

Testing:

var r = new List<temp> { 
    new temp { a = 5 }, 
    new temp { a = 1 }, 
    new temp { a = 15 }
}.OrderBy("a");

provides the appropriate outcome (1, 5, 15) and lazy execution for use with EF.

If necessary, you must use the overloads.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow