Несколько «упорядочить по» в LINQ

У меня есть две таблицы, moviesи categoriesя получаю упорядоченный список сначала по categoryID, а затем по имени .

Таблица фильмов имеет три столбца ID, Имя и CategoryID . Таблица категорий имеет два столбца ID и Имя .

Я попробовал что-то вроде следующего, но это не сработало.

var movies = _db.Movies.OrderBy( m => { m.CategoryID, m.Name })
18.11.2008 13:34:11
Вот почему это не может работать: лямбда-выражение в скобках должно возвращать значение, которое можно использовать для упорядочивания элементов: m.CategoryID - это число, которое можно использовать для упорядочения элементов. Но «m.CategoryID, m.Name» не имеет смысла в этом контексте.
chiccodoro 22.10.2010 13:22:10
.То, что вы ищете?
eka808 10.07.2014 16:38:26
Если по какой-либо причине вы хотите отсортировать их в порядке убывания, то здесь есть путь.
RBT 19.07.2017 12:50:22
7 ОТВЕТОВ
РЕШЕНИЕ

Это должно работать для вас:

var movies = _db.Movies.OrderBy(c => c.Category).ThenBy(n => n.Name)
2814
25.01.2018 14:53:22
Спасибо за ответ, конечно ... Но вместо того, Var movies = _db.Movies.Orderby(c => c.Category).ThenBy(n => n.Name) чтобы использовать Var movies = _db.Movies.Orderby(c => c.Category).OrderBy(n => n.Name) 2 раза "orderBy", почему результат отличается?
user545425 20.01.2011 16:44:42
@devendra, результат другой, потому что второй «OrderBy» работает над коллекцией, которая является результатом первого «OrderBy», и переупорядочивает его элементы
user569876 20.01.2011 16:45:38
Как же я прошел все это время, не зная о чем ThenBy?! ( Изменить: похоже, что он был введен в .NET 4.0, который объясняет, как он незаметно проскользнул мимо меня.)
Jordan Gray 21.11.2013 15:05:38
Это было там с тех пор, как был добавлен LINQ. Этот ответ до .NET 4.0.
Nathan W 9.12.2013 12:55:34
Да, я пришел к выводу, что слишком поспешно на основании 3.5 не находится в выпадающей версии на странице документации ; Я должен был искать информацию о версии. Спасибо за исправление. :)
Jordan Gray 9.12.2013 13:37:55

Используя не лямбда, синтаксис запроса LINQ, вы можете сделать это:

var movies = from row in _db.Movies 
             orderby row.Category, row.Name
             select row;

[РЕДАКТИРОВАТЬ к адресу комментария] Чтобы управлять порядком сортировки, используйте ключевые слова ascending(которые используются по умолчанию и поэтому не особенно полезны) или descending, например, так:

var movies = from row in _db.Movies 
             orderby row.Category descending, row.Name
             select row;
593
21.01.2011 20:57:43
Там нет способа переключаться между нисходящим и не в этом синтаксисе есть?
ehdv 21.01.2011 18:32:12
На самом деле, ваш ответ эквивалентен _db.Movies.Orderby(c => c.Category).OrderBy(n => n.Name). Более правильным являетсяfrom row in _db.Movies orderby row.Category descending orderby row.Name select row
Lodewijk 31.08.2011 08:38:57
@Lodewijk: Я полагаю, что у вас есть это точно назад. Ваш пример в конечном итоге будет иметь row.Name, являющийся первичным столбцом, и row.Category вторичный, что эквивалентно _db.Movies.Orderby(c => c.Category).OrderBy(n => n.Name). Два предоставленных вами фрагмента эквивалентны друг другу, а не ОП.
Scott Stafford 20.10.2011 17:59:19
Единственным недостатком использования синтаксиса SQL для Linq является то, что поддерживаются не все функции, большинство, но не все
Joshua G 19.07.2015 19:09:57

Добавить новое":

var movies = _db.Movies.OrderBy( m => new { m.CategoryID, m.Name })

