2009-03-29 14 views
157

Lassen Sie uns sagen, ich habe diese SQL:LINQ - LEFT JOIN, Gruppe By, und Graf

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

Wie kann ich dies in LINQ to SQL übersetzen? Ich bin bei COUNT (c.ChildId) hängengeblieben, das generierte SQL scheint immer COUNT (*) auszugeben. Hier ist, was ich bis jetzt bekam:

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

Vielen Dank!

Antwort

179
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) } 
+0

OK, das funktioniert, aber warum? Wie denkst du darüber? Wie zählen NULL-Werte uns nicht wie COUNT (C.ChildId)? Vielen Dank. – pbz

+4

So funktioniert SQL. COUNT (Feldname) zählt die Zeilen in diesem Feld, die nicht null sind. Vielleicht bekomme ich Ihre Frage nicht, bitte klären Sie, ob das der Fall ist. –

+0

Ich denke, ich dachte immer über das Zählen von Zeilen nach, aber Sie haben Recht, nur die Nicht-Null-Werte werden gezählt. Vielen Dank. – pbz

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

Betrachten Sie eine Unterabfrage:

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

Wenn die Abfragetypen, die von einem Verband angeschlossen sind, dies vereinfacht zu:

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

Wenn ich mich richtig erinnere (es ist eine Weile her), war diese Abfrage eine vereinfachte Version eines großen. Wenn alles, was ich brauchte, der Schlüssel und die Zählung wäre, wäre Ihre Lösung sauberer/besser gewesen. – pbz

+1

Ihr Kommentar ergibt keinen Sinn im Zusammenhang mit der ursprünglichen Frage und den Antworten mit der Antwort. Zusätzlich - wenn Sie mehr als den Schlüssel möchten, haben Sie die ganze Elternzeile, aus der Sie zeichnen können. –

+0

das hilft mir mit einem etwas verwandten Problem, danke – Merritt

26

LATE ANTWORT:

Sie sollten nicht die linke Join überhaupt brauchen, wenn Sie nur Count() tun. Beachten Sie, dass join...into tatsächlich auf GroupJoin übersetzt, die wie new{parent,IEnumerable<child>} Gruppierungen gibt, so müssen Sie rufen Sie einfach Count() auf die Gruppe:

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

In Erweiterungsmethode Syntax ein join into entspricht GroupJoin (während ein join ohne into ist Join):

context.ParentTable 
    .GroupJoin(
        inner: context.ChildTable 
     outerKeySelector: parent => parent.ParentId, 
     innerKeySelector: child => child.ParentId, 
      resultSelector: (parent, children) => new { parent.Id, Count = children.Count() } 
    ); 
+1

Das ist eine schöne und einfache Lösung für das Problem, danke! –

+0

Dies ist besser als andere Lösungen und sollte die Antwort für diese Frage sein. –

5

Während die Idee hinter LINQ-Syntax der SQL-Syntax zu emulieren ist, können Sie nicht immer direkt übersetzt Ihren SQL-Code in LINQ denken sollen. In diesem speziellen Fall müssen wir keine Gruppe in tun, da in beitritt, ist eine Gruppe selbst beitreten.

Hier ist meine Lösung:

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

Im Gegensatz zu den meist Lösung hier gestimmt haben, brauchen wir nicht j1, j2 und null Prüfung in Count (t => t.ChildId = null!)