2009-09-21 15 views
5

Ho una relazione tabella figlio padre. Nell'esempio seguente Foo ha un FooID e un ParentFooID nullable che punta a un record padre.Join condizionali in LINQ

La tabella Bar è sempre collegata al record padre. Questo è l'SQL che uso per ottenere il risultato.

Select * from Foo f 
JOIN Bar b 
    ON b.FooID = 
    CASE 
     WHEN f.ParentFooID is null 
     THEN f.FooID 
     ELSE f.ParentFooID 
    END 

Sto riscontrando un po 'di problemi nel trovarlo in una query LINQ. Mi piacerebbe evitare una cross join come la seguente:

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

Cheers,

Daniel

risposta

5

Il tuo esempio specifico è usando CASE . a cadere di nuovo ad un valore non nullo, che è in realtà solo un COALESCE Nel qual caso, questo funziona:

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

che si traduce in:

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 chiave è il joi esterno sinistro n su COALESCE(case1, case2), quindi il convertitore di espressioni sembra capirlo.

0

Alcuni scenari complessi non sono ben mappati da LINQ; Suggerirei di unirsi a uno case è uno di questi. Riuscendo a farlo come un cross join ... hai il tuo profilo? (Vale a dire la successiva SQLfrom il from ... from ... (LINQ) vs il complesso join (T)? In molti casi il profiler può ottenere lo stesso (o simile) piano di query dagli approcci vecchio stile.

+1

Ho profilato il da ... da scenario e sì, risulta in un cross join che esegue una scansione dell'indice (non una ricerca) quindi andrà a svolgere molto peggio della query originale che sta facendo un indice di ricerca. – Spruce

+0

Vale la pena provare, almeno. –

1

non risponde direttamente alla tua domanda, ma non sarebbe la query originale essere meglio formulato senza il caso condizionale come:

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 

In questo caso, l'espressione LINQ dovrebbe essere più facile?