动态排序的LINQ查询

本文关键字:查询 LINQ 排序 动态 | 更新日期: 2023-09-27 18:11:55

我有一个查询,我需要有排序基于一个查询字符串参数。例如,如果排序参数是价格,查询需要改变价格。如果是评级,则将查询更改为按评级排序。

我知道PredicateBuilder可以做And和OR的东西,但我怎么做一个动态顺序linq查询

动态排序的LINQ查询

如果您确切地知道哪些是可用于排序的所有可能参数,则Jon的答案是最好的答案。但如果参数数量未知,则可以动态构建表达式。例句:

class Program
{
    static void Main(string[] args)
    {
        var people = new[]{
            new Person { Name = "David", Age = 40 },
            new Person { Name = "Maria", Age = 12 },
            new Person { Name = "Lucas", Age = 45 }
        }.AsQueryable();
        foreach (var p in people.OrderBy("Age"))
        {
            Console.Write(p.Name);
        }
    }
    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
}
static class IQueryableExtensions
{
    public static IQueryable<T> OrderBy<T>(this IQueryable<T> items, string propertyName)
    {
        var typeOfT = typeof(T);
        var parameter = Expression.Parameter(typeOfT, "parameter");
        var propertyType = typeOfT.GetProperty(propertyName).PropertyType;
        var propertyAccess = Expression.PropertyOrField(parameter, propertyName);
        var orderExpression = Expression.Lambda(propertyAccess, parameter);
        var expression = Expression.Call(typeof(Queryable), "OrderBy", new Type[] { typeOfT, propertyType }, items.Expression, Expression.Quote(orderExpression));
        return items.Provider.CreateQuery<T>(expression);
    }        
}

可以使用switch语句或类似的语句:

IQueryable<Foo> query = ...;
switch (orderByParameter)
{
    case "price":
        query = query.OrderBy(x => x.Price);
        break;
    case "rating":
        query = query.OrderBy(x => x.Rating);
        break;
    // etc
}

您也可以通过反射来实现,但假设您要排序的字段数量有限,这可能是最简单的方法。

关于@lontivero答案的扩展。

如果你想对多个项目进行升序和降序的动态排序,你可以做下面类似的事情。添加orderbydescent, ThenBy, thenbydescent方法

static class IQueryableExtensions
 {
     public static IQueryable<T> OrderBy<T>(this IQueryable<T> items, string propertyName)
     {
         var typeOfT = typeof(T);
         var parameter = Expression.Parameter(typeOfT, "parameter");
         var propertyType = typeOfT.GetProperty(propertyName).PropertyType;
         var propertyAccess = Expression.PropertyOrField(parameter, propertyName);
         var orderExpression = Expression.Lambda(propertyAccess, parameter);
         var expression = Expression.Call(typeof(Queryable), "OrderBy", new Type[] { typeOfT, propertyType }, items.Expression, Expression.Quote(orderExpression));
         return items.Provider.CreateQuery<T>(expression);
     }
     public static IQueryable<T> OrderByDescending<T>(this IQueryable<T> items, string propertyName)
     {
         var typeOfT = typeof(T);
         var parameter = Expression.Parameter(typeOfT, "parameter");
         var propertyType = typeOfT.GetProperty(propertyName).PropertyType;
         var propertyAccess = Expression.PropertyOrField(parameter, propertyName);
         var orderExpression = Expression.Lambda(propertyAccess, parameter);
         var expression = Expression.Call(typeof(Queryable), "OrderByDescending", new Type[] { typeOfT, propertyType }, items.Expression, Expression.Quote(orderExpression));
         return items.Provider.CreateQuery<T>(expression);
     }
     public static IQueryable<T> ThenBy<T>(this IQueryable<T> items, string propertyName)
     {
         var typeOfT = typeof(T);
         var parameter = Expression.Parameter(typeOfT, "parameter");
         var propertyType = typeOfT.GetProperty(propertyName).PropertyType;
         var propertyAccess = Expression.PropertyOrField(parameter, propertyName);
         var orderExpression = Expression.Lambda(propertyAccess, parameter);
         var expression = Expression.Call(typeof(Queryable), "ThenBy", new Type[] { typeOfT, propertyType }, items.Expression, Expression.Quote(orderExpression));
         return items.Provider.CreateQuery<T>(expression);
     }
     public static IQueryable<T> ThenByDescending<T>(this IQueryable<T> items, string propertyName)
     {
         var typeOfT = typeof(T);
         var parameter = Expression.Parameter(typeOfT, "parameter");
         var propertyType = typeOfT.GetProperty(propertyName).PropertyType;
         var propertyAccess = Expression.PropertyOrField(parameter, propertyName);
         var orderExpression = Expression.Lambda(propertyAccess, parameter);
         var expression = Expression.Call(typeof(Queryable), "ThenByDescending", new Type[] { typeOfT, propertyType }, items.Expression, Expression.Quote(orderExpression));
         return items.Provider.CreateQuery<T>(expression);
     }
 }