EF orderby / thenby combo extension method
c#, entity-framework, linq, linq-expressions, linq-to-entities
Solution
When you return a value type (such as `int` or `DateTime`) from a lambda expression that returns `object`, the compiler generates a `Box()` call to turn the value type into a boxed object.
The Entity Framework expression parser can't handle this box expression. The only solution is to pass a strongly-typed lambda expression that returns the value type.
To do that, you can mis-use collection initializers:
public class OrderingCollection<TEntity> : IEnumerable {
public void Add<TProperty>(Expression<Func<TEntity, TProperty>>) {
...
}
}
public static IQueryable<T> Sort<T>(this IQueryable<T> entities,
OrderingCollection<T> o) where T : class {
...
}
q = q.Sort(new OrderingCollection { s => s.ProductName, s => s.OrderDate });
Collection initializers allow you to use type inference with an arbitrary number of different type parameters.
Problem
I want to be able to apply combo `firstby / thenby` sorting as follows: ``` allOrders().sort(s => s.ProductName, s => s.OrderDate) ``` So using this post as inspiration, I wrote this extension method, which compiles fine: ``` public static IQueryable<T> sort<T>(this IQueryable<T> entities, params Expression<Func<T, object>>[] predicates) where T : class { var sorted = entities.OrderBy(predicates[0]); for (int i = 1; i < predicates.Length; i++) sorted = sorted.ThenBy(predicates[i]); return sorted; } ``` And I also tried this succint version, which also compiles: ``` public static IQueryable<T> sort<T>(this IQueryable<T> entities, params Expression<Func<T, object>>[] predicates) where T : class { return predicates.Skip(1).Aggregate( entities.OrderBy(predicates[0]), (aggregate, currentPredicate) => aggregate.ThenBy(currentPredicate)); } ``` However if I try sort by a `DateTime`, I get this exception: Unable to cast the type 'System.DateTime' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types. What am I doing wrong? I am using EF5.