2009-03-31 6 views
121

Cette requête est-elle équivalente à une jointure LEFT OUTER?LINQ to SQL Left Outer Join

//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 
} 

Répondre

141

Pas tout à fait - puisque chaque « gauche » ligne dans une gauche-jointure externe correspondra à 0-n lignes « de droite » (dans le deuxième tableau), où, comme le vôtre correspond seulement 0-1. Pour faire une jointure externe gauche, vous avez besoin SelectMany et DefaultIfEmpty, par exemple:

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 ne reconnaît pas la méthode DefaultIfEmpty ... –

+13

Quelqu'un peut-il expliquer comment fonctionne cette syntaxe folle? Je n'arrive pas à voir comment l'un de ces mots clés en fait une jointure gauche. Que fait le "dans sr"? Linq me frustre parfois :) –

+1

@JoePhillips J'ai beaucoup d'expérience SQL, mais essayer d'apprendre LINQ, c'est comme patauger dans la boue. Je suis d'accord que c'est complètement fou. –

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 

Vérifier http://msdn.microsoft.com/en-us/vbasic/bb737929.aspx

+0

Bien essayé mais on dirait que l'OP utilise C#. La syntaxe VB est curieusement différente. – Levitikon

+3

+1 Tout simplement parce que c'est un bon exemple vb.net – twoleggedhorse

4

J'ai trouvé 1 solution. si vous voulez traduire ce type de SQL (joindre à gauche) dans Linq entité ...

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

Voir [ce commentaire] (http://stackoverflow.com/questions/700523/linq-to-sql-left-outer-join#comment21835463_700580), Linq-to Les entités SQL ne prennent pas en charge 'DefaultIfEmpty'. –

177

Vous n'avez pas besoin dans les déclarations:

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 

Et oui, la requête ci-dessus crée en effet une LEFT OUTER JOIN .

Lien à une question similaire qui gère plusieurs gauche rejoint: Linq to Sql: Multiple left outer joins

+10

Bien que je sache que la réponse de @Marc Gravvel fonctionne, je préfère vraiment cette méthode car IMO est plus proche de ce à quoi devrait ressembler une jointure gauche. – llaughlin

+1

Excellente réponse. Vous recherchez plus de 5 heures de recherche google. C'est la seule façon dont SQL aura quitté la partie. –

+1

MERCI soooo much .... Je cherchais une solution pour cela tout l'après-midi et votre code l'a cloué (et se sent naturel de démarrer). J'aurais aimé pouvoir l'emporter plusieurs fois. – Jim

1

Je voudrais ajouter une chose. Dans LINQ to SQL si votre base de données est correctement construite et que vos tables sont liées par des contraintes de clé étrangère, vous n'avez pas besoin de faire de jointure du tout.

En utilisant LINQPad J'ai créé la requête LINQ suivante:

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

Ce qui a été traduit à la requête (légèrement tronquée) ci-dessous

-- 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] 

Notez que le LEFT OUTER JOIN ci-dessus.