2009-09-21 19 views
5

Tengo una relación de tabla secundaria principal. En el ejemplo siguiente, Foo tiene un FooID y un ParentFooID que admite nulos que apunta a un registro principal.Uniones condicionales en LINQ

La tabla de barras siempre está vinculada al registro principal. Este es el SQL que uso para obtener el resultado.

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

Tengo algunos problemas para conseguir esto en una consulta LINQ. Me gustaría evitar una combinación cruzada como la siguiente:

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

Cheers,

Daniel

Respuesta

5

Su ejemplo específico es el uso de CASE . a caer de nuevo a un valor no nulo, que es en realidad un COALESCE En cuyo caso, esto funciona:

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

que se traduce en:

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 clave es el joi externa izquierda n en COALESCE(case1, case2), por lo que el convertidor de expresiones parece entender eso.

0

Algunos escenarios complejos no están bien asignadas por LINQ; Sugeriría que unirse a un case es uno de ellos. Rehaciéndolo como un cruce ... ¿lo has perfilado? (Es decir, la posterior SQLfrom la from ... from ... (LINQ) vs el complejo join (TSQL)? En muchos casos el generador de perfiles puede conseguir la misma (o similar) plan de consulta de los enfoques de estilo antiguo.

+1

He descrito el escenario desde ... desde y sí, resulta en una unión cruzada que hace un escaneo de índice (no una búsqueda) por lo que va a funcionar mucho peor que la consulta original que está haciendo un búsqueda de índice – Spruce

+0

Vale la pena probar, al menos. –

1

no responde directamente a su pregunta, pero no sería la consulta original debería formularse sin el caso condicional como:

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 

En este caso, la expresión LINQ debería ser más fácil?