Linq: Skip в сочетании с OrderBy -> проблемы?
От: J_K  
Дата: 04.02.11 18:51
Оценка:
Здравствуйте!
Обнаружился на днях в системе баг — оказалось, что пейджинг на странице не работает как надо. При сортировке по некоторым столбцам показывает меньше количество записей, чем есть на самом деле. И вот что оказалось...
Код (в сокращенном виде) примерно такой:

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<>, а он не поддерживает строки в качестве имен столбцов, и выражения надо строить на лету. Поправьте меня, если это не так. Хотя это уже совсем другая история.

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

Спасибо
Life is very short and there's no time
for fussing and fighting... (C) Paul McCartney & John Lennon
Re: Linq: Skip в сочетании с OrderBy -> проблемы?
От: Lloyd Россия  
Дата: 04.02.11 20:00
Оценка:
Здравствуйте, J_K, Вы писали:

J_K>Кто-нибудь может объяснить, почему делая сортировку со скипом, мы не можем быть уверены в конечном результате, если значения повторяются?


В какой sql транслируются эти запросы?
Re[2]: Linq: Skip в сочетании с OrderBy -> проблемы?
От: J_K  
Дата: 04.02.11 20:54
Оценка:
Здравствуйте, 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
Life is very short and there's no time
for fussing and fighting... (C) Paul McCartney & John Lennon
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.