gpt4 book ai didi

c# - 基于字段列表和 Asc/Desc 规则的 OrderBy

转载 作者:行者123 更新时间:2023-11-30 15:21:24 25 4
gpt4 key购买 nike

我有以下带有 OrderBy 参数的 List:

List<String> fields = new List<String> { "+created", "-approved", "+author" }

这将导致以下 Linq 查询:

IQueryable<Post> posts = _context.posts.AsQueryable();

posts = posts
.OrderBy(x => x.Created)
.ThenByDescending(x => x.Approved);
.ThenBy(x => x.Author.Name);

所以基本上规则是:

  1. 使用 OrderBy 中的第一项和 ThenBy 中的其他项。
  2. 当字段以 - 开头时使用降序,当以 + 开头时使用升序。

我的想法是:

OrderExpression expression = posts
.Add(x => x.Created, "created")
.Add(x => x.Approved, "approved")
.Add(x => x.Author.Name, "author");

因此表达式将帖子属性/子属性与字段中的每个键相关联。然后它将按如下方式应用:

posts = posts.OrderBy(expression, fields);

因此 OrderBy 扩展将遍历 OrderExpression 中的每个项目并应用规则 (1) 和 (2) 来构建查询:

posts = posts
.OrderBy(x => x.Created)
.ThenByDescending(x => x.Approved);
.ThenBy(x => x.Author.Name);

如何做到这一点?

最佳答案

接下来的类(class)将帮助您做到这一点。你可以找到内联代码的解释。

public static class MyClass
{
public static IQueryable<T> Order<T>(
IQueryable<T> queryable,
List<string> fields,
//We pass LambdaExpression because the selector property type can be anything
Dictionary<string, LambdaExpression> expressions)
{
//Start with input queryable
IQueryable<T> result = queryable;

//Loop through fields
for (int i = 0; i < fields.Count; i++)
{
bool ascending = fields[i][0] == '+';
string field = fields[i].Substring(1);

LambdaExpression expression = expressions[field];

MethodInfo method = null;

//Based on sort order and field index, determine which method to invoke
if (ascending && i == 0)
method = OrderbyMethod;
else if (ascending && i > 0)
method = ThenByMethod;
else if (!ascending && i == 0)
method = OrderbyDescendingMethod;
else
method = ThenByDescendingMethod;

//Invoke appropriate method
result = InvokeQueryableMethod( method, result, expression);
}

return result;
}

//This method can invoke OrderBy or the other methods without
//getting as input the expression return value type
private static IQueryable<T> InvokeQueryableMethod<T>(
MethodInfo methodinfo,
IQueryable<T> queryable,
LambdaExpression expression)
{
var generic_order_by =
methodinfo.MakeGenericMethod(
typeof(T),
expression.ReturnType);

return (IQueryable<T>)generic_order_by.Invoke(
null,
new object[] { queryable, expression });
}

private static readonly MethodInfo OrderbyMethod;
private static readonly MethodInfo OrderbyDescendingMethod;

private static readonly MethodInfo ThenByMethod;
private static readonly MethodInfo ThenByDescendingMethod;

//Here we use reflection to get references to the open generic methods for
//the 4 Queryable methods that we need
static MyClass()
{
OrderbyMethod = typeof(Queryable)
.GetMethods()
.First(x => x.Name == "OrderBy" &&
x.GetParameters()
.Select(y => y.ParameterType.GetGenericTypeDefinition())
.SequenceEqual(new[] { typeof(IQueryable<>), typeof(Expression<>) }));

OrderbyDescendingMethod = typeof(Queryable)
.GetMethods()
.First(x => x.Name == "OrderByDescending" &&
x.GetParameters()
.Select(y => y.ParameterType.GetGenericTypeDefinition())
.SequenceEqual(new[] { typeof(IQueryable<>), typeof(Expression<>) }));

ThenByMethod = typeof(Queryable)
.GetMethods()
.First(x => x.Name == "ThenBy" &&
x.GetParameters()
.Select(y => y.ParameterType.GetGenericTypeDefinition())
.SequenceEqual(new[] { typeof(IOrderedQueryable<>), typeof(Expression<>) }));

ThenByDescendingMethod = typeof(Queryable)
.GetMethods()
.First(x => x.Name == "ThenByDescending" &&
x.GetParameters()
.Select(y => y.ParameterType.GetGenericTypeDefinition())
.SequenceEqual(new[] { typeof(IOrderedQueryable<>), typeof(Expression<>) }));
}

}

这是一个用法示例:

public class Person
{
public int Age { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name + ", " + Age;
}
}

class Program
{
static void Main(string[] args)
{
List<Person> persons = new List<Person>
{
new Person {Name = "yacoub", Age = 30},
new Person {Name = "yacoub", Age = 32},
new Person {Name = "adam", Age = 30},
new Person {Name = "adam", Age = 33},
};

var query = MyClass.Order(
persons.AsQueryable(),
new List<string> { "+Name", "-Age" },
new Dictionary<string, LambdaExpression>
{
{"Name", (Expression<Func<Person, string>>) (x => x.Name)},
{"Age", (Expression<Func<Person, int>>) (x => x.Age)}
});

var result = query.ToList();
}
}

关于c# - 基于字段列表和 Asc/Desc 规则的 OrderBy,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37629897/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com