我喜欢@Mark Powell 的答案,但正如@ShuberFu 所说,它给出了错误LINQ to Entities only supports casting EDM primitive or enumeration types。
删除 var propAsObject = Expression.Convert(property, typeof(object)); 不适用于值类型的属性,例如整数,因为它不会隐式地将 int 装箱到对象。
使用来自 Kristofer Andersson 和 Marc Gravell 的想法我找到了一种使用属性名称构造 Queryable 函数的方法,并且它仍然适用于实体框架。我还包括了一个可选的 IComparer 参数。 注意: IComparer 参数不适用于实体框架,如果使用 Linq to Sql,则应省略。
以下适用于 Entity Framework 和 Linq to Sql:
query = query.OrderBy("ProductId");
@Simon Scheurer 这也有效:
query = query.OrderBy("ProductCategory.CategoryId");
如果您不使用实体框架或 Linq to Sql,这可行:
query = query.OrderBy("ProductCategory", comparer);
代码如下:
public static class IQueryableExtensions
{
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "OrderBy", propertyName, comparer);
}
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "OrderByDescending", propertyName, comparer);
}
public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "ThenBy", propertyName, comparer);
}
public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "ThenByDescending", propertyName, comparer);
}
/// <summary>
/// Builds the Queryable functions using a TSource property name.
/// </summary>
public static IOrderedQueryable<T> CallOrderedQueryable<T>(this IQueryable<T> query, string methodName, string propertyName,
IComparer<object> comparer = null)
{
var param = Expression.Parameter(typeof(T), "x");
var body = propertyName.Split('.').Aggregate<string, Expression>(param, Expression.PropertyOrField);
return comparer != null
? (IOrderedQueryable<T>)query.Provider.CreateQuery(
Expression.Call(
typeof(Queryable),
methodName,
new[] { typeof(T), body.Type },
query.Expression,
Expression.Lambda(body, param),
Expression.Constant(comparer)
)
)
: (IOrderedQueryable<T>)query.Provider.CreateQuery(
Expression.Call(
typeof(Queryable),
methodName,
new[] { typeof(T), body.Type },
query.Expression,
Expression.Lambda(body, param)
)
);
}
}