LINQ Join mit mehreren Bedingungen in On-Klausel

93

Ich versuche, eine Abfrage in LINQ zu implementieren, die einen linken äußeren Join mit mehreren Bedingungen in der ON-Klausel verwendet.

Ich verwende das Beispiel der folgenden beiden Tabellen Project (ProjectID, ProjectName) und Task (TaskID, ProjectID, TaskName, Completed). Ich möchte die vollständige Liste aller Projekte mit ihren jeweiligen Aufgaben sehen, aber nur die Aufgaben, die abgeschlossen sind.

Ich kann keinen Filter für verwenden, Completed == trueda dadurch alle Projekte herausgefiltert werden, für die keine Aufgaben abgeschlossen wurden. Stattdessen möchte ich Completed == truedie ON-Klausel des Joins hinzufügen , damit die vollständige Liste der Projekte angezeigt wird, aber nur abgeschlossene Aufgaben angezeigt werden. Projekte ohne abgeschlossene Aufgaben zeigen eine einzelne Zeile mit einem Nullwert für Aufgabe an.

Hier ist die Grundlage der Abfrage.

from t1 in Projects
join t2 in Tasks
on new { t1.ProjectID} equals new { t2.ProjectID } into j1
from j2 in j1.DefaultIfEmpty()
select new { t1.ProjectName, t2.TaskName }

Wie füge ich && t2.Completed == trueder on-Klausel hinzu?

Ich kann anscheinend keine LINQ-Dokumentation dazu finden.

Kuyenda
quelle
Verwandte Antwort hier mit Lambda-Syntax
StuartLC

Antworten:

130

Sie müssen nur die anonyme Eigenschaft auf beiden Seiten gleich benennen

on new { t1.ProjectID, SecondProperty = true } equals 
   new { t2.ProjectID, SecondProperty = t2.Completed } into j1

Basierend auf den Kommentaren von @svick ist hier eine weitere Implementierung, die sinnvoller sein könnte:

from t1 in Projects
from t2 in Tasks.Where(x => t1.ProjectID == x.ProjectID && x.Completed == true)
                .DefaultIfEmpty()
select new { t1.ProjectName, t2.TaskName }
Aducci
quelle
2
Das scheint ein nicht offensichtlicher Weg zu sein. Ich bin mir nicht sicher, ob ich verstehen würde, was ich tun soll.
Svick
1
@svick - Mit anonymen Typen können Sie mehreren Kriterien beitreten. Sie müssen nur sicherstellen, dass die Eigenschaftsnamen für beide Typen übereinstimmen. Nicht sicher, woher die Verwirrung kommt?
Aducci
Die Verwirrung ist, dass es wirklich sinnvoller ist, wenn zwei Gleichheiten miteinander verbunden sind and, nicht eine Gleichheit eines „seltsamen“ Objekts. Und um meinen Standpunkt zu beweisen, ist Ihr Code falsch. Damit es funktioniert, müssten Sie trueauf der linken Seite und t2.Completeauf der rechten Seite haben.
Svick
1
Danke Aducci. Ich musste die Seiten in der Abfrage tauschen, um den richtigen Kontext zu erhalten, aber das hat funktioniert. Dieses Problem ist vereinfacht, und in meinem realen Problem ist SecondProperty nicht nur wahr oder falsch, SecondProperty ist eine Ganzzahl, die ich verwende AND SecondProperty IN (123, 456). Ich werde mich dieser Herausforderung stellen und jede Hilfe, die Sie geben könnten, wäre sehr dankbar.
Kuyenda
@svick - Guter Fang, ich habe die Reihenfolge des t2.Completed und den wahren Wert geändert . Ich habe eine weitere Lösung hinzugefügt, die für Sie möglicherweise weniger seltsam ist.
Aducci
38

Hier geht's mit:

from b in _dbContext.Burden 
join bl in _dbContext.BurdenLookups on
new { Organization_Type = b.Organization_Type_ID, Cost_Type = b.Cost_Type_ID } equals
new { Organization_Type = bl.Organization_Type_ID, Cost_Type = bl.Cost_Type_ID }
Nalan Madheswaran
quelle
Das sieht verständlicher aus.
Bijay Yadav
1

Das kannst du nicht so machen. Die joinKlausel (und die Join()Erweiterungsmethode) unterstützen nur Equijoins. Das ist auch der Grund, warum es verwendet equalsund nicht ==. Und selbst wenn Sie so etwas tun könnten, würde es nicht funktionieren, da joines sich um eine innere Verknüpfung handelt, nicht um eine äußere Verknüpfung.

svick
quelle
Eine äußere Verbindung wurde nicht angefordert, und (siehe andere Antworten) natürlich können Sie.
edc65
0

Dies funktioniert gut für 2 Tabellen. Ich habe 3 Tabellen und die on-Klausel muss 2 Bedingungen aus 3 Tabellen verknüpfen. Mein Code:

from p in _dbContext.Products join pv in _dbContext.ProductVariants on p.ProduktId entspricht pv.ProduktId join jpr in leftJoinQuery on new {VariantId = pv.Vid, ProductId = p.ProduktId} entspricht new {VariantId = jpr.Pr ProductId = jpr.Prices.ProduktID} in lj

An dieser Stelle wird jedoch ein Fehler angezeigt: Join pv in _dbContext.ProductVariants auf p.ProduktId entspricht pv.ProduktId

Fehler: Der Typ eines der Ausdrücke in der Join-Klausel ist falsch. Die Typinferenz ist beim Aufruf von 'GroupJoin' fehlgeschlagen.

OracleNovice
quelle