Linq to Sql: Mehrere linke äußere Verknüpfungen

160

Ich habe einige Probleme damit, herauszufinden, wie mehr als ein linker äußerer Join mit LINQ to SQL verwendet werden kann. Ich verstehe, wie man einen linken äußeren Join verwendet. Ich benutze VB.NET. Unten ist meine SQL-Syntax.

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
Bryan Roth
quelle

Antworten:

247

Dies kann sauberer sein ( Sie benötigen nicht alle intoAnweisungen ):

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

Hier ist ein weiteres Beispiel für Linksverknüpfungen

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  
    }
Amir
quelle
12
@manitra: Nein, Sie erhalten tatsächlich LEFT OUTER JOIN-Anweisungen (keine verschachtelten Auswahlen). Ziemlich verrückt, oder?
Amir
6
Ich mag diesen Ansatz besser, als alle in-Anweisungen zu verwenden. Danke, dass du das gepostet hast!
Bryan Roth
7
Das ist alles süß. Allerdings: wtf warum gibt es in linq keinen linken Join, wenn es einen Join gibt? Welche satzbasierte Welt verbindet nur Inneres? Grrr.
JCollum
2
Dies brachte nur ein breites Lächeln auf mein Gesicht. Vielen Dank für das leicht verständliche Beispiel.
Nycdan
2
Ich habe es versucht und es war eine Größenordnung langsamer als die Methode von @ tvanfosson. Ich habe es nicht direkt gegen eine Datenbank gemacht, sondern ausschließlich in Linq zu Objekten. Ich hatte das Äquivalent von 500000 Ausgaben, 4000 KategorieDtos und 4000 AusgabenTypDtos. Der Lauf dauerte 1 Minute. Mit der Syntax von tvanfosson dauert es 6 Sekunden.
Chris
49

Ich habe keinen Zugriff auf VisualStudio (ich bin auf meinem Mac), sondern verwende die Informationen von http://bhaidar.net/cs/archive/2007/08/01/left-outer-join-in-linq-to -sql.aspx Es sieht so aus, als könnten Sie so etwas tun:

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 }
Tvanfosson
quelle
22

Ich habe herausgefunden, wie mehrere linke äußere Verknüpfungen in VB.NET mithilfe von LINQ to SQL verwendet werden:

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
Bryan Roth
quelle
8

In VB.NET mit Funktion,

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 
Mitul
quelle
3

Ich denke, Sie sollten in der Lage sein, die in diesem Beitrag verwendete Methode zu befolgen . Es sieht wirklich hässlich aus, aber ich würde denken, Sie könnten es zweimal tun und das gewünschte Ergebnis erzielen.

Ich frage mich, ob dies tatsächlich ein Fall ist, in dem Sie besser dran sind, als DataContext.ExecuteCommand(...)in linq zu konvertieren.

Jon Norton
quelle
0

Ich verwende diese Linq-Abfrage für meine Anwendung. Wenn dies Ihrer Anforderung entspricht, können Sie dies verweisen. hier habe ich mich mit 3 Tabellen verbunden (Left Outer Join).

 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()
Ich bin ck
quelle