Сортировка столбца даты IQueryable по строковому значению в LINQ - PullRequest
0 голосов
/ 17 октября 2011

Я пытаюсь отсортировать IQueryable объект по определенному столбцу с помощью строкового ввода .

Вызов .ToList() на IQueryable и сортировка по столбцу списка работает отлично, однако при сортировке столбца даты он сортируется по алфавиту, что не идеально.

Если бы кто-нибудь мог указать мне правильное направление здесь, я был бы признателен.

Мое использование

IQueryable<MyItemType> list = (from t1 in db.MyTable
                                         select t1);

List<MyItemType> itemsSorted; // Sort here

if (!String.IsNullOrEmpty(OrderBy))
{
    itemsSorted = list.OrderBy(OrderBy).ToList();
}
else
{
    itemsSorted = list.ToList();
}

Метод расширения

using System.Linq;
using System.Collections.Generic;
using System;
using System.Linq.Expressions;
using System.Reflection;

public static class OrderByHelper
{
public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> enumerable, string orderBy)
{
    return enumerable.AsQueryable().OrderBy(orderBy).AsEnumerable();
}

public static IQueryable<T> OrderBy<T>(this IQueryable<T> collection, string orderBy)
{
    foreach (OrderByInfo orderByInfo in ParseOrderBy(orderBy))
        collection = ApplyOrderBy<T>(collection, orderByInfo);

    return collection;
}

private static IQueryable<T> ApplyOrderBy<T>(IQueryable<T> collection, OrderByInfo orderByInfo)
{
    string[] props = orderByInfo.PropertyName.Split('.');
    Type type = typeof(T);

    ParameterExpression arg = Expression.Parameter(type, "x");
    Expression expr = arg;
    foreach (string prop in props)
    {
        // use reflection (not ComponentModel) to mirror LINQ
        PropertyInfo pi = type.GetProperty(prop);
        expr = Expression.Property(expr, pi);
        type = pi.PropertyType;
    }
    Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
    LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
    string methodName = String.Empty;

    if (!orderByInfo.Initial && collection is IOrderedQueryable<T>)
    {
        if (orderByInfo.Direction == SortDirection.Ascending)
            methodName = "ThenBy";
        else
            methodName = "ThenByDescending";
    }
    else
    {
        if (orderByInfo.Direction == SortDirection.Ascending)
            methodName = "OrderBy";
        else
            methodName = "OrderByDescending";
    }

    //TODO: apply caching to the generic methodsinfos?
    return (IOrderedQueryable<T>)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[] { collection, lambda });

}

private static IEnumerable<OrderByInfo> ParseOrderBy(string orderBy)
{
    if (String.IsNullOrEmpty(orderBy))
        yield break;

    string[] items = orderBy.Split(',');
    bool initial = true;
    foreach (string item in items)
    {
        string[] pair = item.Trim().Split(' ');

        if (pair.Length > 2)
            throw new ArgumentException(String.Format("Invalid OrderBy string '{0}'. Order By Format: Property, Property2 ASC, Property2 DESC", item));

        string prop = pair[0].Trim();

        if (String.IsNullOrEmpty(prop))
            throw new ArgumentException("Invalid Property. Order By Format: Property, Property2 ASC, Property2 DESC");

        SortDirection dir = SortDirection.Ascending;

        if (pair.Length == 2)
            dir = ("desc".Equals(pair[1].Trim(), StringComparison.OrdinalIgnoreCase) ? SortDirection.Descending : SortDirection.Ascending);

        yield return new OrderByInfo() { PropertyName = prop, Direction = dir, Initial = initial };

        initial = false;
    }

}

private class OrderByInfo
{
    public string PropertyName { get; set; }
    public SortDirection Direction { get; set; }
    public bool Initial { get; set; }
}

private enum SortDirection
{
    Ascending = 0,
    Descending = 1
}
public static IQueryable<T> OrderByIQueryableStringValue<T>(this IQueryable<T> source, string ordering, params object[] values)
{
    var type = typeof(T);
    var property = type.GetProperty(ordering);
    var parameter = Expression.Parameter(type, "p");
    var propertyAccess = Expression.MakeMemberAccess(parameter, property);
    var orderByExp = Expression.Lambda(propertyAccess, parameter);
    MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderBy", new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp));
    return source.Provider.CreateQuery<T>(resultExp);
} 

}

1 Ответ

1 голос
/ 17 октября 2011

Если вы хотите, чтобы уже существовала библиотека для динамического linq, которая имеет метод упорядочения по расширению (и другие методы linq), который принимает строковый ввод для всех типов данных. Смотри http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...