动态排序的LINQ查询
本文关键字:查询 LINQ 排序 动态 | 更新日期: 2023-09-27 18:11:55
我有一个查询,我需要有排序基于一个查询字符串参数。例如,如果排序参数是价格,查询需要改变价格。如果是评级,则将查询更改为按评级排序。
我知道PredicateBuilder可以做And和OR的东西,但我怎么做一个动态顺序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);
}
}