如何在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); }