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

时间:2012-05-11 10:36:44

标签: c# .net linq linq-to-entities sql-order-by

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

我有一些应该可行的代码,但是由于我无法对我的操作进行参数化,所以我重复自己太多了(Linq to Entities是非常严格的。我可以在我的lambdas中做什么)。请建议我如何根据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);
            }
        }
    }

2 个答案:

答案 0 :(得分:13)

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

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

    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]);
    }
}

答案 1 :(得分:2)

对于 Untype :您还可以使用动态Linq库:Using the LINQ Dynamic Query Library

enter image description here

OR

完整文章:Handle GridView.OnSorting() and create sorting expression dynamically using LINQ

对于键入:您可以执行动态排序,如下所示删除您编写的代码

如何在没有修改列名和排序方向的人员上打电话

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;
}