LINQ的GroupBy然后OrderBy的行为

3

我有一个场景,需要先按组分组,然后对每个组进行排序。我想出了以下可行的查询:

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();

第一个查询返回了申请人的Id,结果如下:
7, 10, 8, 2, 9, 6, 5, 3, 4, 1
但是第二个查询返回了:
7, 10, 8, 2, 9, 6, 3, 4, 5, 1

我不确定为什么会出现这种情况,两个查询之间有什么区别。
我到底错在哪里了吗?

编辑: 示例输入和期望输出:

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
@Vlad274:请查看编辑。 - Vishal Anand
1个回答

8
您正在按布尔值进行排序。一旦一个组中的两个值具有相同的IsEndorseChild值,它们相对于彼此的顺序通常是未定义的。
OrderBy实际上被转换为SQL ORDER BY,因此结果还取决于您使用的数据库的ORDER BY实现。它可以是不稳定的或稳定的。
不稳定意味着它可以以任何顺序返回具有相同排序值的行。
稳定意味着它将以输入的相同顺序返回它们。
例如,SQL Server具有不稳定的排序: Is SQL order by clause guaranteed to be stable ( by Standards) 因此,我的结论是,ToList调用——两个查询中唯一的区别——对结果没有影响。差异仅仅是由不稳定的排序引起的。

谢谢您的解释。我想按布尔值排序,使得假值在顶部,真值在底部。我有哪些选择? - Vishal Anand
1
@VishalAnand 当你有超过两个值需要按布尔值排序时,false 值的顺序将是任意的。同样适用于 true 值。换句话说,false 值将出现在 true 值之前。但是哪个具体的 false 值将是第一个是未定义的。如果你想要一个明确的顺序,可以通过 ThenBy 添加第二个排序级别。 - Daniel Hilgarth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接