LINQ: сортировка по многим столбцам динамически - PullRequest
3 голосов
/ 23 июля 2010

У меня есть запрос IQueryable и я хочу применить к нему сортировку динамически, сортировка может быть по многим столбцам (asc или desc). Я написал следующую обобщенную функцию:

    private IQueryable<T> ApplySorting<T,U>(IQueryable<T> query, Expression<Func<T, U>> predicate, SortOrder order)
    {
        if (order == SortOrder.Ascending)
        {
            {
                return query.OrderBy<T, U>(predicate);
            }
        }
        else
        {
            {
                return query.OrderByDescending<T, U>(predicate);
            }
        }
    }

SortOrder - это мое простое перечисление с двумя значениями: по возрастанию и по убыванию

Затем я вызываю эту функцию в цикле для каждого столбца, который пользователь запрашивал сортировку. Однако я заметил, что это не удается, потому что он всегда сортируется по последнему использованному столбцу, игнорируя остальные.

Затем я обнаружил, что в IOrderedQueryable есть метод ThenBy, поэтому допустимое использование:

var q = db.MyType.OrderBy(x=>x.Col1).ThenBy(y=>y.Col2); //etc.

Но как я могу сделать его родовым? Я попытался проверить, является ли запрос IOrderedQueryable, но он всегда кажется истинным, даже если он простейший var q = from x в db.

Понятия не имею, почему это было задумано. Что не так с:

var q = db.MyType.OrderBy(x=>x.Col1).OrderBy(y=>y.Col2); //etc.

это так интуитивно понятно

Ответы [ 5 ]

1 голос
/ 23 июля 2010

Вам просто нужно проверить, заказан ли уже запрос:

private IQueryable<T> ApplySorting<T,U>(IQueryable<T> query, Expression<Func<T, U>> predicate, SortOrder order)
{
    var ordered = query as IOrderedQueryable<T>;
    if (order == SortOrder.Ascending)
    {
        if (ordered != null)
            return ordered.ThenBy(predicate);
        return query.OrderBy(predicate);
    }
    else
    {
        if (ordered != null)
            return ordered.ThenByDescending(predicate);
        return query.OrderByDescending(predicate);
    }
}
0 голосов
/ 28 февраля 2018

Как насчет просто сделать первый OrderBy статическим, а затем всегда ThenBy?

OrderColumn[] columnsToOrderby = getColumnsToOrderby();
IQueryable<T> data = getData();

if(!columnToOrderBy.Any()) { }
else
{
    OrderColumn firstColumn = columnsToOrderBy[0];
    IOrderedEnumerable<T> orderedData =
        firstColumn.Ascending
        ? data.OrderBy(predicate)
        : data.OrderByDescending(predicate);

    for (int i = 1; i < columnsToOrderBy.Length; i++)
    {
        OrderColumn column = columnsToOrderBy[i];
        orderedData =
            column.Ascending
            ? orderedData.ThenBy(predicate)
            : orderedData.ThenByDescending(predicate);
    }
}
0 голосов
/ 28 февраля 2018

Расширение до динамического мультизаказа:

public static class DynamicExtentions
{
    public static IEnumerable<T> DynamicOrder<T>(this IEnumerable<T> data, string[] orderings) where T : class
    {
        var orderedData = data.OrderBy(x => x.GetPropertyDynamic(orderings.First()));
        foreach (var nextOrder in orderings.Skip(1))
        {
            orderedData = orderedData.ThenBy(x => x.GetPropertyDynamic(nextOrder));
        }
        return orderedData;
    }

    public static object GetPropertyDynamic<Tobj>(this Tobj self, string propertyName) where Tobj : class
    {
        var param = Expression.Parameter(typeof(Tobj), "value");
        var getter = Expression.Property(param, propertyName);
        var boxer = Expression.TypeAs(getter, typeof(object));
        var getPropValue = Expression.Lambda<Func<Tobj, object>>(boxer, param).Compile();            
        return getPropValue(self);
    }
}

Пример:

var q =(myItemsToSort.Order(["Col1","Col2"]);

Примечание: не уверен, что любой IQueryable провайдер может перевести это

0 голосов
/ 23 июля 2010

Я бы написал обертку и использовал бы внутренние методы расширения linq.

var resultList =   presentList
        .MyOrderBy(x => x.Something)
        .MyOrderBY(y => y.SomethingElse)
        .MyOrderByDesc(z => z.AnotherThing)

public IQueryable<T> MyOrderBy(IQueryable<T> prevList, Expression<Func<T, U>> predicate) {

       return (prevList is IOrderedQueryable<T>)
            ? query.ThenBy(predicate)
            : query.OrderBy(predicate);
}

public IQueryable<T> MyOrderByDesc(IQueryable<T> prevList, Expression<Func<T, U>> predicate) {

       return (prevList is IOrderedQueryable<T>)
            ? query.ThenByDescending(predicate)
            : query.OrderByDescending(predicate);
}

PS: я не проверял код

0 голосов
/ 23 июля 2010

Полное предположение, но вы можете сделать что-то подобное?

query.OrderBy(x => 1).ThenBy<T,U>(predicate)

За исключением любых синтаксических ошибок, идея состоит в том, чтобы сделать OrderBy (), который ни на что не влияет, а затем выполнить реальную работу в вызове метода .ThenBy ()

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