LINQ Join z wieloma warunkami w klauzuli On

94

Próbuję zaimplementować zapytanie w LINQ, które używa lewego sprzężenia zewnętrznego z wieloma warunkami w klauzuli ON.

Posłużę się przykładem następujących dwóch tabel Project (ProjectID, ProjectName) i Task (TaskID, ProjectID, TaskName, Completed). Chcę zobaczyć pełną listę wszystkich projektów z przypisanymi im zadaniami, ale tylko te zadania, które zostały zakończone.

Nie mogę użyć filtru dla, Completed == trueponieważ spowoduje to odfiltrowanie projektów, które nie mają ukończonych zadań. Zamiast tego chcę dodać Completed == trueklauzulę ON w złączeniu, aby wyświetlić pełną listę projektów, ale zostaną wyświetlone tylko ukończone zadania. W projektach bez ukończonych zadań zostanie wyświetlony pojedynczy wiersz z wartością null dla zadania.

Oto podstawa zapytania.

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 }

Jak dodać && t2.Completed == truedo klauzuli on?

Nie mogę znaleźć żadnej dokumentacji LINQ, jak to zrobić.

Kuyenda
źródło
Odpowiedź pokrewne tutaj używając składni lambda
StuartLC

Odpowiedzi:

133

Musisz tylko nazwać anonimową właściwość taką samą po obu stronach

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

Opierając się na komentarzach @svick, oto kolejna implementacja, która może mieć większy sens:

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
źródło
2
To wydaje się nieoczywistym sposobem, aby to zrobić. Nie jestem pewien, czy zrozumiałbym, co to ma zrobić.
Svick
1
@svick - Korzystanie z typów anonimowych umożliwia dołączanie na podstawie wielu kryteriów. Musisz tylko upewnić się, że nazwy właściwości są zgodne w obu typach. Nie wiesz, skąd pochodzi zamieszanie?
Aducci,
Nieporozumienie polega na tym, że ma to większy sens, gdy dwie równości są połączone and, a nie jedna równość jakiegoś „dziwnego” obiektu. Aby udowodnić mój punkt widzenia, twój kod jest błędny. Aby to działało, musiałbyś mieć truepo lewej i t2.Completepo prawej stronie.
Svick
1
Dzięki, Aducci. Musiałem zamienić strony w zapytaniu, aby uzyskać właściwy kontekst, ale to zadziałało. Ten problem jest uproszczony, aw moim prawdziwym problemie nie chodzi tylko o to, że SecondProperty jest prawdą lub fałszem, SecondProperty jest liczbą całkowitą i używam AND SecondProperty IN (123, 456). Podejmę się tego wyzwania i każda pomoc, której mógłbyś udzielić, byłaby bardzo wdzięczna.
Kuyenda
@svick - dobry chwyt, zmieniłem kolejność t2.Completed i wartość true . Dodałem kolejne rozwiązanie, które może być dla Ciebie mniej dziwne.
Aducci,
41

Tutaj idziesz z:

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
źródło
Wygląda to bardziej zrozumiale.
Bijay Yadav
1

Nie możesz tego zrobić w ten sposób. joinKlauzula (a Join()metoda rozszerzenie) obsługuje tylko equijoins. To także powód, dlaczego używa, equalsa nie ==. A nawet gdybyś mógł zrobić coś takiego, to nie zadziała, ponieważ joinjest złączeniem wewnętrznym, a nie złączem zewnętrznym.

svick
źródło
Nie zażądano połączenia zewnętrznego i (zobacz inne odpowiedzi) oczywiście możesz.
edc65
0

Działa to dobrze w przypadku 2 tabel. Mam 3 tabele i na klauzuli muszę połączyć 2 warunki z 3 tabel. Mój kod:

z p w _dbContext.Products dołącz pv w _dbContext.ProductVariants na p.ProduktId równa się pv.ProduktId dołącz jpr w leftJoinQuery na nowym {VariantId = pv.Vid, ProductId = p.ProduktId} równa się nowy {VariantId.Vprices.Vprices. ProductId = jpr.Prices.ProduktID} do lj

Ale w tym momencie pokazuje błąd: dołącz pv w _dbContext.ProductVariants na p.ProduktId równa się pv.ProduktId

Błąd: typ jednego z wyrażeń w klauzuli join jest nieprawidłowy. Wnioskowanie o typie nie powiodło się w wywołaniu „GroupJoin”.

OracleNovice
źródło