Orderby () неправильно упорядочивает номера c # - PullRequest
35 голосов
/ 09 марта 2010

Я пишу приложение для своей компании и в настоящее время работаю над поиском. Когда пользователь ищет элемент, я хочу отобразить самую высокую версию (которая хранится в базе данных).

Проблема в том, что версия сохраняется в виде строки вместо int, и когда я выполняю OrderBy (q => q.Version) для результатов, они возвращаются как

1
10
11
2
3
...

Очевидно, что 2 предшествует 10.

Есть ли способ для меня преобразовать версию в целое число или есть простой IComparer там? Пока я не мог найти ничего существенного.

Я пытался сделать это:

var items = (from r in results
             select r).OrderBy(q => Int32.Parse(q.Version));

Это компилируется, но не работает.

Ответы [ 12 ]

25 голосов
/ 10 марта 2010

Int32.Parse не поддерживается переводчиком LinqToSql. Convert.ToInt32 поддерживается.

http://msdn.microsoft.com/en-us/library/sf1aw27b.aspx

http://msdn.microsoft.com/en-us/library/bb882655.aspx

7 голосов
/ 09 марта 2010

Ваша проблема в другом месте, работает следующее:

new[] { "1", "10", "2", "3", "11" }
    .OrderBy(i => int.Parse(i))
    .ToList()
    .ForEach(Console.WriteLine);

Если ваша проблема связана с LINQ to SQL, то CLR пытается создать SQL из вашего LINQ и не понимает int.Parse. Что вы можете сделать - это сначала получить данные из SQL, а затем заказать их после загрузки всех данных:

var items = (from r in results
             select r)
            .ToList()
            .OrderBy(q => Int32.Parse(q.Version));

Должен это сделать.

6 голосов
/ 09 марта 2010

Если вы не можете изменить определение таблицы (то есть версия является числовым типом), и ваш запрос действительно соответствует списку (вы не используете пропуск, или брать, или иным образом уменьшаете количество результатов), лучше всего вы можете сделать это - вызвать ToList для несортированных результатов, что, когда вы затем примените к нему лямбду OrderBY, будет иметь место в вашем коде, вместо того, чтобы пытаться сделать это на стороне SQL Server (и которая теперь должна работать). 1001 *

5 голосов
/ 16 августа 2012

Есть потрясающий кусок кода, который отлично справляется с задачей естественной сортировки. Его имя <a href="http://www.davekoelle.com/alphanum.html" rel="nofollow">AlphanumComparator</a>.

Пример кода:

var ordered = Database.Cars.ToList().OrderBy(c => c.ModelString, new AlphanumComparator());

Обратите внимание, что список должен быть в памяти.

Если вы получаете версию C #, сделайте это:

AlphanumComparator : IComparer<string>

и

public int Compare(string x, string y)
5 голосов
/ 09 марта 2010

Почему вы сортируете в лямбду? Почему бы вам просто не отсортировать запрос?

var query = from r in items
            orderby int.Parse( r )
            select r;

Теперь, когда мы знаем, что вы используете LINQ to SQL, вы можете подумать о том, чтобы сделать стандартный вызов SQL для этого, выполнив что-то вроде:

Select ..., Cast( TextWhichShouldBeIntCol As int ) As IntCol
From ...

Или даже

Select ..., Cast( TextWhichShouldBeIntCol As int ) As IntCol
From ...
Order By Cast( TextWhichShouldBeIntCol As int )

Это будет сливаться с вашим LINQ как int (и, если вы используете вторую итерацию, вам будет приказано). Это позволяет избежать необходимости проходить через набор результатов дважды в LINQ (один раз для запроса, один раз для заказа).

1 голос
/ 24 мая 2012
var items = (from r in results
         select r).OrderBy(q => Convert.ToInt32(q.Version));

Определенно беги ......

1 голос
/ 09 марта 2010

Почему вы сортируете, если вам нужна только "самая высокая версия"? Похоже, вы могли бы избежать некоторых накладных расходов, если бы использовали Max ().

Кроме того, вам действительно следует изменить тип столбца на целое число.

1 голос
/ 09 марта 2010

попробуйте это:

var items = results.(Select(v => v).OrderBy(v => v.PadLeft(4));

это будет работать в Linq2Sql

1 голос
/ 09 марта 2010

Я сделал тест. У меня есть следующий код.

string[] versions = { "1", "2", "10", "12", "22", "30" };
foreach (var ver in versions.OrderBy(v => v))
{
     Console.WriteLine(ver);
}

Как и следовало ожидать, результат 1, 10, 12, 2, 22, 30 Затем давайте изменим versions.OrderBy(v => v)) на versions.OrderBy(v => int.Parse(v))). И все отлично работает: 1, 2, 10, 12, 22, 30

Я думаю, что ваша проблема в том, что в вашей строке есть нецифровые символы типа '.'. Какое исключение вы получаете?

0 голосов
/ 09 марта 2010
var items = (from v in results
                    select v).ToList().OrderBy(x => int.Parse(x.Version));
...