2008-12-13 12 views
34

¿Cómo puedo proyectar el número de fila en el conjunto de resultados de la consulta de linq?Cómo proyectar un número de línea en Linq Query Results

En lugar de decir:

campo1, campo2, field3

campo1, campo2, field3

me gustaría:

1, campo1, campo2, field3

2 , campo1, campo2, campo3

Aquí está mi intento en este:

public List<ScoreWithRank> GetHighScoresWithRank(string gameId, int count) 
{ 
    Guid guid = new Guid(gameId); 
    using (PPGEntities entities = new PPGEntities()) 
    { 
     int i = 1; 
     var query = from s in entities.Scores 
        where s.Game.Id == guid 
        orderby s.PlayerScore descending 
        select new ScoreWithRank() 
        { 
         Rank=i++, 
         PlayerName = s.PlayerName, 
         PlayerScore = s.PlayerScore 
        }; 
     return query.ToList<ScoreWithRank>(); 
    } 
} 

Por desgracia, el "Rango = i ++" línea lanza la siguiente excepción en tiempo de compilación:

"Un árbol de expresión no puede contener un operador de asignación"

+0

duplicado posible de [¿Cómo agregar un campo de índice de resultados Linq] (http://stackoverflow.com/questions/269058/how-do-you-add-an-index-field- to-linq-results) –

Respuesta

55

Bueno, el más fácil forma sería la de hacerlo en el lado del cliente en lugar de la parte de base de datos, y utilizar la sobrecarga de Selección que proporciona un índice así:

public List<ScoreWithRank> GetHighScoresWithRank(string gameId, int count) 
{ 
    Guid guid = new Guid(gameId); 
    using (PPGEntities entities = new PPGEntities()) 
    { 
     var query = from s in entities.Scores 
        where s.Game.Id == guid 
        orderby s.PlayerScore descending 
        select new 
        { 
         PlayerName = s.PlayerName, 
         PlayerScore = s.PlayerScore 
        }; 

     return query.AsEnumerable() // Client-side from here on 
        .Select((player, index) => new ScoreWithRank() 
          { 
           PlayerName = player.PlayerName, 
           PlayerScore = player.PlayerScore, 
           Rank = index + 1; 
          }) 
        .ToList(); 

    } 
} 
+3

obteniendo todo de la base de datos en realidad no es una 'solución' – Adaptabi

+1

@DotNetWise: No está obteniendo * todo * de la base de datos, solo el bit que coincide con la consulta. Solo está obteniendo la misma cantidad de datos de la base de datos que el intento original, simplemente haciendo un poco de postprocesamiento. –

+0

¿Cómo es eso? query.AsEnumerable() alimentará todos los registros coincidentes para el gameId dado. Intenta tomar solo las posiciones clasificadas después del 20 °. Obtendrás todo desde el archivo db para tener los rangos y luego cortar lo que necesitas. ¡Realmente no es la solución deseada! Aparte de eso, ¿dónde se usa el parámetro de recuento? – Adaptabi

1

Ok, eso hizo el truco. Gracias.

Aquí está mi código final ...

Servidor:

public List<Score> GetHighScores(string gameId, int count) 
{ 
    Guid guid = new Guid(gameId); 
    using (PPGEntities entities = new PPGEntities()) 
    { 
     var query = from s in entities.Scores 
        where s.Game.Id == guid 
        orderby s.PlayerScore descending 
        select s; 
     return query.ToList<Score>(); 
    }                  
} 

Cliente:

void hsc_LoadHighScoreCompleted(object sender, GetHighScoreCompletedEventArgs e) 
{ 
    ObservableCollection<Score> list = e.Result; 

    _listBox.ItemsSource = list.Select((player, index) => new ScoreWithRank() 
          { 
           PlayerName = player.PlayerName, 
           PlayerScore = player.PlayerScore, 
           Rank = index+=1 
          }).ToList(); 
} 
+0

¿Realmente necesita GetHighScores() para devolver una lista en lugar de un IEnumerable ? Si vas a convertirlo en una lista, tan solo deberías hacerlo una vez. –

+0

@Jon: podría llamar AsEnumerable en su lugar, pero ... El método AsEnumerable no tiene otro efecto que el de cambiar el tipo de fuente en tiempo de compilación. http://msdn.microsoft.com/en-us/library/bb335435.aspx - en otras palabras, no traerá los objetos a la memoria. Si quiere control sobre eso, ToList es bueno –

+0

Sí, pero solo * si * tiene que hacerlo en ese punto. Si no lo necesita, no tiene sentido copiar todos los datos dos veces. De ahí la naturaleza de la pregunta de mi cómplice :) De hecho, incluso AsEnumerable no es necesario, por supuesto, si el método GetHighScores se declara para devolver IEnumerable que lo hará. –

0

También puede hacer sólo un ligero ajuste a su código original para que funcione . Palabra de advertencia, si conecta o accede al objeto nuevamente, el rango aumentará cada vez. En esos casos, la mejor respuesta es mejor.

let Rank = i++ 

y

Rank.ToString() 

código completo:

public List<ScoreWithRank> GetHighScoresWithRank(string gameId, int count) 
{ 
Guid guid = new Guid(gameId); 
using (PPGEntities entities = new PPGEntities()) 
{ 
    int i = 1; 
    var query = from s in entities.Scores 
       let Rank = i++ 
       where s.Game.Id == guid 
       orderby s.PlayerScore descending 
       select new ScoreWithRank() 
       { 
        Rank.ToString(), 
        PlayerName = s.PlayerName, 
        PlayerScore = s.PlayerScore 
       }; 
    return query.ToList<ScoreWithRank>(); 
} 

}

+3

Este código ni siquiera se compilará. Genera el error CS0832: un árbol de expresiones no puede contener un operador de asignación –

Cuestiones relacionadas