Linq Сортировка с текстовым значением, а не лямбда - PullRequest
1 голос
/ 13 мая 2011

Сайт MVC3.Код EF4.1 первый.

Я сохраняю столбец сортировки и направление в сеансе, чтобы при возвращении пользователя на страницу сетка оставалась в том же порядке сортировки.

Я хочу иметь возможность указать, как сортировать коллекцию по сохраненным значениям следующим образом.

this.Issues = this.db.ITIssues.Orderby (this.sort + "" + this.sortdir)...

В настоящее время я должен использовать оператор switch и обрабатывать каждую комбинацию полей + направление сортировки.Есть ли лучший способ?

switch (this.Sort)
{
    case "ITApplication.Name":
        if (this.SortDir == "ASC")
            this.Issues = this.db.ITIssues.OrderBy(i => i.ITApplication.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        else
            this.Issues = this.db.ITIssues.OrderByDescending(i => i.ITApplication.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;

    case "ITIssueType.Name":
        if (this.SortDir == "ASC")
            this.Issues = this.db.ITIssues.OrderBy(i => i.ITIssueType.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        else
            this.Issues = this.db.ITIssues.OrderByDescending(i => i.ITIssueType.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;

    case "CurrentStatus.Name":
        if (this.SortDir == "ASC")
            this.Issues = this.db.ITIssues.OrderBy(i => i.CurrentStatus.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        else
            this.Issues = this.db.ITIssues.OrderByDescending(i => i.CurrentStatus.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;

    case "CurrentAssignedTo.Fname":
        if (this.SortDir == "ASC")
            this.Issues = this.db.ITIssues.OrderBy(i => i.CurrentAssignedTo.Fname).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        else
            this.Issues = this.db.ITIssues.OrderByDescending(i => i.CurrentAssignedTo.Fname).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;

    case "CreatedBy.Fname":
        if (this.SortDir == "ASC")
            this.Issues = this.db.ITIssues.OrderBy(i => i.CreatedBy.Fname).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        else
            this.Issues = this.db.ITIssues.OrderByDescending(i => i.CreatedBy.Fname).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;

    case "CurrentPriority.Name":
        if (this.SortDir == "ASC")
            this.Issues = this.db.ITIssues.OrderBy(i => i.CurrentPriority.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        else
            this.Issues = this.db.ITIssues.OrderByDescending(i => i.CurrentPriority.Name).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;

    default:
        this.Issues = this.db.ITIssues.OrderByDescending(i => i.ID).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;
}

Ответы [ 2 ]

1 голос
/ 13 мая 2011

Недавно мне пришлось сделать что-то похожее, то, что вы ищете, - это Dynamic Linq! Взгляните на это:

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

0 голосов
/ 13 мая 2011

Кажется, что в вашем коде есть два препятствия, первое включает получение имени свойства из строки, представленной this.Sort. Это, вероятно, будет включать в себя некоторый код отражения. Вторая часть включает сокращение количества кода, необходимого для указания сортировки по возрастанию и сортировки по убыванию.

Вы могли бы сделать это несколькими способами. Первой идеей, о которой я подумал, было создание метода расширения для OrderBy, который бы использовал аргумент bool SortDir. Существует несколько перегрузок для OrderBy, допускающих Func<T,TKey> KeySelectors и IComparer<T>. Я покажу вам простой с просто keySelector, но вы можете реализовать их все для полностью универсального решения

public static class IEnumerableExtentions
{
    public static IEnumerable<T> OrderBy<T,TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector, bool reverse)
    {
        return reverse ? source.OrderByDescending(keySelector) : source.OrderBy(keySelector);
    }
}

Имея это, вы могли бы написать свой код без всех этих if

switch (this.Sort)
{
    case "ITApplication.Name":
        this.Issues = this.db.ITIssues.OrderBy(i => i.ITApplication.Name, this.SortDir == "ASC").Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;
    /*...*/
}

В качестве второго решения для определения порядка сортировки вы передаете IComparer, который использует SortDir. Вот реализация IComparer, которую вы можете использовать

class ReversableComparer : IComparer<IComparable>
{
    private bool _reverse;

    public ReversableComparer(bool reverse)
    {
        _reverse = reverse;
    }

    public int Compare(IComparable x, IComparable y)
    {
        return _reverse ? y.CompareTo(x) : x.CompareTo(y);
    }
}

Тогда вы могли бы написать свой код

switch (this.Sort)
{
    case "ITApplication.Name":
        this.Issues = this.db.ITIssues.OrderBy(i => i.ITApplication.Name, new ReversableComparer(this.SortDir != "ASC")).Where(i => i.ITAppGroupID == this.ITAppGroupID);
        break;
    /*...*/
}

Это немного больше кода, чтобы написать, но он есть, если вам это нужно.

Что касается имени / отражения свойства, если вы используете Linq как часть Linq to SQL, динамическая ссылка linq, предоставляемая @AlbertVo, может стоить посмотреть. Если вы больше работаете с Linq to Objects, то вместо i => i.ITApplication.Name попробуйте поиграть с i => i.GetType().GetProperty(this.Sort).GetValue(i, null) Конечно, вам понадобится System.Reflection, чтобы это работало, и это может быть медленнее, чем ваше первоначальное решение.

Я надеюсь, что это помогло. Приветствия.

EDIT Таким образом, эти два метода могут быть объединены. Ваш окончательный код может выглядеть так:

public static class IEnumerableExtentions
{
    public static IEnumerable<T> OrderBy<T,TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector, bool reverse)
    {
        return reverse ? source.OrderByDescending(keySelector) : source.OrderBy(keySelector);
    }
}

void Main()
{
    this.Issues = this.db.ITIssues
        .OrderBy(i => i.GetType().GetProperty(this.Sort).GetValue(i, null), 
            this.SortDir == "ASC")
        .Where(i => i.ITAppGroupID == this.ITAppGroupID);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...