web-dev-qa-db-fra.com

LINQ - Rejoindre à gauche, grouper par et compter

Disons que j'ai ce SQL:

SELECT p.ParentId, COUNT(c.ChildId)
FROM ParentTable p
  LEFT OUTER JOIN ChildTable c ON p.ParentId = c.ChildParentId
GROUP BY p.ParentId

Comment puis-je traduire cela en LINQ to SQL? Je me suis retrouvé coincé au COUNT (c.ChildId), le SQL généré semble toujours sortir COUNT (*). Voici ce que j'ai eu jusqu'à présent:

from p in context.ParentTable
join c in context.ChildTable on p.ParentId equals c.ChildParentId into j1
from j2 in j1.DefaultIfEmpty()
group j2 by p.ParentId into grouped
select new { ParentId = grouped.Key, Count = grouped.Count() }

Je vous remercie!

165
pbz
from p in context.ParentTable
join c in context.ChildTable on p.ParentId equals c.ChildParentId into j1
from j2 in j1.DefaultIfEmpty()
group j2 by p.ParentId into grouped
select new { ParentId = grouped.Key, Count = grouped.Count(t=>t.ChildId != null) }
185
Mehrdad Afshari

Pensez à utiliser une sous-requête:

from p in context.ParentTable 
let cCount =
(
  from c in context.ChildTable
  where p.ParentId == c.ChildParentId
  select c
).Count()
select new { ParentId = p.Key, Count = cCount } ;

Si les types de requête sont connectés par une association, cela simplifie:

from p in context.ParentTable 
let cCount = p.Children.Count()
select new { ParentId = p.Key, Count = cCount } ;
55
Amy B

TARD REPONSE:

Vous ne devriez pas avoir besoin de la jointure gauche du tout si tout ce que vous faites est Count (). Notez que join...into est en fait traduit en GroupJoin qui renvoie des groupements tels que new{parent,IEnumerable<child>} de sorte qu'il vous suffit d'appeler Count() sur le groupe:

from p in context.ParentTable
join c in context.ChildTable on p.ParentId equals c.ChildParentId into g
select new { ParentId = p.Id, Count = g.Count() }

Dans la méthode d'extension, la syntaxe join into équivaut à GroupJoin (alors qu'une join sans into correspond à Join):

context.ParentTable
    .GroupJoin(
                   inner: context.ChildTable
        outerKeySelector: parent => parent.ParentId,
        innerKeySelector: child => child.ParentId,
          resultSelector: (parent, children) => new { parent.Id, Count = children.Count() }
    );
33
Eren Ersönmez
 (from p in context.ParentTable     
  join c in context.ChildTable 
    on p.ParentId equals c.ChildParentId into j1 
  from j2 in j1.DefaultIfEmpty() 
     select new { 
          ParentId = p.ParentId,
         ChildId = j2==null? 0 : 1 
      })
   .GroupBy(o=>o.ParentId) 
   .Select(o=>new { ParentId = o.key, Count = o.Sum(p=>p.ChildId) })
7
雪域飞貂

Bien que la syntaxe LINQ repose sur l’émulation de la syntaxe SQL, vous ne devriez pas toujours penser à traduire directement votre code SQL en LINQ. Dans ce cas particulier, il n'est pas nécessaire de faire group into car join into est un groupe à joindre lui-même.

Voici ma solution:

from p in context.ParentTable
join c in context.ChildTable on p.ParentId equals c.ChildParentId into joined
select new { ParentId = p.ParentId, Count = joined.Count() }

Contrairement à la solution la plupart du temps votée ici, nous n’avons pas besoin de j1, j2 et de la vérification nulle dans Count (t => t.ChildId! = Null)

7
Mosh