2009-03-31 9 views
121

¿Es esta consulta equivalente a un LEFT OUTER unirse?LINQ to SQL Left External Unir

//assuming that I have a parameter named 'invoiceId' of type int 
from c in SupportCases 
let invoice = c.Invoices.FirstOrDefault(i=> i.Id == invoiceId) 
where (invoiceId == 0 || invoice != null)  
select new 
{ 
     Id = c.Id 
     , InvoiceId = invoice == null ? 0 : invoice.Id 
} 

Respuesta

141

No del todo - ya que cada fila "izquierda" en el lateral izquierdo de combinación externa coincidirá 0-n filas "correctas" (en la segunda tabla), donde-como la suya sólo coincide 0-1. Para hacer una combinación externa izquierda, necesita SelectMany y DefaultIfEmpty, por ejemplo:

var query = from c in db.Customers 
      join o in db.Orders 
       on c.CustomerID equals o.CustomerID into sr 
      from x in sr.DefaultIfEmpty() 
      select new { 
       CustomerID= c.CustomerID, ContactName=c.ContactName, 
       OrderID = x.OrderID == null ? -1 : x.OrderID}; 

(or via the extension methods)

+4

LINQ to Entities no reconoce el método DefaultIfEmpty ... –

+13

¿Puede alguien explicar cómo funciona esta sintaxis loca? No veo cómo una de esas palabras clave mágicamente la convierte en una combinación de la izquierda. ¿Qué hace el "into sr"? Linq me frustra a veces :) –

+1

@JoePhillips Tengo mucha experiencia SQL, pero tratar de aprender LINQ es como vadear barro. Estoy de acuerdo, es absolutamente loco. –

12
Public Sub LinqToSqlJoin07() 
Dim q = From e In db.Employees _ 
     Group Join o In db.Orders On e Equals o.Employee Into ords = Group _ 
     From o In ords.DefaultIfEmpty _ 
     Select New With {e.FirstName, e.LastName, .Order = o} 

ObjectDumper.Write(q) End Sub 

Comprobar http://msdn.microsoft.com/en-us/vbasic/bb737929.aspx

+0

Buen intento, pero parece que el OP está utilizando C#. La sintaxis de VB es extrañamente diferente. – Levitikon

+3

+1 Simplemente porque este es un buen ejemplo de vb.net – twoleggedhorse

4

me encontré con 1 solución. Si desea traducir este tipo de SQL (izquierda se unen) en LINQ Entidad ...

SQL:

SELECT * FROM [JOBBOOKING] AS [t0] 
LEFT OUTER JOIN [REFTABLE] AS [t1] ON ([t0].[trxtype] = [t1].[code]) 
            AND ([t1]. [reftype] = "TRX") 

LINQ:

from job in JOBBOOKINGs 
join r in (from r1 in REFTABLEs where r1.Reftype=="TRX" select r1) 
      on job.Trxtype equals r.Code into join1 
from j in join1.DefaultIfEmpty() 
select new 
{ 
    //cols... 
} 
+0

Ver [este comentario] (http://stackoverflow.com/questions/700523/linq-to-sql-left-outer-join#comment21835463_700580), Linq-to -Las entidades SQL no son compatibles con 'DefaultIfEmpty'. –

177

No es necesario el en afirmaciones:

var query = 
    from customer in dc.Customers 
    from order in dc.Orders 
     .Where(o => customer.CustomerId == o.CustomerId) 
     .DefaultIfEmpty() 
    select new { Customer = customer, Order = order } 
    //Order will be null if the left join is null 

Y sí, la consulta anterior en efecto, crear una combinación externa izquierda .

Enlace a una pregunta similar que maneja múltiples izquierda se une a: Linq to Sql: Multiple left outer joins

+10

Si bien sé que la respuesta de @Marc Gravvel sí funciona, realmente prefiero este método porque IMO se parece más a lo que debe ser una combinación de la izquierda. – llaughlin

+1

Excelente respuesta. Buscando más de 5 horas de búsqueda de Google. Esta es la única forma en que el SQL resultante se unirá a él. –

+1

MUCHAS GRACIAS ... Estuve buscando una solución para esta tarde y su código lo enganchó (y se siente natural para arrancar). Ojalá pudiera votar esto varias veces. – Jim

1

Me gustaría añadir una cosa más. En LINQ to SQL si su base de datos está construida correctamente y sus tablas están relacionadas a través de restricciones de clave externa, entonces no necesita hacer una combinación en absoluto.

Usando LINQPad I crean los siguientes LINQ consulta:

//Querying from both the CustomerInfo table and OrderInfo table 
from cust in CustomerInfo 
where cust.CustomerID == 123456 
select new {cust, cust.OrderInfo} 

que fue traducido a la consulta (ligeramente truncada) por debajo de

-- Region Parameters 
DECLARE @p0 Int = 123456 
-- EndRegion 
SELECT [t0].[CustomerID], [t0].[AlternateCustomerID], [t1].[OrderID], [t1].[OnlineOrderID], (
    SELECT COUNT(*) 
    FROM [OrderInfo] AS [t2] 
    WHERE [t2].[CustomerID] = [t0].[CustomerID] 
    ) AS [value] 
FROM [CustomerInfo] AS [t0] 
LEFT OUTER JOIN [OrderInfo] AS [t1] ON [t1].[CustomerID] = [t0].[CustomerID] 
WHERE [t0].[CustomerID] = @p0 
ORDER BY [t0].[CustomerID], [t1].[OrderID] 

Aviso la LEFT OUTER JOIN anteriormente.