Сортировка списка Linq с одним столбцом - PullRequest
3 голосов
/ 19 августа 2011

Я думаю, это должно быть очень просто, но я не могу найти, как это сделать. У меня есть запрос linq, который выбирает один столбец, типа int, и мне нужно его отсортировать.

var values = (from p in context.Products
              where p.LockedSince == null
              select Convert.ToInt32(p.SearchColumn3)).Distinct();
values = values.OrderBy(x => x);

SearchColumn3 является строкой типа op, но я содержит только целые числа. Поэтому я подумал, что преобразование в Int32 и упорядочение определенно дадут мне хороший список значений, отсортированный по 1,2,3. Но вместо этого список остается упорядоченным, как строки.

199 20 201

Обновление: Я сделал несколько тестов с кодом C # и LinqPad. LinqPad генерирует следующий SQL:

SELECT [t2].[value]
FROM (
    SELECT DISTINCT [t1].[value]
    FROM (
        SELECT CONVERT(Int,[t0].[SearchColumn3]) AS [value], [t0].[LockedSince], [t0].[SearchColumn3]
        FROM [Product] AS [t0]
        ) AS [t1]
    WHERE ([t1].[LockedSince] IS NULL)
    ) AS [t2]
ORDER BY [t2].[value]

И мой профилировщик SQL говорит, что мой код C # генерирует этот фрагмент SQL:

SELECT DISTINCT a.[SearchColumn3] AS COL1                  
FROM [Product] a 
WHERE a.[LockedSince] IS NULL 
ORDER BY a.[SearchColumn3] 

Так что, похоже, код C # Linq просто опускает Convert.ToInt32. Кто-нибудь может сказать что-нибудь полезное по этому поводу?

Ответы [ 4 ]

3 голосов
/ 25 августа 2011

[Отказ от ответственности - я работаю в Telerik]

Эту проблему также можно решить с помощью Telerik OpenAccess ORM. Вот что я бы предложил в этом случае.

var values = (from p in context.Products
              where p.LockedSince == null
              orderby "cast({0} as integer)".SQL<int>(p.SearchColumn3)
              select "cast({0} as integer)".SQL<int>(p.SearchColumn3)).ToList().Distinct();

OpenAccess предоставляет метод расширения SQL, который дает вам возможность добавить определенный код SQL в сгенерированный оператор SQL. Мы начали работать над улучшением этого поведения. Спасибо, что указали на это.

Привет

Ralph

2 голосов
/ 21 августа 2011

Тот же ответ, что и на мои другие вопросы, оказывается, что провайдер Linq, который я использую, тот, который поставляется с Telerik OpenAccess ORM, делает вещи, отличные от стандартного провайдера Linq to SQL!Смотрите SQL, который я разместил в своем вступительном посте!Я совсем не ожидал чего-то подобного, но мне кажется, что Telerik OpenAccess все еще нуждается в значительном улучшении.Так что будьте осторожны, прежде чем начать его использовать.Выглядит красиво, но у него есть серьезные недостатки.

1 голос
/ 19 августа 2011

Я не могу воспроизвести эту проблему. Но просто убедитесь, что вы перечисляете коллекцию, когда осматриваете ее. Как вы проверяете результат?

values = values.OrderBy(x => x);
foreach (var v in values)
{
    Console.WriteLine(v.ToString());
}

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

0 голосов
/ 19 августа 2011

Поскольку ваша переменная values является результатом выражения Linq, так что в действительности она не имеет значений, пока вы не вызовете метод, такой как ToList, ToArray и т. Д.

Возвращаясь к вашему примеру, переменная x в методе OrderBy будет обрабатываться как p.SearchColumn3 и, следовательно, это строка.

Чтобы избежать этого, вам нужно, чтобы p.SearchColumn3 стал целым числом перед OrderBy методом. Вы должны добавить оператор let в свой код, как показано ниже:

var values = (from p in context.Products
              where p.LockedSince == null
              let val = Convert.ToInt32(p.SearchColumn3)
              select val).Distinct();
values = values.OrderBy(x => x);

Кроме того, вы можете комбинировать порядок по заявке с первым, это будет хорошо.

...