2015-10-09 3 views
3

У меня есть сценарий, в котором я должен был сначала группировать, а затем сортировать каждую группу. Я придумал следующий рабочий запрос:LINQ GroupBy then OrderBy Behavior

applicants = context.Applicants 
        .OrderBy(app => app.Id).Skip((pageNumber - 1)*defaultPageSize) 
        .Take(defaultPageSize) 
        .GroupBy(app => app.PassportNumber) 
        .Select(g => g.OrderBy(d => d.IsEndorseChild)).ToList() 
        .SelectMany(grouping => grouping) 
        .ToList(); 

Но это не работает:

applicants = context.Applicants 
        .OrderBy(app => app.Id).Skip((pageNumber - 1)*defaultPageSize) 
        .Take(defaultPageSize) 
        .GroupBy(app => app.PassportNumber) 
        .Select(g => g.OrderBy(d => d.IsEndorseChild)) 
        .SelectMany(grouping => grouping) 
        .ToList(); 

Первый запрос выдает результат (это идентификатор претендентов возвращается), как:
7, 10, 8, 2, 9, 6, 5, 3, 4, 1
но второй запрос производит:
7, 10, 8, 2, 9, 6, 3, 4, 5, 1

Я не уверен, почему это происходит, и w hat - разница между запросами.
Что именно я здесь не хватает?

EDIT: Пример входного и Ожидаемый результат:

Applicant 1 => ID : 1 
       IsEndorsed : 0 
       Passport : ABC123 

Applicant 2 => ID : 2 
       IsEndorsed : 1 
       Passport : ABC123 


Applicant 3 => ID : 3 
       IsEndorsed : 0 
       Passport : ABC1234 

Applicant 4 => ID : 4 
       IsEndorsed : 0 
       Passport : A1234 

Applicant 5 => ID : 5 
       IsEndorsed : 1 
       Passport : PQR123 
Applicant 6 => ID : 6 
       IsEndorsed : 1 
       Passport : PQR123 
Applicant 7 => ID : 7 
       IsEndorsed : 0 
       Passport : PQR123 


Expected output : (Grp by Passport Number and in each group IsEndorsed = 0 is at top) 
---------------------------------------------- 

Applicant 1 => ID : 1 
       IsEndorsed : 0 
       Passport : ABC123 

Applicant 2 => ID : 2 
       IsEndorsed : 1 
       Passport : ABC123 

Applicant 3 => ID : 3 
       IsEndorsed : 0 
       Passport : ABC1234 

Applicant 4 => ID : 4 
       IsEndorsed : 0 
       Passport : AX1234 

Applicant 7 => ID : 7 
       IsEndorsed : 0 
       Passport : PQR123 

Applicant 5 => ID : 5 
       IsEndorsed : 1 
       Passport : PQR123 
Applicant 6 => ID : 6 
       IsEndorsed : 1 
       Passport : PQR123 
+2

Можете ли вы добавить некоторые примеры данных и каков ожидаемый результат? – Vlad274

+0

@ Влад274: См. Редактирование –

ответ

8

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

Это OrderBy фактически переводится на SQL-код ORDER BY, поэтому результат также зависит от реализации используемой вами базы данных ORDER BY. Он может быть стабильным или неустойчивым.
Unstable означает, что он может возвращать строки с одинаковым упорядоченным значением в любом порядке.
Стабильный означает, что он вернет их в том же порядке, в каком они были.

SQL Server, например, имеет неустойчивый вид: Is SQL order by clause guaranteed to be stable (by Standards)

Итак, мой вывод, что ToList вызов - единственное различие в обоих запросах - не имеет никакого влияния на результат. Разница просто вызвана нестабильной сортировкой.

+0

Спасибо за объяснение. Я хочу сортировать по логическому значению, чтобы ложное значение находилось сверху, а true - внизу. Какие у меня варианты? –

+1

@VishalAnand Как только у вас будет более двух значений, которые вы сортируете по булевскому значению, порядок значений 'false' будет произвольным. То же самое относится к значениям «истина». Другими словами. Значения 'false' будут поступать до значений' true'. Но какое конкретное значение «false» будет первым, не определено. Если вам нужен определенный порядок, вы можете добавить второй уровень сортировки через 'ThenBy' –