微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 在LINQ中获取动态OrderBy

参见英文答案 > Dynamically Sorting with LINQ                                    9个
我在ASP.NET MVC 3站点中的很多页面中使用数据表.他们使用服务器端分页,现在我想基于列标题实现排序.数据表附带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,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;
}

这适用于它对string或int类型的列进行排序.我有另一列DateTime我要排序,所以我需要编写另一个sortExpression3然后将其添加到我的OrderByDir.

但是我真的不喜欢实现 – 我曾尝试编写一个通用的排序表达式,它将一个对象作为第二个参数而不是string,int,Datetime,但是当这个代码到位时,我得到了Unable来强制转换类型’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,"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");

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