Linq to Sql: Nhiều kết nối ngoài trái


160

Tôi gặp một số khó khăn khi tìm hiểu làm thế nào để sử dụng nhiều hơn một kết nối bên ngoài bên trái bằng cách sử dụng LINQ to SQL. Tôi hiểu làm thế nào để sử dụng một bên ngoài tham gia. Tôi đang sử dụng VB.NET. Dưới đây là cú pháp SQL của tôi.

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

Câu trả lời:


247

Điều này có thể sạch hơn ( bạn không cần tất cả các intobáo cáo ):

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

Đây là một ví dụ tham gia trái

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: Không, bạn thực sự nhận được các câu lệnh LEFT OUTER THAM GIA (không có lựa chọn lồng nhau). Khá điên hả?
Amir

6
Tôi thích cách tiếp cận này tốt hơn là sử dụng tất cả các báo cáo. Cảm ơn bạn đã đăng bài này!
Bryan Roth

7
Đây là tất cả các loại ngọt ngào. Tuy nhiên: wtf tại sao không có tham gia trái trong linq nếu có tham gia? Thế giới dựa trên tập hợp nào chỉ tham gia bên trong? Grrr.
jcollum

2
Điều này chỉ đặt một nụ cười lớn trên khuôn mặt của tôi. Cảm ơn ví dụ dễ làm theo.
nycdan

2
Tôi đã thử điều này và nó là một thứ tự cường độ chậm hơn so với phương pháp của @ tvanfosson. Tôi đã không làm điều đó trực tiếp với cơ sở dữ liệu, mà là nghiêm ngặt trong linq đến các đối tượng. Tôi đã có tương đương với 500000 chi phí, 4000 loạiDtos và 4000 chi phíTypeDtos. Phải mất 1 phút để chạy. Với cú pháp của tvanfosson, phải mất 6 giây.
Chris

49

Không có quyền truy cập vào VisualStudio (Tôi trên máy Mac của tôi), nhưng sử dụng thông tin từ http://bhaidar.net/cs/archive/2007/08/01/left-outer-join-in-linq-to -sql.aspx có vẻ như bạn có thể làm một cái gì đó như thế này:

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

Tôi đã tìm ra cách sử dụng nhiều phép nối ngoài trái trong VB.NET bằng cách sử dụng 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

Trong VB.NET sử dụng Hàm,

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

Tôi nghĩ bạn nên có thể làm theo phương pháp được sử dụng trong bài viết này . Nó trông thực sự xấu xí, nhưng tôi nghĩ bạn có thể làm điều đó hai lần và nhận được kết quả mà bạn muốn.

Tôi tự hỏi nếu đây thực sự là một trường hợp bạn nên sử dụng tốt hơn DataContext.ExecuteCommand(...)thay vì chuyển đổi sang linq.


0

Tôi đang sử dụng truy vấn linq này cho ứng dụng của tôi. Nếu điều này phù hợp với yêu cầu của bạn, bạn có thể tham khảo điều này. Ở đây tôi đã tham gia (Tham gia bên ngoài bên trái) với 3 bảng.

 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()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.