Linq ke Sql: Banyak gabungan luar kiri

160

Saya mengalami beberapa masalah mencari tahu bagaimana menggunakan lebih dari satu bergabung luar menggunakan LINQ to SQL. Saya mengerti cara menggunakan satu join luar kiri. Saya menggunakan VB.NET. Di bawah ini adalah sintaks SQL saya.

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
sumber

Jawaban:

247

Ini mungkin lebih bersih ( Anda tidak perlu semua intopernyataan ):

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

Berikut ini contoh gabung kiri lainnya

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
sumber
12
@manitra: Tidak, Anda benar-benar mendapatkan pernyataan GABUNG LEFT OUTER (tidak ada pilihan bersarang) Cukup gila ya?
Amir
6
Saya suka pendekatan ini lebih baik daripada menggunakan semua pernyataan. Terima kasih telah memposting ini!
Bryan Roth
7
Ini semua jenis manis. Namun: wtf mengapa tidak ada gabung kiri di linq jika ada gabung? Dunia berbasis himpunan apa yang hanya dimiliki oleh inner? Grrr.
jcollum
2
Ini hanya membuat saya tersenyum lebar. Terima kasih atas contoh yang mudah diikuti.
nycdan
2
Saya mencoba ini dan itu urutan besarnya lebih lambat daripada metode @ tvanfosson. Saya tidak melakukannya secara langsung terhadap database, tetapi lebih tepatnya di LINQ ke objek. Saya memiliki yang setara dengan 500.000 pengeluaran, 4000 categoryDtos, dan 4000 costTypeDtos. Butuh 1 menit untuk berlari. Dengan sintaks tvanfosson, dibutuhkan 6 detik.
Chris
49

Tidak memiliki akses ke VisualStudio (saya menggunakan Mac saya), tetapi menggunakan informasi dari http://bhaidar.net/cs/archive/2007/08/01/left-outer-join-in-linqlin-to -sql.aspx sepertinya Anda dapat melakukan sesuatu seperti ini:

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
sumber
22

Saya menemukan cara menggunakan beberapa gabungan luar kiri di VB.NET menggunakan LINQ ke 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
Bryan Roth
sumber
8

Di VB.NET menggunakan 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 
Mitul
sumber
3

Saya pikir Anda harus dapat mengikuti metode yang digunakan dalam posting ini . Kelihatannya sangat jelek, tapi saya pikir Anda bisa melakukannya dua kali dan mendapatkan hasil yang Anda inginkan.

Saya bertanya-tanya apakah ini sebenarnya kasus di mana Anda akan lebih baik menggunakan DataContext.ExecuteCommand(...)daripada mengkonversi ke LINQ.

Jon Norton
sumber
0

Saya menggunakan permintaan LINQ ini untuk aplikasi saya. jika ini sesuai dengan kebutuhan Anda, Anda dapat merujuk ini. di sini saya telah bergabung (Gabung luar kiri) dengan 3 tabel.

 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()
Iam ck
sumber