2015-09-26 2 views
0

J'ai trois tables ("Ratings", "Comments" et "Users"). Une note peut avoir plusieurs commentaires. Un commentaire appartient à un utilisateur.Comment regrouper plus de deux tables en utilisant Linq

Jusqu'ici, j'ai cette instruction LINQ qui fonctionne bien.

from rating in Ratings 
join comment in Comments 
on rating.ID equals comment.RatingID 
join user in Users 
on comment.UserID equals user.ID 
select new {rating, comment, user} 
.Where(x => x.rating.LocationID == 3); 

Comment puis-je grouper ceci?

+4

ce groupe avez-vous besoin? – Backs

+1

Si vous utilisez les propriétés de navigation, il se peut que vous n'ayez besoin d'aucun regroupement. –

Répondre

3

Cela dépend un peu de ce que vous voulez regrouper. Mais il existe une multitude de solutions.

Solution 1:

Disons que vous voulez groupe par notes, vous pouvez faire:

var query1 = from rating in db.Ratings 
       join comment in db.Comments 
        on rating.ID equals comment.RatingID 
       join user in db.Users 
        on comment.UserID equals user.ID 
       group new { comment, user } by rating into g 
       select new { g.Key, l = g.ToList() }; 

foreach (var row in query1) 
{ 
    // you get rows grouped by rating 
    Debug.WriteLine(row.Key.ID); // rating.ID 

    // and a list of comments/users per rating 
    foreach (var g in row.l) 
    { 
     Debug.WriteLine(g.comment.ID); 
     Debug.WriteLine(g.user.ID); 
    } 
} 

Cela vous donne une seule ligne par note. Et l'objet dynamique g contient une liste de paires commentaire/utilisateur par évaluation.

Solution 2:

Cependant, comme @gertarnold mentionné, il est plus facile à lire juste l'objet que vous voulez regrouper par. Et puis traverser ses propriétés. Comme ceci:

var query2 = db.Ratings; 

foreach (var rating in query2) 
{ 
    Debug.WriteLine(rating.name); 
    foreach (var comment in rating.Comments) 
    { 
     Debug.WriteLine(comment.name); 
     Debug.WriteLine(comment.User.name); 
    } 
} 

Ceci est beaucoup plus facile à comprendre. Il a un inconvénient de performance difficile, car il effectue une base de données distincte pour chaque commentaire dans la boucle interne. Si une note a beaucoup de nombreux commentaires, alors c'est très lent. Le premier exemple avec le regroupement tire tout dans une seule instruction de base de données SELECT, ce qui est beaucoup plus rapide.

Solution 3:

Et il y a un moyen d'avoir le meilleur des deux solutions. Faites comme en solution 2 et ajouter un peu DataLoadOptions devant lui:

DataLoadOptions options = new DataLoadOptions(); 
options.LoadWith<Rating>(rating => rating.Comments); 
options.LoadWith<Comment>(comment => comment.User); 
db.LoadOptions = options; 

Cela précharger toutes les évaluations avec tous les objets enfants nécessaires dans un seul SELECT. C'est rapide et facile à lire et à comprendre.

PS: Juste une note de côté: Les tableaux doivent être nommés au singulier. Dans ce cas, Rating, Comment et User au lieu de Ratings, Comments et Users. PS2: Pour obtenir également des notes sans commentaires dans la solution 1, vous devez convertir les jointures en jointures externes. Comme ceci:

var query1 = from rating in db.Ratings 
     join comment in db.Comments 
      on rating.ID equals comment.RatingID into j1 
     from comment in j1.DefaultIfEmpty() 
     join user in db.Users 
      on comment.UserID equals user.ID into j2 
     from user in j2.DefaultIfEmpty()         
     group new { comment, user } by rating into g 
     select new { g.Key, l = g.ToList() }; 

voir aussi: 101 LINQ Samples - Left outer join

+0

Merci beaucoup pour votre réponse détaillée, @nharrer! Cela n'aurait pas pu être mieux expliqué que vous. Je comprends cet avantage de la solution 2 et de la solution 3. Cependant, je fais aussi une "déclaration WHERE", donc je ne veux pas avoir la liste complète. La solution 1 fonctionne bien pour moi. Le seul problème est maintenant que je reçois seulement des évaluations qui ont des commentaires.Pouvez-vous s'il vous plaît me dire comment je reçois toutes les notes? Merci une fois de plus. J'apprécie vraiment :) – user1705950

+0

Ensuite, vous auriez besoin de jointures externes gauche. J'ai ajouté un exemple sous PS2 – nharrer

+0

Merci beaucoup. – user1705950