11 giugno 2008 19:11
Left outer Join in LINQ con due condizioni
Non ho trovato molti esempi su come impostare una query Linq2Sql che abbia una Left Outer join con due (o più) condizioni all'interno della join; mi segno quindi qui come penso sia corretto fare:
Supponiamo di avere una tabella Employees (impiegati), una Groups (gruppi) e una JoinEmployeesGroups che mi tenga la relazione molti a molti. Voglio tirare fuori tutti i gruppi, ovvero idGroup e GroupName e una terza colonna che mi indichi se un determinato impiegato è associato a quel gruppo (il classico caso di binding ad una checkboxlist ad esempio).
In Sql, per ottenere ad esempio i gruppi a cui è associato l'impiegato 12, farei:
SELECT g.idGroup,
g.GroupName,
( CASE
WHEN j.idEmployee IS NOT NULL THEN 1
ELSE 0
END ) AS Selected
FROM Groups AS g
LEFT OUTER JOIN JoinEmployeesGroups AS j ON ( g.idGroup = j.idGroup ) AND ( j.idEmployee = 12 )
ORDER BY GroupName
ottenendo
idGroup GroupName Selected
---------- --------------- -----------
MAG Magazzino 0
MGMT Management 1
MANUF Manufacturing 0
PROC Procurement 0
HWDEV Progettisti HW 0
SWDEV Progettisti SW 1
Come tradurla in Linq to Sql ?
var qgroup = from g in db.Groups
join j in db.JoinEmployeesGroups.Where( p => p.idEmployee == 12) on g.idGroup equals j.idGroup into jg
from x in jg.DefaultIfEmpty()
orderby g.GroupName
select new { g.idGroup, g.GroupName, Selected = (x.idEmployee != null) };
La parte blu è quella "tricky" (parola grossa, era ovvio che si facesse così)... Ma dove metterla ? Alla fine non cambia praticamente niente se la mettiamo nella parte della join o nella seconda from (verificato con la query sql che genera)
var qgroup = from g in db.Groups
join j in db.JoinEmployeesGroups on g.idGroup equals j.idGroup into jg
from x in jg.Where( p => p.idEmployee == 12).DefaultIfEmpty()
orderby g.GroupName
select new { g.idGroup, g.GroupName, Selected = (x.idEmployee != null) };
Come bindare alla checkboxlist e selezionare gli item giusti è poi banale
cblGroups.DataSource = qgroup;
cblGroups.DataTextField = "GroupName";
cblGroups.DataValueField = "idGroup";
cblGroups.DataBind();
foreach (var gr in qgroup)
{
ListItem li = cblGroups.Items.FindByValue(gr.idGroup);
li.Selected = gr.Selected;
}
Ogni giorno mi innamoro sempre di più di LINQ... :-)