Linq vers Sql: plusieurs jointures externes à gauche


160

J'ai du mal à comprendre comment utiliser plus d'une jointure externe gauche à l'aide de LINQ to SQL. Je comprends comment utiliser une jointure externe gauche. J'utilise VB.NET. Voici ma syntaxe SQL.

T-SQL

SELECT
    o.OrderNumber,
    v.VendorName,
    s.StatusName
FROM
    Orders o
LEFT OUTER JOIN Vendors v ON
    v.Id = o.VendorId
LEFT OUTER JOIN Status s ON
    s.Id = o.StatusId
WHERE
    o.OrderNumber >= 100000 AND
    o.OrderNumber <= 200000

Réponses:


247

Cela peut être plus propre ( vous n'avez pas besoin de toutes les intodéclarations ):

var query = 
    from order in dc.Orders
    from vendor 
    in dc.Vendors
        .Where(v => v.Id == order.VendorId)
        .DefaultIfEmpty()
    from status 
    in dc.Status
        .Where(s => s.Id == order.StatusId)
        .DefaultIfEmpty()
    select new { Order = order, Vendor = vendor, Status = status } 
    //Vendor and Status properties will be null if the left join is null

Voici un autre exemple de jointure à gauche

var results = 
    from expense in expenseDataContext.ExpenseDtos
    where expense.Id == expenseId //some expense id that was passed in
    from category 
    // left join on categories table if exists
    in expenseDataContext.CategoryDtos
                         .Where(c => c.Id == expense.CategoryId)
                         .DefaultIfEmpty() 
    // left join on expense type table if exists
    from expenseType 
    in expenseDataContext.ExpenseTypeDtos
                         .Where(e => e.Id == expense.ExpenseTypeId)
                         .DefaultIfEmpty()
    // left join on currency table if exists
    from currency 
    in expenseDataContext.CurrencyDtos
                         .Where(c => c.CurrencyID == expense.FKCurrencyID)
                         .DefaultIfEmpty() 
    select new 
    { 
        Expense = expense,
        // category will be null if join doesn't exist
        Category = category,
        // expensetype will be null if join doesn't exist
        ExpenseType = expenseType,
        // currency will be null if join doesn't exist
        Currency = currency  
    }

12
@manitra: Non, vous obtenez en fait des instructions LEFT OUTER JOIN (pas de sélections imbriquées). Assez fou hein?
Amir

6
J'aime mieux cette approche que d'utiliser toutes les instructions into. Merci d'avoir publié ceci!
Bryan Roth

7
C'est toutes sortes de sucreries. Cependant: pourquoi n'y a-t-il pas de jointure gauche dans linq s'il y a une jointure? Quel monde basé sur des ensembles ne fait que des jointures internes? Grrr.
jcollum

2
Cela m'a juste fait un grand sourire. Merci pour l'exemple facile à suivre.
nycdan

2
J'ai essayé ceci et c'était un ordre de grandeur plus lent que la méthode de @ tvanfosson. Je ne le faisais pas directement contre une base de données, mais plutôt strictement dans linq aux objets. J'avais l'équivalent de 500000 dépenses, 4000 categoryDtos et 4000 depenseTypeDtos. Il a fallu 1 minute pour courir. Avec la syntaxe de tvanfosson, cela prend 6 secondes.
Chris

49

Je n'ai pas accès à VisualStudio (je suis sur mon Mac), mais en utilisant les informations de http://bhaidar.net/cs/archive/2007/08/01/left-outer-join-in-linq-to -sql.aspx il semble que vous puissiez faire quelque chose comme ceci:

var query = from o in dc.Orders
            join v in dc.Vendors on o.VendorId equals v.Id into ov
            from x in ov.DefaultIfEmpty()
            join s in dc.Status on o.StatusId equals s.Id into os
            from y in os.DefaultIfEmpty()
            select new { o.OrderNumber, x.VendorName, y.StatusName }

22

J'ai compris comment utiliser plusieurs jointures externes gauches dans VB.NET en utilisant LINQ to SQL:

Dim db As New ContractDataContext()

Dim query = From o In db.Orders _
            Group Join v In db.Vendors _
            On v.VendorNumber Equals o.VendorNumber _
            Into ov = Group _
            From x In ov.DefaultIfEmpty() _
            Group Join s In db.Status _
            On s.Id Equals o.StatusId Into os = Group _
            From y In os.DefaultIfEmpty() _
            Where o.OrderNumber >= 100000 And o.OrderNumber <= 200000 _
            Select Vendor_Name = x.Name, _
                   Order_Number = o.OrderNumber, _
                   Status_Name = y.StatusName

8

Dans VB.NET en utilisant Function,

Dim query = From order In dc.Orders
            From vendor In 
            dc.Vendors.Where(Function(v) v.Id = order.VendorId).DefaultIfEmpty()
            From status In 
            dc.Status.Where(Function(s) s.Id = order.StatusId).DefaultIfEmpty()
            Select Order = order, Vendor = vendor, Status = status 

3

Je pense que vous devriez pouvoir suivre la méthode utilisée dans cet article. Cela a l'air vraiment moche, mais je pense que vous pouvez le faire deux fois et obtenir le résultat souhaité.

Je me demande si c'est réellement un cas où vous feriez mieux d'utiliser DataContext.ExecuteCommand(...)au lieu de convertir en linq.


0

J'utilise cette requête linq pour mon application. si cela correspond à vos besoins, vous pouvez le référer. ici, j'ai joint (jointure externe gauche) avec 3 tables.

 Dim result = (From csL In contractEntity.CSLogin.Where(Function(cs) cs.Login = login AndAlso cs.Password = password).DefaultIfEmpty
                   From usrT In contractEntity.UserType.Where(Function(uTyp) uTyp.UserTypeID = csL.UserTyp).DefaultIfEmpty ' <== makes join left join
                   From kunD In contractEntity.EmployeeMaster.Where(Function(kunDat) kunDat.CSLoginID = csL.CSLoginID).DefaultIfEmpty
                   Select New With {
                  .CSLoginID = csL.CSLoginID,
                  .UserType = csL.UserTyp}).ToList()
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.