2010-03-09 16 views
35

Estoy escribiendo una aplicación para mi empresa y actualmente estoy trabajando en la funcionalidad de búsqueda. Cuando un usuario busca un artículo, quiero mostrar la versión más alta (que se almacena en una base de datos).números orderBy() no se ordenan correctamente C#

El problema es que la versión se almacena como una cadena en lugar de int, y cuando lo haga un OrdenarPor (q => q.Version) en los resultados, que se devuelven como

1 
10 
11 
2 
3 
... 

Obviamente 2 viene antes de los 10

¿existe una manera para mí para lanzar la versión como un entero o hay un IComparer sencilla por ahí? No pude encontrar nada sustancial hasta el momento.

He intentado hacer esto:

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

Esto compila pero no funciona.

+2

me habría sugerido exactamente lo que hizo al final de su pregunta (ordenado por 'q => int .Parse (q.Version) '); ¿A qué te refieres con "no funciona"? –

+0

Tal vez su problema está aquí: '(q => Int32.Parse (q.Version))'. ¿Debería ser '(q => Int32.Parse (q))' de acuerdo con las versiones de trabajo a continuación? – MusiGenesis

+1

Recibo este mensaje de error: "Método 'Int32 Parse (System.String)' no tiene traducción soportada a SQL" al ver los resultados enumerados – Darcy

Respuesta

7

Su problema está en otra parte, las siguientes obras:

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

Si su problema es LINQ a SQL, entonces lo que está sucediendo se CLR está intentando crear SQL de su LINQ y no entiende int.Parse . Lo que puede hacer es primero obtener los datos de SQL para luego disponer que una vez que se ha cargado todos los datos:

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

debe hacerlo.

+0

Aparece este mensaje de error: "Método 'Int32 Parse (System.String)' no tiene traducción soportada a SQL" al ver los resultados enumerados. – Darcy

+0

Casting a la Lista (ToList) también funciona. Gracias yuriy. – Darcy

+0

@CodeBlend esta declaración es para Linq a Objetos. –

5

¿Por qué está clasificando en una lambda? ¿Por qué no solo ordena la consulta?

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

Ahora que sabemos que está utilizando LINQ a SQL, podría considerar hacer una llamada SQL estándar en este caso haciendo algo como:

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

O incluso

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

Eso sangrará en su LINQ como int (y si usa la segunda iteración, ordene). Eso evita tener que pasar por el conjunto de resultados dos veces en LINQ (una vez para consultar, una para ordenar).

+0

No es lo mismo – Darcy

+2

No difiere en rendimiento: las bases de datos tienen buenos procesos de clasificación y algunos pueden procesar la creación del conjunto de resultados en paralelo, por lo que la clasificación en la base de datos suele ser más rápida y raramente más lenta. – Mark

+2

No solo eso, está recorriendo en bicicleta la lista dos veces: una para la consulta y otra para la lambda. – Thomas

1

me hizo una prueba. tengo el siguiente código.

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

Como era de esperar el resultado es 1, 10, 12, 2, 22, 30 luego le permite cambiar versions.OrderBy(v => v)) a versions.OrderBy(v => int.Parse(v))). Y funciona bien: 1, 2, 10, 12, 22, 30

Creo que su problema es que tiene caracteres nondigit en su cadena como '.'. ¿Qué tipo de excepción obtienes?

1

intente esto:

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

que va a trabajar en Linq2Sql

6

Si no es capaz de cambiar su definición de la tabla (por lo que la versión es un tipo numérico), y la consulta realmente es tan en la lista (no usa saltar, tomar, o reducir el número de resultados), lo mejor que puede hacer es llamar a "Lista" en los resultados no ordenados, que cuando aplique una orden lambda a ella tendrá lugar en su código , en lugar de tratar de hacerlo en el extremo del servidor SQL (y que ahora debería funcionar).

+0

Ah, funcionó. ¿Por qué esto no funcionaría en la sentencia linq? Porque en el linq está tratando de incluir el caso en el servidor lado? – Darcy

+0

@Darcy: Ver aquí ... http: //www.atrevido.net/blog/2007/09/05/ Llamadas + Personalizadas + Métodos + In + LINQtoSQL.aspx –

+4

Tenga en cuenta que también puede usar 'AsEnumerable' en lugar de' ToList', que cambia el proveedor de consultas a linq-to-objects, pero mantiene la semántica de ejecución diferida de las consultas linq en lugar de forzando la ejecución. –

0

Parece que tiene un valor de texto en lugar de un valor numérico.

Si necesita ordenar, puede intentar:

var items = (from r in results 
      select r); 
return items.OrderBy(v=> Int.Parse(v.Version)); 
0
var query = from r in items 
      let n = int.Parse(r) 
      orderby n 
      select n; 
0
var items = (from v in results 
        select v).ToList().OrderBy(x => int.Parse(x.Version)); 
1

¿Por qué estás ordenando si sólo se necesita "la versión más alta"? Parece que podrías evitar un poco de sobrecarga si usabas Max().

Además, realmente debería cambiar el tipo de columna a entero.

+0

La razón por la que no puedo usar 'Max' es porque necesito la versión más alta de cada artículo. Un elemento sería algo así como "nombre_423_1", donde 1 es el número de versión. Podría haber "name_423_2" y "differentName_234_1" – Darcy

1
var items = (from r in results 
     select r).OrderBy(q => Convert.ToInt32(q.Version)); 

Definitivamente ejecutar ......

5

Hay una impresionante pieza de código que hace un gran trabajo cuando se trata de la clasificación natural. Su nombre es AlphanumComparator.

Código de ejemplo:

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

Tenga en cuenta que la lista debe estar en la memoria.

Si tienes la versión de C#, haga lo siguiente:

AlphanumComparator : IComparer<string> 

y

public int Compare(string x, string y) 
+2

amo este, ¡gracias por compartir! – ozz

+0

no funciona con linq to entity framework – gavin

+0

@gavin: por supuesto, no funcionará si lo que pretende es ejecutar la consulta en el lado de la base de datos. Los valores que se comparan deben estar en la memoria usando algo como '.ToList()' para que 'AlphanumComparator' pueda hacer su trabajo. :) –

Cuestiones relacionadas