Проблема DISTINCT() и ORDERBY

Я узнаю о LINQ-to-SQL, и все шло хорошо, пока не произошло что-то странное:

Я попытался сделать пример distinct, поэтому, используя dabatase Northwind, я написал следующий запрос:

var query = 
    from o in db.Orders
    orderby o.CustomerID
    select new
    {
        o.CustomerID
    };

Если я распечатаю SQL, сгенерированный LINQ-to-SQL для запроса, хранящегося в query, он выглядит следующим образом:

SELECT [t0].[CustomerID]
FROM [dbo].[Orders] AS [t0]
ORDER BY [t0].[CustomerID]

Итак, как обычно, запрос приносит все CustomerID для каждого Order в таблице Orders, упорядоченной по алфавиту.

Но! Если я использую метод Distinct() следующим образом:

var query = (
    from o in db.Orders
    orderby o.CustomerID
    select new
    {
        o.CustomerID
    }).Distinct();

Запрос выводит ожидаемые результаты предложения distinct, но CustomerID не упорядочены, несмотря на то, что я написал orderby o.CustomerID!

Запрос SQL для этого второго запроса LINQ выглядит следующим образом:

SELECT DISTINCT [t0].[CustomerID]
FROM [dbo].[Orders] AS [t0]

Как мы видим, ** предложение ORDER BY отсутствует. Почему это?

Почему предложение ORDER BY исчезает, когда я использую метод Distinct()?

Ответы

Ответ 1

Из Документация Queryable.Distinct;

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

Другими словами, любой порядок, который имеет существующий IQueryable, теряется при использовании Distinct() на нем.

То, что вы хотите, вероятно, что-то более похожее, OrderBy() после выполнения Distinct();

var query = (from o in db.Orders
             select new
             {
                 o.CustomerID
             }).Distinct().OrderBy(x => x.CustomerID);

Ответ 2

Попробуйте переупорядочить участников, чтобы разместить OrderBy после Distinct. Вам нужно будет вернуться к цепочке методов:

db.Orders.Select(o=>o.CustomerId).Distinct().OrderBy(id=>id);

Это будет более эффективный способ настроить запрос в Enumerable Linq в любом случае, потому что OrderBy будет работать только с уникальными элементами, а не со всеми из них. Кроме того, согласно MSDN, Enumerable.Distinct в любом случае не гарантирует порядок возврата элементов, поэтому упорядочение перед дедупликацией бессмысленно.

Ответ 3

Из-за использования отдельных, порядок возвращаемого списка не гарантируется. LinqToSql достаточно умен, чтобы распознать это, поэтому он игнорирует его.

Если вы разместите заказ ПОСЛЕ вашего отличительного знака, все будет происходить по вашему желанию.

var query = (from o in db.Orders
             select new
             {
                 o.CustomerID
             }).Distinct().OrderBy(o => o.CustomerID);

или

var query = db.Orders.Select(o => o.CustomerID).Distinct().OrderBy(o => o.CustomerID);

Пожалуйста, ознакомьтесь с этой статьей для уточнения:

http://programminglinq.com/blogs/marcorusso/archive/2008/07/20/use-of-distinct-and-orderby-in-linq.aspx

Ответ 4

Вы можете имитировать ORDERBY и DISTINCT с помощью этой команды:

var distinctItems = employees.GroupBy(x => x.EmpID).OrderBy(x => x).Select(y => y.First());