Это работает на моей коробке. Он возвращает что-то, что можно использовать для сортировки. Возвращает объект с двумя значениями.

Аналогично, но отличается от сортировки по объединенному столбцу следующим образом.

var movies = _db.Movies.OrderBy( m => (m.CategoryID.ToString() + m.Name))
74
15.12.2017 12:17:42
Будьте осторожны при использовании этого для чисел.
WoF_Angel 6.09.2012 12:15:22
Вы можете использовать OrderByDescending и ThenBy, или OrderBy и ThenByDescending, в зависимости от ваших потребностей.
Ali Shah Ahmed 21.03.2013 08:08:22
Я вполне уверен, что .OrderBy( m => new { m.CategoryID, m.Name })и .OrderBy( m => new { m.Name, m.CategoryID })получу те же результаты, а не соблюдение намеченного приоритета. Иногда может показаться, что вы заказываете то, что вам нужно, по стечению обстоятельств. Кроме того, m.CategoryID.ToString() + m.Nameбудут получены неправильные заказы, если CategoryID является int. Например, что-то с id = 123, name = 5times появится после id = 1234, name = что-то вместо прежнего. Также неэффективно проводить сравнения строк, где могут происходить сравнения int.
AaronLS 6.05.2013 16:40:20
Когда я пытаюсь упорядочить по анонимному типу, я получаю ArgumentException с сообщением «По крайней мере, один объект должен реализовывать IComparable». Я вижу, что другим приходится объявлять компаратор при этом. См. Stackoverflow.com/questions/10356864/… .
Robert Gowland 31.07.2014 20:06:24
Это абсолютно неправильно. Упорядочение по новому анонимному типу, который не имеет реализации ICompariable, не может работать, потому что нет порядка для свойств анонимного типа. Он не знал бы, нужно ли сначала отсортировать по CategoryID или Name, не говоря уже о том, нужно ли сортировать их в противоположных порядках.
Triynko 31.08.2015 19:08:23

Есть по крайней мере еще один способ сделать это с помощью LINQ, хотя и не самый простой. Вы можете сделать это с помощью OrberBy()метода, который использует IComparer. Прежде всего , необходимо реализовать IComparerдля Movieкласса , как это:

public class MovieComparer : IComparer<Movie>
{
    public int Compare(Movie x, Movie y)
    {
        if (x.CategoryId == y.CategoryId)
        {
            return x.Name.CompareTo(y.Name);
        }
        else
        {
            return x.CategoryId.CompareTo(y.CategoryId);
        }
    }
}

Тогда вы можете заказать фильмы со следующим синтаксисом:

var movies = _db.Movies.OrderBy(item => item, new MovieComparer());

Если вам нужно переключить порядок по убыванию для одного из элементов, просто переключите x и y внутри Compare() метода MovieComparerсоответственно.

16
3.04.2015 14:12:32
Мне нравится это как более общий, чем тогда, поскольку вы можете делать странные вещи со сравнением, в том числе иметь разные объекты сравнения с разными алгоритмами, готовыми к работе. Это лучше, чем мое предпочтительное решение, прежде чем узнавать о том, каким образом было создать класс, реализующий интерфейс IComparable.
Gerard ONeill 29.09.2015 16:29:07
С 2012 года (.NET версия 4.5) вам не нужно создавать класс MovieComparerсамостоятельно; вместо этого вы можете сделать _db.Movies.OrderBy(item => item, Comparer<Movie>.Create((x, y) => { if (x.CategoryId == y.CategoryId) { return x.Name.CompareTo(y.Name); } else { return x.CategoryId.CompareTo(y.CategoryId); } }));. Конечно, если вы предпочитаете писать логику в виде одного выражения вместо if... else, тогда лямда (x, y) => exprможет быть проще.
Jeppe Stig Nielsen 27.07.2018 07:37:01

используйте следующую строку в вашем DataContext, чтобы записать действие SQL в DataContext на консоль - тогда вы сможете точно увидеть, что ваши операторы linq запрашивают из базы данных:

_db.Log = Console.Out

Следующие операторы LINQ:

