2008-12-13 8 views
34

Comment puis-je projeter le numéro de ligne sur le jeu de résultats de requête linq.Comment projeter un numéro de ligne dans les résultats de requête Linq

Au lieu de dire:

champ1, champ2, field3

champ1, champ2, field3

Je voudrais:

1, champ1, champ2, field3

2 , field1, field2, field3

Voici ma tentative à ceci:

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>(); 
    } 
} 

Malheureusement, le "Rank = i ++" ligne lève l'exception à la compilation suivante:

"Un arbre d'expression ne peut pas contenir un opérateur d'affectation"

+0

double possible de [Comment ajouter un champ d'index aux résultats Linq] (http://stackoverflow.com/questions/269058/how-do-you-add-an-index-field- to-linq-results) –

Répondre

55

Eh bien, le plus facile moyen serait de le faire à côté client plutôt que du côté de la base de données et utiliser la surcharge de Select qui fournit un indice ainsi:

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

obtenir tout de la base de données ce n'est pas vraiment une 'solution' – Adaptabi

+1

@DotNetWise: Cela n'obtient pas * tout * de la base de données - seulement le bit qui correspond à la requête. Il obtient seulement la même quantité de données de la base de données que la tentative originale - juste faire un peu de post-traitement. –

+0

Comment ça? query.AsEnumerable() alimentera tous les enregistrements correspondants pour le gameId donné. Essayez de ne prendre que les positions classées après le 20ème. Vous obtiendrez tout de la db afin d'avoir les rangs et ensuite découper ce dont vous avez besoin. Pas vraiment la solution désirée! Autre que cela - où le paramètre count est-il utilisé? – Adaptabi

1

Ok, qui a fait l'affaire. Merci.

Voici mon code final ...

serveur:

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>(); 
    }                  
} 

Client:

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

Avez-vous vraiment besoin de GetHighScores() pour retourner une liste au lieu d'un IEnumerable ? Si vous allez le convertir en une liste, vous pourriez aussi bien le faire une seule fois. –

+0

@Jon: Il pourrait appeler AsEnumerable à la place mais ... La méthode AsEnumerable n'a d'autre effet que de changer le type de source de la compilation. http://msdn.microsoft.com/en-us/library/bb335435.aspx - en d'autres termes, il ne mettra pas les objets en mémoire. S'il veut contrôler cela, ToList est bon –

+0

Oui, mais seulement * si * il doit le faire à ce moment-là. S'il n'en a pas besoin, il ne sert à rien de copier deux fois toutes les données. D'où la question nature de mon cooment :) En fait même AsEnumerable n'est pas nécessaire bien sûr - si la méthode GetHighScores est déclarée pour retourner IEnumerable qui le fera. –

0

Vous pouvez aussi faire juste un léger ajustement à votre code d'origine pour le faire fonctionner . Un mot d'avertissement, si vous databind ou accédez à l'objet à nouveau, le rang augmentera à chaque fois. Dans ces cas, la meilleure réponse est meilleure.

let Rank = i++ 

et

Rank.ToString() 

code complet:

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

Ce code ne sera même pas compilé. Il génère l'erreur CS0832: Une arborescence d'expression ne peut pas contenir d'opérateur d'affectation. –

Questions connexes