2009-09-21 8 views
5

J'ai une relation parent-table. Dans l'exemple ci-dessous, Foo a un FooID et un ParentFooID nullable qui pointe vers un enregistrement parent.Joints conditionnels dans LINQ

La table Bar est toujours liée à l'enregistrement parent. C'est le SQL que j'utilise pour obtenir le résultat. J'ai un peu de mal à obtenir cela dans une requête LINQ. Je voudrais éviter une jointure croisée comme ce qui suit:

var q = from f in Foo 
      from b in Bar 
      where b.FooID == (f.ParentFooID ?? f.FooID) 

Cheers,

Daniel

Répondre

5

Votre exemple spécifique en utilisant CASE . pour revenir à une valeur non nulle, ce qui est vraiment juste un COALESCE Dans ce cas, cela fonctionne:

var q = from f in dc.Foos 
     join 
     b in dc.Bars 
     on 
     (f.ParentFooID ?? f.FooID) 
     equals 
     b.FooID 
     into grouped 
     select grouped; 

ce qui se traduit par:

SELECT ... 
FROM [dbo].[Foo] AS [t0] 
LEFT OUTER JOIN [dbo].[Bar] AS [t1] 
ON (COALESCE([t0].[ParentFooID],[t0].[FooID])) = [t1].[FooID] 
ORDER BY [t0].[FooID], [t1].[BarID] 

la clé est la joi externe gauche n sur COALESCE(case1, case2), donc le convertisseur d'expression semble comprendre cela.

0

Certains scénarios complexes ne sont pas bien mis en correspondance par LINQ; Je suggère que joindre à un case est l'un d'entre eux. Re le faire comme une jointure croisée ... l'avez-vous profilé? (La SQLfrom ultérieure, le from ... from ... (LINQ) vs le join complexe (TSQL)? Dans de nombreux cas, le profileur peut obtenir le même (ou similaire) plan de requête à partir des approches de style ancien.

+1

J'ai profilé le scénario from ... from et oui, il en résulte une jointure croisée qui effectue un scan d'index (pas une recherche), donc ça va être bien pire que la requête originale qui fait un recherche d'index. – Spruce

+0

Worth testing, au moins. –

1

Ne répond directement à votre question, mais ne serait pas la requête initiale mieux phrasé sans le cas conditionnel:

Select * 
from Foo f 
JOIN Bar b ON b.FooID = f.FooID 
Where f.ParentFooID is null 
UNION ALL 
Select * 
from Foo f 
JOIN Bar b ON b.FooID = f.ParentFooID 
Where f.ParentFooID is not null 

Dans ce cas, l'expression LINQ devrait être plus facile?

Questions connexes