EF orderby/thenby combo扩展方法

Bob*_*y B 5 c# linq linq-to-entities entity-framework linq-expressions

我希望能够应用firstby / thenby如下的组合排序:

allOrders().sort(s => s.ProductName, s => s.OrderDate)
Run Code Online (Sandbox Code Playgroud)

所以使用这篇文章作为灵感,我写了这个扩展方法,编译很好:

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;
}
Run Code Online (Sandbox Code Playgroud)

我也试过这个succint版本,它也编译:

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));
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试按a排序DateTime,我会得到以下异常:

无法将类型"System.DateTime"强制转换为"System.Object"类型.LINQ to Entities仅支持转换EDM原语或枚举类型.

我究竟做错了什么?我正在使用EF5.

SLa*_*aks 6

从返回的lambda表达式返回值类型(例如intDateTime)时object,编译器会生成一个Box()调用,将值类型转换为盒装对象.

Entity Framework表达式解析器无法处理此框表达式.
唯一的解决方案是传递一个返回值类型的强类型lambda表达式.

为此,您可能会误用集合初始值设定项:

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 });
Run Code Online (Sandbox Code Playgroud)

集合初始值设定项允许您使用具有任意数量的不同类型参数的类型推断.