Jeśli używany jest dostawca LINQ oparty na bazie danych, można znacznie lepiej odczytać lewe łączenie zewnętrzne:
from maintable in Repo.T_Whatever
from xxx in Repo.T_ANY_TABLE.Where(join condition).DefaultIfEmpty()
Jeśli pominiesz to DefaultIfEmpty()
, będziesz mieć wewnętrzne połączenie.
Weź przyjętą odpowiedź:
from c in categories
join p in products on c equals p.Category into ps
from p in ps.DefaultIfEmpty()
Ta składnia jest bardzo myląca i nie jest jasne, jak to działa, gdy chcesz opuścić dołączanie do WIELU tabel.
Uwaga
Należy zauważyć, żefrom alias in Repo.whatever.Where(condition).DefaultIfEmpty()
jest to to samo, co zewnętrzny-zastosuj / lewy-złącz-boczny, który dowolny (porządny) optymalizator bazy danych jest w stanie doskonale przetłumaczyć na lewe złączenie, o ile nie wprowadzisz poszczególnych wierszy -wartości (inaczej rzeczywiste zastosowanie zewnętrzne). Nie rób tego w Linq-2-Objects (ponieważ nie ma optymalizatora DB, gdy używasz Linq-to-Objects).
Szczegółowy przykład
var query2 = (
from users in Repo.T_User
from mappings in Repo.T_User_Group
.Where(mapping => mapping.USRGRP_USR == users.USR_ID)
.DefaultIfEmpty() // <== makes join left join
from groups in Repo.T_Group
.Where(gruppe => gruppe.GRP_ID == mappings.USRGRP_GRP)
.DefaultIfEmpty() // <== makes join left join
// where users.USR_Name.Contains(keyword)
// || mappings.USRGRP_USR.Equals(666)
// || mappings.USRGRP_USR == 666
// || groups.Name.Contains(keyword)
select new
{
UserId = users.USR_ID
,UserName = users.USR_User
,UserGroupId = groups.ID
,GroupName = groups.Name
}
);
var xy = (query2).ToList();
W połączeniu z LINQ 2 SQL ładnie przełoży się na następujące bardzo czytelne zapytanie SQL:
SELECT
users.USR_ID AS UserId
,users.USR_User AS UserName
,groups.ID AS UserGroupId
,groups.Name AS GroupName
FROM T_User AS users
LEFT JOIN T_User_Group AS mappings
ON mappings.USRGRP_USR = users.USR_ID
LEFT JOIN T_Group AS groups
ON groups.GRP_ID == mappings.USRGRP_GRP
Edytować:
Zobacz także „
Konwertuj zapytanie SQL Server na zapytanie Linq ”, aby uzyskać bardziej złożony przykład.
Ponadto, jeśli robisz to w Linq-2-Objects (zamiast Linq-2-SQL), powinieneś to zrobić w staromodny sposób (ponieważ LINQ na SQL tłumaczy to poprawnie, aby połączyć operacje, ale nad obiektami ta metoda wymusza pełne skanowanie i nie korzysta z wyszukiwania indeksów, cokolwiek ...):
var query2 = (
from users in Repo.T_Benutzer
join mappings in Repo.T_Benutzer_Benutzergruppen on mappings.BEBG_BE equals users.BE_ID into tmpMapp
join groups in Repo.T_Benutzergruppen on groups.ID equals mappings.BEBG_BG into tmpGroups
from mappings in tmpMapp.DefaultIfEmpty()
from groups in tmpGroups.DefaultIfEmpty()
select new
{
UserId = users.BE_ID
,UserName = users.BE_User
,UserGroupId = mappings.BEBG_BG
,GroupName = groups.Name
}
);