如何在Entity Framework中动态构造Order By Expression?

我使用以下方法构造Order By Expression 。 原始来源

它真的很光滑。 缺点是它只适用于Property是字符串类型。

如何在不为不同数据类型创建一堆方法的情况下使其接受不同的Property 类型

public static bool PropertyExists(string propertyName) { return typeof (T).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) != null; } public static Expression<Func> GetPropertyExpression(string propertyName) { if (typeof(T).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) == null) { return null; } var paramterExpression = Expression.Parameter(typeof(T)); return (Expression<Func>)Expression.Lambda( Expression.PropertyOrField(paramterExpression, propertyName), paramterExpression); } 

用法

 // orderBy can be either Name or City. if (QueryHelper.PropertyExists(orderBy)) { var orderByExpression = QueryHelper.GetPropertyExpression(orderBy); clubQuery = clubQuery.OrderBy(orderByExpression); } else { clubQuery = clubQuery.OrderBy(c => c.Id); } 

问题

 public class Club { public int Id { get; set; } public string Name { get; set; } public string City { get; set; } public DateTime CreateDate { get; set; } <= this won't work } 

我当前的方法(如果声明太多)

 public static Expression<Func> GetPropertyExpression(string propertyName) { if (typeof (TSource).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) == null) { return null; } var paramterExpression = Expression.Parameter(typeof (TSource)); return (Expression<Func>) Expression.Lambda(Expression.PropertyOrField( paramterExpression, propertyName), paramterExpression); } 

缺点是我最终会为每种数据类型添加很多if语句。

 if (QueryHelper.PropertyExists(orderBy)) { if(orderBy == "CreateDate") { var orderByExpression = GetPropertyExpression(orderBy); ... } else if(orderBy == "Name" || orderBy == "City") { var orderByExpression = GetPropertyExpression(orderBy); ... } ... } else { clubQuery = clubQuery.OrderBy(c => c.Id); } 

我在Jon Skeet的老答案的帮助下找到了解决方案。

 public static class QueryHelper { private static readonly MethodInfo OrderByMethod = typeof (Queryable).GetMethods().Single(method => method.Name == "OrderBy" && method.GetParameters().Length == 2); private static readonly MethodInfo OrderByDescendingMethod = typeof (Queryable).GetMethods().Single(method => method.Name == "OrderByDescending" && method.GetParameters().Length == 2); public static bool PropertyExists(string propertyName) { return typeof(T).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) != null; } public static IQueryable OrderByProperty( this IQueryable source, string propertyName) { if (typeof (T).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) == null) { return null; } ParameterExpression paramterExpression = Expression.Parameter(typeof (T)); Expression orderByProperty = Expression.Property(paramterExpression, propertyName); LambdaExpression lambda = Expression.Lambda(orderByProperty, paramterExpression); MethodInfo genericMethod = OrderByMethod.MakeGenericMethod(typeof (T), orderByProperty.Type); object ret = genericMethod.Invoke(null, new object[] {source, lambda}); return (IQueryable) ret; } public static IQueryable OrderByPropertyDescending( this IQueryable source, string propertyName) { if (typeof (T).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) == null) { return null; } ParameterExpression paramterExpression = Expression.Parameter(typeof (T)); Expression orderByProperty = Expression.Property(paramterExpression, propertyName); LambdaExpression lambda = Expression.Lambda(orderByProperty, paramterExpression); MethodInfo genericMethod = OrderByDescendingMethod.MakeGenericMethod(typeof (T), orderByProperty.Type); object ret = genericMethod.Invoke(null, new object[] {source, lambda}); return (IQueryable) ret; } } 

用法

 string orderBy = "Name"; if (QueryHelper.PropertyExists(orderBy)) { query = query.OrderByProperty(orderBy); - OR - query = query.OrderByPropertyDescending(orderBy); }