Add Sort Extension by Column name

Aug 14, 2014 at 8:38 AM
Edited Aug 14, 2014 at 8:39 AM
I try to make the sort by Column Name and direction by Boolean, because this is send from client with Grid. I don't know about another available function in EF6 or something else. Please show me if there is better code for that.
But I test this and it work, except I don't check when column is empty. This must be check in your BLL with a default column sort.

Just add this class into Repository.Pattern.Ef6, I think that place is suite:
   public static class OrderHelper
    {
        private static IOrderedQueryable<T> OrderingHelper<T>(IQueryable<T> source, string propertyName, bool descending, bool anotherLevel)
        {
            ParameterExpression param = Expression.Parameter(typeof(T), string.Empty); // I don't care about some naming
            MemberExpression property = Expression.PropertyOrField(param, propertyName);
            LambdaExpression sort = Expression.Lambda(property, param);

            MethodCallExpression call = Expression.Call(
                typeof(Queryable),
                (!anotherLevel ? "OrderBy" : "ThenBy") + (descending ? "Descending" : string.Empty),
                new[] { typeof(T), property.Type },
                source.Expression,
                Expression.Quote(sort));

            return (IOrderedQueryable<T>)source.Provider.CreateQuery<T>(call);
        }

        public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName, bool descending = false)
        {
            return OrderingHelper(source, propertyName, descending, false);
        }

        public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string propertyName, bool descending = false)
        {
            return OrderingHelper(source, propertyName, descending, true);
        }
    }
And use in Services like example below that:
string orderBy = "Column1"; boolean descending = false;
base.Query().OrderBy(q => q.OrderBy(orderBy, descending))
       .SelectPage(page, pageSize, out totalCount);
Coordinator
Sep 12, 2014 at 11:25 PM
Thanks sphyhunter88, we'll review your contribution, and will let you know if this will be absorbed into the framework in anyway.
Marked as answer by lelong37 on 9/12/2014 at 3:25 PM
Feb 25, 2015 at 4:19 PM
I have something similar to that. Is this something you guys will include into the project?

Here is what I am using :
public static class QueryableExtensions
    {
        public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property, bool asc)
        {
            if (asc)
                return source.OrderBy(property);

            return source.OrderByDescending(property);
        }

        public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
        {
            return ApplyOrder<T>(source, property, "OrderBy");
        }

        public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
        {
            return ApplyOrder<T>(source, property, "OrderByDescending");
        }

        public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)
        {
            return ApplyOrder<T>(source, property, "ThenBy");
        }

        public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property, bool asc)
        {
            if (asc)
                return ThenBy(source, property);

            return ThenByDescending(source, property);
        }

        public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)
        {
            return ApplyOrder<T>(source, property, "ThenByDescending");
        }

        static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
        {
            string[] props = property.Split('.');
            Type type = typeof(T);
            ParameterExpression arg = Expression.Parameter(type, "x");
            Expression expr = arg;
            foreach (string prop in props)
            {
                // use reflection (not ComponentModel) to mirror LINQ
                PropertyInfo pi = type.GetProperty(prop, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
                if (pi == null) throw new InvalidOperationException("Ordering property not found " + prop);
                expr = Expression.Property(expr, pi);
                type = pi.PropertyType;
            }
            Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
            LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);

            object result = typeof(Queryable).GetMethods().Single(
                method => method.Name == methodName
                          && method.IsGenericMethodDefinition
                          && method.GetGenericArguments().Length == 2
                          && method.GetParameters().Length == 2)
                .MakeGenericMethod(typeof(T), type)
                .Invoke(null, new object[] { source, lambda });
            return (IOrderedQueryable<T>)result;
        }

    }
Aug 20, 2015 at 2:46 PM
Edited Aug 20, 2015 at 2:47 PM
Hello notretro, does/can your extension method support .dot notation for sorting by sub-items? For example:
customerList.OrderBy(Orders.Date", true)?
Where 'Orders' is a collection property of 'Customer' for example.