Здравствуйте!
Обнаружился на днях в системе баг — оказалось, что пейджинг на странице не работает как надо. При сортировке по некоторым столбцам показывает меньше количество записей, чем есть на самом деле. И вот что оказалось...
Код (в сокращенном виде) примерно такой:
query = query.OrderBy(sortColumnName);
return query.Skip(startRow).Take(max).ToList()
Так вот, оказалось, что если столбец содержит повторяющиеся значения, то скип работает совершенно непредсказуемо.
Т.е. всего например значений больше 700, то где-то с третьей страницы уже ничего нет:
q.Skip(300).Take(100).Count()
100 --Ок
q.Skip(400).Take(100).Count()
0 --Куда делись значения??? Ведь их же больше 700, я это знаю совершенно точно:
q.Take(1000).Count()
759
Проблема решается "легко" — просто добавить дополнительную сортировку по столбцу, где все значения уникальны, например, DateTime. Кул, только конструкция order by col1, col 2 не дает нужного результата почему-то. Нужный результат получается только при использовании ThenBy. Кул, только ThenBy доступен только в IQueryable<>, а он не поддерживает строки в качестве имен столбцов, и выражения надо строить на лету. Поправьте меня, если это не так. Хотя это уже совсем другая история.
Кто-нибудь может объяснить, почему делая сортировку со скипом, мы не можем быть уверены в конечном результате, если значения повторяются?
Спасибо
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, J_K, Вы писали:
J_K>>Кто-нибудь может объяснить, почему делая сортировку со скипом, мы не можем быть уверены в конечном результате, если значения повторяются?
L>В какой sql транслируются эти запросы?
Когда листаю на первую страницу (т.е. беру первые 20 записей и сортирую по Level):
SELECT TOP 20
[Var_122].[Id] AS [Internal_Id],
[Var_122].[Source] AS [Internal_Source],
[Var_122].[LogLevel] AS [Internal_LogLevel],
[Var_122].[Message] AS [Internal_Message],
[Var_122].[DetailedDescription] AS [Internal_DetailedDescription],
[Var_122].[UserId] AS [Internal_UserId],
[Var_122].[Timestamp] AS [Internal_Timestamp],
[Var_122].[UserNameAuthenticated] AS [Internal_UserNameAuthenticated]
FROM [dbo].[Log] AS [Var_122]
WHERE NOT (EXISTS (SELECT [Var_124].[Internal_LogLevel1] AS [Internal_LogLevel1]
FROM ( SELECT TOP 0
[Extent1].[LogLevel] AS [Internal_LogLevel1]
FROM [dbo].[Log] AS [Extent1]
ORDER BY [Extent1].[LogLevel] DESC
) AS [Var_124]
WHERE ([Var_122].[LogLevel] = [Var_124].[Internal_LogLevel1]) OR (([Var_122].[LogLevel] IS NULL) AND ([Var_124].[Internal_LogLevel1] IS NULL))))
ORDER BY [Var_122].[LogLevel] DESC
На последнюю (где результата нет, но должен быть):
SELECT TOP 20
[Var_132].[Id] AS [Internal_Id],
[Var_132].[Source] AS [Internal_Source],
[Var_132].[LogLevel] AS [Internal_LogLevel],
[Var_132].[Message] AS [Internal_Message],
[Var_132].[DetailedDescription] AS [Internal_DetailedDescription],
[Var_132].[UserId] AS [Internal_UserId],
[Var_132].[Timestamp] AS [Internal_Timestamp],
[Var_132].[UserNameAuthenticated] AS [Internal_UserNameAuthenticated]
FROM [dbo].[Log] AS [Var_132]
WHERE NOT (EXISTS (SELECT [Var_134].[Internal_LogLevel1] AS [Internal_LogLevel1]
FROM ( SELECT TOP 760
[Extent1].[LogLevel] AS [Internal_LogLevel1]
FROM [dbo].[Log] AS [Extent1]
ORDER BY [Extent1].[LogLevel] DESC
) AS [Var_134]
WHERE ([Var_132].[LogLevel] = [Var_134].[Internal_LogLevel1]) OR (([Var_132].[LogLevel] IS NULL) AND ([Var_134].[Internal_LogLevel1] IS NULL))))
ORDER BY [Var_132].[LogLevel] DESC