var movies = from row in _db.Movies 
             orderby row.CategoryID, row.Name
             select row;

А ТАКЖЕ

var movies = _db.Movies.OrderBy(m => m.CategoryID).ThenBy(m => m.Name);

создайте следующий SQL:

SELECT [t0].ID, [t0].[Name], [t0].CategoryID
FROM [dbo].[Movies] as [t0]
ORDER BY [t0].CategoryID, [t0].[Name]

Принимая во внимание, что повторение OrderBy в Linq, по-видимому, обращает результирующий вывод SQL:

var movies = from row in _db.Movies 
             orderby row.CategoryID
             orderby row.Name
             select row;

А ТАКЖЕ

var movies = _db.Movies.OrderBy(m => m.CategoryID).OrderBy(m => m.Name);

создайте следующий SQL (Name и CategoryId переключаются):

SELECT [t0].ID, [t0].[Name], [t0].CategoryID
FROM [dbo].[Movies] as [t0]
ORDER BY [t0].[Name], [t0].CategoryID
29
3.10.2016 12:08:32

Я создал несколько методов расширения (ниже), поэтому вам не нужно беспокоиться о том, заказан ли IQueryable или нет. Если вы хотите упорядочить по нескольким свойствам, просто сделайте это следующим образом:

// We do not have to care if the queryable is already sorted or not. 
// The order of the Smart* calls defines the order priority
queryable.SmartOrderBy(i => i.Property1).SmartOrderByDescending(i => i.Property2);

Это особенно полезно, если вы создаете порядок динамически, например, из списка свойств для сортировки.

public static class IQueryableExtension
{
    public static bool IsOrdered<T>(this IQueryable<T> queryable) {
        if(queryable == null) {
            throw new ArgumentNullException("queryable");
        }

        return queryable.Expression.Type == typeof(IOrderedQueryable<T>);
    }

    public static IQueryable<T> SmartOrderBy<T, TKey>(this IQueryable<T> queryable, Expression<Func<T, TKey>> keySelector) {
        if(queryable.IsOrdered()) {
            var orderedQuery = queryable as IOrderedQueryable<T>;
            return orderedQuery.ThenBy(keySelector);
        } else {
            return queryable.OrderBy(keySelector);
        }
    }

    public static IQueryable<T> SmartOrderByDescending<T, TKey>(this IQueryable<T> queryable, Expression<Func<T, TKey>> keySelector) {
        if(queryable.IsOrdered()) {
            var orderedQuery = queryable as IOrderedQueryable<T>;
            return orderedQuery.ThenByDescending(keySelector);
        } else {
            return queryable.OrderByDescending(keySelector);
        }
    }
}
24
15.12.2017 12:17:17
Этот ответ - золото! Я объединю проверку для queryable.IsOrdered () с ответом из этого поста, чтобы иметь единственный метод, который принимает направление сортировки: stackoverflow.com/questions/388708
SwissCoder 14.03.2018 08:56:32
Таким образом, реализация Linq должна идти в первую очередь! OrderBy плохо спроектирован ...
Andrzej Martyna 22.03.2018 19:46:19
@ Мари, ты явно не понял вариант использования. Как вы, например, динамически создаете порядок из списка свойств? Это единственный способ. Пожалуйста, не отрицайте и не пересматривайте. Спасибо.
sjkm 17.09.2018 08:59:07
Справедливо. Я все еще не вижу выгоды, но я заберу свой голос назад
Marie 17.09.2018 13:30:16
Будет ли это работать сnullable datetime
aggie 27.07.2019 14:36:07

Если использовать общий репозиторий

> lstModule = _ModuleRepository.GetAll().OrderBy(x => new { x.Level,
> x.Rank}).ToList();

еще

> _db.Module.Where(x=> ......).OrderBy(x => new { x.Level, x.Rank}).ToList();
3
17.07.2018 14:35:11
Анонимные выражения будут анализироваться локально ядром платформы сущностей. Выражение LINQ не может быть переведено и будет оценено локально.
alhpe 26.03.2019 12:25:05