5

所以我的问题是这样的;在 C# 代码中,我需要在 Linq to Entities 的帮助下执行实体集的多个排序,具体取决于输入参数。有三列要排序,排序列的顺序本身是可变的(这意味着对于每个排序,我需要查找要排序的列)。我怎样才能做到这一点?

我有一些应该可以工作的代码,但是我重复自己的方式太多了,因为我无法参数化我的操作(Linq to Entities 非常严格。我可以在我的 lambda 中做的事情)。请建议我如何根据DRY原则重写我的代码,也许在 T4 代码生成的帮助下?

以下代码应该说明我的问题。这是真实代码的摘录,为简洁起见,如果我应该包含更多内容,请告诉我。该orderSpecs变量是“订单规范”的数组,每个指定要排序的列以及是否以降序方式排序。数组至少有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);
            }
        }
    }
4

2 回答 2

16

如何创建一个字典来将导致这些巨大的 if-else 构造的这些列映射到属性。可能看起来像这样:

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]);
    }
}
于 2012-05-11T11:00:50.153 回答
3

对于Untype:您还可以使用动态 Linq 库:使用 LINQ 动态查询库

在此处输入图像描述

或者

全文:使用 LINQ 处理 GridView.OnSorting() 并动态创建排序表达式

对于Typed:您可以进行如下动态排序,删除您编写的代码

如何在列名和排序方向不固定的名为 person 的类上进行排序

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

人物类

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

用于对数据进行排序的具有表达式树的通用方法

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;
}
于 2012-05-11T10:48:51.780 回答