Расширение динамического заказа Linq Марка Гравелла - PullRequest
7 голосов
/ 20 мая 2011

Я нашел динамический порядок Марка Гравелла:

Динамический LINQ OrderBy на IEnumerable

Я поместил его в класс LinqHelper,В этом классе я также создал два новых класса, так что в моем коде я могу сделать это:

var q = db.tblJobHeaders;

LinqHelper.OrderByCollection OBys = new LinqHelper.OrderByCollection();
OBys.AddOrderBy("some field", true);
OBys.AddOrderBy("anotherfield", false);
OBys.ExecuteOrderBys(q);

Классы для достижения этого:

/// <summary>
/// A collection of order bys
/// </summary>
public class OrderByCollection
{
    private ArrayList Orderings = new ArrayList();

    public OrderByCollection(){ }

    /// <summary>
    /// Add an order by to this collection
    /// </summary>
    public void AddOrderBy(string Field, bool Descending)
    {
        OrderByObj NewObj = new OrderByObj(Descending, Field);
        this.Orderings.Add(NewObj);
    }

    /// <summary>
    /// Executes the order bys
    /// </summary>
    public IOrderedQueryable<T> ExecuteOrderBys<T>(this IOrderedQueryable<T> source)
    {
        int ExecutionIndex = 0;
        foreach (OrderByObj O in this.Orderings)
        {
            if (ExecutionIndex == 0)
            {
                if (O.Descending)
                    source = LinqHelper.OrderByDescending(source, O.Field);
                else
                    source = LinqHelper.OrderBy(source, O.Field);
            }
            else
            {
                if (O.Descending)
                    source = LinqHelper.ThenByDescending(source, O.Field);
                else
                    source = LinqHelper.ThenBy(source, O.Field);
            }
            ExecutionIndex++;
        }
        return (IOrderedQueryable<T>)source;
    }
}

/// <summary>
/// An order by object
/// </summary>
private class OrderByObj
{
    public bool Descending { get; set; }
    public string Field { get; set; }

    public OrderByObj(bool IsDescending, string DatabaseField)
    {
        this.Descending = IsDescending;
        this.Field = DatabaseField;
    }
}

Как бы я ни былдовольно плохо знаком с передачей функций Linq в функции (меня это немного смущает).В настоящее время я получаю сообщение об ошибке:

OBys.ExecuteOrderBys(q);

, которое дает ошибку:

Аргументы типа для метода 'LinqHelper.OrderByCollection.ExecuteOrderBys (System.Linq.IOrderedQueryable)' не могутбыть выведены из использования.Попробуйте явно указать аргументы типа.

Я немного озадачен этим, если кто-то может помочь, правильно ли я передаю var q, а затем возвращаю его правильно?

1 Ответ

4 голосов
/ 20 мая 2011

Бьюсь об заклад, тип q равен IQueryable<T>, а не IOrderedQueryable<T>.Простое изменение подписи должно работать, потому что вы начинаете с OrderBy.

Тогда вам понадобится IOrderedQueryable<T> для ThenBy s.Вы можете просто разыграть его, потому что вы точно знаете, что у вас есть IOrderedQueryable<T> из предыдущего вызова на OrderBy или ThenBy.

Если вам не нравится идея разыгрыша,вам нужно внести некоторые изменения:

public IOrderedQueryable<T> ExecuteOrderBys<T>(this IQueryable<T> source)
{
    if(!this.Orderings.Any())
        throw new InvalidOperationException("You need to add orderings");
    IOrderedQueryable<T> ordered;
    if (this.Orderings[0].Descending)
        ordered = LinqHelper.OrderByDescending(source, this.Orderings[0].Field);
    else
        ordered = LinqHelper.OrderBy(source, this.Orderings[0].Field);
    foreach(var ordering in this.Orderings.Skip(1))
    {
        if (ordering.Descending)
            ordered = LinqHelper.ThenByDescending(source, ordering.Field);
        else
            ordered = LinqHelper.ThenBy(source, ordering.Field);
    }
    return ordered;
}

Обратите внимание, что ваш код не получится впечатляюще, если вы не добавите какие-либо заказы из-за преобразования в IOrderedQueryable<T> в конце.Вы можете изменить тип возвращаемого значения на IQueryable<T> (что теряет способность "прикреплять" больше OrderBys позже) или бросить, если нет заказов, как я.

...