如何在实体框架中动态构造 Order By Expression? [英] How to construct Order By Expression dynamically in Entity Framework?

查看:16
本文介绍了如何在实体框架中动态构造 Order By Expression?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用以下方法构建Order By Expression.原始来源

它真的很光滑.缺点是它仅在 Property 为 string 类型时才有效.

It is really slick. The downside is it only works if Property is string type.

如何让它接受不同的属性类型而不为不同的数据类型创建一堆方法?

How can I make it to accept different Property type without creating a bunch of methods for different data types?

public static bool PropertyExists<T>(string propertyName)
{
    return typeof (T).GetProperty(propertyName, BindingFlags.IgnoreCase |
      BindingFlags.Public | BindingFlags.Instance) != null;
}

public static Expression<Func<T, string>> GetPropertyExpression<T>(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<T, string>>)Expression.Lambda(
        Expression.PropertyOrField(paramterExpression, propertyName), paramterExpression);
}

用法

// orderBy can be either Name or City.
if (QueryHelper.PropertyExists<Club>(orderBy)) 
{ 
   var orderByExpression = QueryHelper.GetPropertyExpression<Club>(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
} 

我目前的方法(if语句太多)

public static Expression<Func<TSource, TKey>> 
    GetPropertyExpression<TSource, TKey>(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<TSource, TKey>>) 
        Expression.Lambda(Expression.PropertyOrField(
           paramterExpression, propertyName), paramterExpression);
}

缺点是我最终会为每种数据类型编写大量 if 语句.

The downside is I end up with a lot of if statements for each datatype.

if (QueryHelper.PropertyExists<Club>(orderBy)) 
{
   if(orderBy == "CreateDate")
   {       
      var orderByExpression = GetPropertyExpression<Club, DateTime>(orderBy);
      ...
   }
   else if(orderBy == "Name" || orderBy == "City")
   {
      var orderByExpression = GetPropertyExpression<Club, string>(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<T>(this IQueryable<T> source, string propertyName)
    {
        return typeof(T).GetProperty(propertyName, BindingFlags.IgnoreCase |
            BindingFlags.Public | BindingFlags.Instance) != null;
    }

    public static IQueryable<T> OrderByProperty<T>(
       this IQueryable<T> 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<T>) ret;
    }

    public static IQueryable<T> OrderByPropertyDescending<T>(
        this IQueryable<T> 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<T>) ret;
    }
}

用法

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

这篇关于如何在实体框架中动态构造 Order By Expression?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