带有排序的动态Linq查询,结尾为空

时间:2014-10-15 21:19:09

标签: c# asp.net linq sorting dynamic-linq

我正在尝试构建一个对可空字段进行排序的ASP.NET页面。我想要做的是,如果可排序字段中有空值,则始终将这些行抛出到列表的末尾。否则,它们出现在列表的开头,我可以想象在你到达A-Z排序元素之前的空值行的页面和页面。

我在ASP.NET框架中工作。可排序列的解决方案是针对此处的GridViewDataSource构建动态查询:

public static class QueryExtensions {
public static IQueryable<T> SortBy<T>(this IQueryable<T> source, string propertyName) {
    if (source == null) {
        throw new ArgumentNullException("source");
    }
    // DataSource control passes the sort parameter with a direction
    // if the direction is descending          
    int descIndex = propertyName.IndexOf(" DESC");
    if (descIndex >= 0) {
        propertyName = propertyName.Substring(0, descIndex).Trim();
    }

    if (String.IsNullOrEmpty(propertyName)) {
        return source;
    }

    ParameterExpression parameter = Expression.Parameter(source.ElementType, String.Empty);
    MemberExpression property = Expression.Property(parameter, propertyName);
    LambdaExpression lambda = Expression.Lambda(property, parameter);

    string methodName = (descIndex < 0) ? "OrderBy" : "OrderByDescending";

    Expression methodCallExpression = Expression.Call(typeof(Queryable), methodName,
                                        new Type[] { source.ElementType, property.Type },
                                        source.Expression, Expression.Quote(lambda));

    return source.Provider.CreateQuery<T>(methodCallExpression);
}

}

因为我在这个框架内工作,所以我不会改变这个函数的工作方式。相反,我试图用这个签名重载方法:

public static IQueryable<T> SortBy<T>(this IQueryable<T> source, string propertyName, bool nullsToEnd)

我遇到的问题是我无法弄清楚如何编辑&#39; methodName&#39;特别允许这种类型的排序(A-Z在末尾带有空值)。

关于什么可以做到这一点的任何想法?

由于

1 个答案:

答案 0 :(得分:2)

我不认为有一个方法名称本身会做你想要的。相反,您需要在此方案中选择不同的方法重载,一个采用自定义IComparer实例的方法重载。然后,您需要实现一个包装Comparer.Default的IComparer,在不涉及null时返回该comparer的结果,并在它们出现时将nulls排序到末尾。

请注意,如果您希望OrderBy和OrderByDescending案例的末尾都有空值,则需要相应地调整IComparer实现。要么它处理空值和升序/降序选项,要么在执行“降序”的情况下将空值排序到开头(个人,因为你必须根据升序/降序状态调整IComparer,我会继续,只让IComparer处理上升/下降部分。

例如:

class NullsAtEndComparer<T> : IComparer<T> where T : class
{
    private static readonly IComparer<T> _baseComparer = Comparer<T>.Default;

    private readonly bool _ascending;

    public NullsAtEndComparer(bool ascending = true)
    {
        _ascending = ascending;
    }

    public int Compare(T t1, T t2)
    {
        if (object.ReferenceEquals(t1, t2))
        {
            return 0;
        }

        if (t1 == null)
        {
            return 1;
        }

        if (t2 == null)
        {
            return -1;
        }

        return _ascending ? _baseComparer.Compare(t1, t2) : _baseComparer.Compare(t2, t1);
    }
}

然后对于“结束时的空值”场景,只需始终使用OrderBy方法并为该方法提供上述IComparer实现的实例。