C# 在LINQ中获取动态OrderBy

C# 在LINQ中获取动态OrderBy,c#,linq,entity-framework,linq-to-entities,dynamic-linq,C#,Linq,Entity Framework,Linq To Entities,Dynamic Linq,在我的ASP.NET MVC 3站点的很多页面中,我都在使用datatables。它们使用服务器端分页,现在我想实现基于列标题的排序。Datatables附带了iSortCol\u 0,它是单击的列的int值 我不喜欢这种方法,因为查询的结果可能是: if(iSortCol_0 == 0) { // query // OderBy(x => x.CarName) } 然后对每个列重复此操作(加上每个列上的else子句,按降序排列)。因此,我改变了方法,现在将列名传

在我的ASP.NET MVC 3站点的很多页面中,我都在使用datatables。它们使用服务器端分页,现在我想实现基于列标题的排序。Datatables附带了
iSortCol\u 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)
这是因为它对类型为
string
int
的列进行排序。我还有一列要排序的
DateTime
,因此我需要编写另一列
sortExpression3
,然后将其添加到我的
OrderByDir

然而,我并不真正喜欢这个实现——我曾试图编写一个通用的排序表达式,将对象作为第二个参数,而不是
string
int
Datetime
,但是当有了这个代码时,我无法将类型“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;
    }
}

为什么有两个SORTEXPRESSION?根据您的代码,可以设置表达式1或表达式2,但不能同时设置两者。这是否正确?@mattytomo:不适用,引用“我假设您只需要支持LINQ到对象”。@DanielHilgarth-因为其中一个排序表达式用于年龄列(一个int字段)-另一个排序表达式用于字符串列我建议将顺序方向添加为参数,而不是单独的方法。可以这样做,但这里的线索是lambda表达式树的构建和执行。其他次要变化是主观偏好的问题。
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");