c# - 在 LINQ 中获取动态 OrderBy

标签 c# linq entity-framework linq-to-entities dynamic-linq

<分区>

我在我的 ASP.NET MVC 3 站点的很多页面中使用了数据表。他们使用服务器端分页,现在我想实现基于列标题的排序。 Datatables 带有 iSortCol_0,它是点击列的 int 值。

我不喜欢这种方法,因为查询最终会是这样的:

if(iSortCol_0 == 0)
{    
    // query
    // OderBy(x => x.CarName)
}

然后这将对每一列重复(加上每列的 else 子句以按降序排列)。所以我改变了我的方法,现在将列名传递给服务器。

我想出了以下几点:

Expression<Func<vw_Car, string>> sortExpression1 = null;
Expression<Func<vw_Car, int>> sortExpression2 = null;

switch(columnToSort) 
{
    case "InvoiceNo": sortExpression1 = x => x.CarNo; break;
    case "ClientNumber": sortExpression1 = x => x.ForeName; break;
    case "ClientName": sortExpression1 = x => x.SurName; break;
    default: sortExpression2 =  x => x.Age.Value; break;
}

// start of query
.OrderByDir(sortDirection, sortExpression1 , sortExpression2)

现在 OrderByDir 如下所示:

public static IOrderedQueryable<T> OrderByDir<T>(this IQueryable<T> source, string dir, Expression<Func<T, string>> column1, Expression<Func<T, int>> column2)
{
    if (column1 != null)
    {
        return dir == "asc" ? source.OrderBy(column1) : source.OrderByDescending(column1);
    }         
    if (column2 != null)
    {
        return dir == "asc" ? source.OrderBy(column2) : source.OrderByDescending(column2);
    }    
    return null;
}

这是因为它对类型为 stringint 的列进行排序。我还有另一列要排序的 DateTime,因此我需要编写另一个 sortExpression3,然后将其添加到我的 OrderByDir

但是我不太喜欢这个实现 - 我曾尝试编写一个通用的排序表达式,它将一个对象作为第二个参数而不是 stringintDatetime,但是当有此代码时,我得到 无法将类型“System.DateTime”强制转换为类型“System.Object”。 LINQ to Entities 仅支持转换实体数据模型基元类型

关于可能的更好方法,有人有任何想法吗?

最佳答案

这样的扩展应该符合您的需求:

public static class LinqExtensions
{
    public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
    {
        return ApplyOrder(source, property, "OrderBy");
    }

    public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
    {
        return ApplyOrder(source, property, "OrderByDescending");
    }

    private static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
    {
        var props = property.Split('.');
        var type = typeof(T);
        var arg = Expression.Parameter(type, "x");
        Expression expr = arg;
        foreach (var prop in props)
        {
            // use reflection (not ComponentModel) to mirror LINQ
            var pi = type.GetProperty(prop);
            expr = Expression.Property(expr, pi);
            type = pi.PropertyType;
        }
        var delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
        var lambda = Expression.Lambda(delegateType, expr, arg);

        var result = typeof(Queryable).GetMethods().Single(
                method => method.Name == methodName
                        && method.IsGenericMethodDefinition
                        && method.GetGenericArguments().Length == 2
                        && method.GetParameters().Length == 2)
                .MakeGenericMethod(typeof(T), type)
                .Invoke(null, new object[] { source, lambda });
        return (IOrderedQueryable<T>)result;
    }
}

调用示例:

query.OrderBy("Age.Value");

关于c# - 在 LINQ 中获取动态 OrderBy,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16077490/

相关文章:

c# - 如何在桌面应用程序中退出 Azure AD 2.0/MSAL?

c# - WPF——嵌套窗口

c# - 为 GeckoFX 网络浏览器设置 cookies?

c# - 动态修改 LINQ to SQL Select 语句的列

c# - LINQ 和多对多关系

c# - 如何在 Entity Framework 中进行正确的左连接

c# - 获取当前值和先前值

C# linq 查询聚合可为空 boolean 值

c# - 根据另一个列表的内容对列表进行排序

entity-framework - 无法加载文件,因为在此系统上禁用了脚本的执行