简体   繁体   English

如何动态执行多个 Linq to Entities 排序

[英]How to perform multiple Linq to Entities orderings dynamically

So my problem is like this;所以我的问题是这样的; in C# code, I need to perform multiple orderings of an entity set with the help of Linq to Entities, dependent on input parameters.在 C# 代码中,我需要在 Linq to Entities 的帮助下根据输入参数对实体集执行多次排序。 There are three columns to order on, and the order of the ordering columns is itself variable (meaning that for each ordering, I need to look up which column to order on).有三列要排序,排序列的顺序本身是可变的(这意味着对于每个排序,我需要查找要排序的列)。 How can I achieve this?我怎样才能做到这一点?

I have some code that should work, but I repeat myself way too much since I haven't been able to parameterize my operations (Linq to Entities is very restrictive wrt. what I'm allowed to do in my lambdas).我有一些应该可以工作的代码,但是我重复了太多,因为我无法参数化我的操作(Linq to Entities 是非常严格的wrt。我可以在我的 lambdas 中做什么)。 Please suggest how I can rewrite my code in accordance with the DRY principle, perhaps with the help of T4 code generation?请建议我如何根据DRY原则重写我的代码,也许在 T4 代码生成的帮助下?

The following code should illustrate my problem.下面的代码应该说明我的问题。 It's an excerpt of the real code, for brevity, let me know if I should include more.这是真实代码的摘录,为简洁起见,如果我应该包含更多内容,请告诉我。 The orderSpecs variable is an array of "order specifications", each of which specifying a column to order on and whether to order in a descending manner. orderSpecs变量是一个“订单规范”数组,每个规范指定要排序的列以及是否以降序方式排序。 The orderSpecs array has at least one element, so at least one ordering is performed. orderSpecs数组至少有一个元素,因此至少执行了一种排序。

using (var db = new MyContainer())
{
    var orderSpec = orderSpecs[0];
    IQueryable<DbVersion> dVersions = null;
    if (orderSpec.Column == 0)
    {
        if (orderSpec.Descending)
        {
            dVersions = db.Versions.OrderByDescending(ver => ver.Name);
        }
        else
        {
            dVersions = db.Versions.OrderBy(ver => ver.Name);
        }
    }
    else if (orderSpec.Column == 1)
    {
        if (orderSpec.Descending)
        {
            dVersions = db.Versions.OrderByDescending(ver => ver.Built);
        }
        else
        {
            dVersions = db.Versions.OrderBy(ver => ver.Built);
        }
    }
    else if (orderSpec.Column == 2)
    {
        if (orderSpec.Descending)
        {
            dVersions = db.Versions.OrderByDescending(ver => ver.Id);
        }
        else
        {
            dVersions = db.Versions.OrderBy(ver => ver.Id);
        }
    }

    foreach (var spec in orderSpecs.Skip(1))
    {
        if (spec.Column == 0)
        {
            if (spec.Descending)
            {
                dVersions = dVersions.ThenByDescending(ver => ver.Name);
            }
            else
            {
                dVersions = dVersions.ThenBy(ver => ver.Name);
            }
        }
        else if (spec.Column == 1)
        {
            if (spec.Descending)
            {
                dVersions = dVersions.ThenByDescending(ver => ver.Built);
            }
            else
            {
                dVersions = dVersions.ThenBy(ver => ver.Built);
            }
        }
        else if (spec.Column == 2)
        {
            if (spec.Descending)
            {
                dVersions = dVersions.ThenByDescending(ver => ver.Id);
            }
            else
            {
                dVersions = dVersions.ThenBy(ver => ver.Id);
            }
        }
    }

What about creating a dictionary for mapping these colums that are causing these huge if-else constructs to the properties.如何创建一个字典来将这些导致这些巨大的 if-else 构造的列映射到属性。 Could look like this:看起来像这样:

using (var db = new MyContainer())
{
    var orderSpec = orderSpecs[0];
    IOrderedEnumerable<DbVersion> dVersions;

    var mapping = new Dictionary<int, Func<DbVersion, object>>()
    {
        { 0, ver => ver.Name },
        { 1, ver => ver.Built },
        { 2, ver => ver.Id }
    };

    if (orderSpec.Descending)
        dVersions = db.Versions.OrderByDescending(mapping[orderSpec.Column]);
    else
        dVersions = db.Versions.OrderBy(mapping[orderSpec.Column]);

    foreach (var spec in orderSpecs.Skip(1))
    {
        if (spec.Descending)
            dVersions = dVersions.ThenByDescending(mapping[spec.Column]);
        else
            dVersions = dVersions.ThenBy(mapping[spec.Column]);
    }
}

For Untype : You can also make use of Dynamic Linq Library : Using the LINQ Dynamic Query Library对于Untype :您还可以使用动态 Linq 库: 使用 LINQ 动态查询库

在此处输入图片说明

OR要么

Full article : Handle GridView.OnSorting() and create sorting expression dynamically using LINQ全文: 处理 GridView.OnSorting() 并使用 LINQ 动态创建排序表达式

For Typed : You can do dynamic sorting as below which remove the code that you have written对于Typed :您可以进行如下动态排序,删除您编写的代码

How to do soring on class called person where the columnname and sorting direction is not fix如何对列名和排序方向未修复的名为 person 的类进行排序

IEnumerable<Person> persons = GetPersons();
    persons = persons.OrderBy(e.SortExpression, e.SortDirection);

Person class人物类

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Generic method with expression tree for sorting data使用表达式树对数据进行排序的通用方法

public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> collection, 
       string columnName, SortDirection direction)
{
    ParameterExpression param = Expression.Parameter(typeof(T), "x"); // x
    Expression property = Expression.Property(param, columnName);     // x.ColumnName
    Func<T, object> func = Expression.Lambda<Func<T, object>>(        // x => x.ColumnName
        Expression.Convert(Expression.Property(param, columnName), 
        typeof(object)), param).Compile();

    Func<IEnumerable<T>, Func<T, object>, IEnumerable<T>> expression =
        SortExpressionBuilder<T>.CreateExpression(direction);
    IEnumerable<T> sorted = expression(collection, func);
    return sorted;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM