Linq ถึง Sql: การรวมภายนอกด้านซ้ายหลายรายการ


160

ฉันมีปัญหาในการหาวิธีใช้การรวมภายนอกด้านซ้ายมากกว่าหนึ่งรายการโดยใช้ LINQ กับ SQL ฉันเข้าใจวิธีใช้การรวมภายนอกหนึ่งครั้ง ฉันใช้ VB.NET ด้านล่างเป็นไวยากรณ์ 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

คำตอบ:


247

นี้อาจจะทำความสะอาด ( คุณไม่จำเป็นต้องทุกintoงบ ):

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

นี่เป็นอีกตัวอย่างที่เหลือ

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: ไม่จริง ๆ แล้วคุณได้รับข้อความ LEFT OUTER JOIN (ไม่มีการเลือกซ้อนกัน) พริตตี้บ้าเหรอ?
อาเมียร์

6
ฉันชอบวิธีนี้ดีกว่าการใช้คำสั่งทั้งหมดลงใน ขอบคุณสำหรับการโพสต์นี้!
ไบรอันโรท

7
นี่มันหวานทุกชนิด อย่างไรก็ตาม: ทำไมถึงไม่มีการเข้าร่วมที่เหลือใน linq หากมีการเข้าร่วม? โลกภายในที่ตั้งค่าเพียงใดที่เข้าร่วมภายในเท่านั้น? ฮึ่ม
jcollum

2
นี่เป็นเพียงรอยยิ้มขนาดใหญ่บนใบหน้าของฉัน ขอบคุณสำหรับตัวอย่างที่ง่ายต่อการติดตาม
nycdan

2
ฉันลองสิ่งนี้และมันเป็นลำดับความสำคัญช้ากว่าวิธีการของ @ tvanfosson ฉันไม่ได้ทำมันโดยตรงกับฐานข้อมูล แต่ค่อนข้างเคร่งครัดใน linq กับวัตถุ ฉันมีค่าใช้จ่ายเทียบเท่า 500,000 รายการประเภท 4000 และประเภทค่าใช้จ่าย 4000 ประเภท ใช้เวลา 1 นาทีในการวิ่ง ด้วยไวยากรณ์ของ tvanfosson ใช้เวลา 6 วินาที
Chris

49

ไม่สามารถเข้าถึง VisualStudio (ฉันใช้ Mac) แต่ใช้ข้อมูลจากhttp://bhaidar.net/cs/archive/2007/08/01/left-outer-join-in-linq-to -sql.aspxดูเหมือนคุณอาจทำสิ่งนี้ได้:

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

ฉันหาวิธีใช้การรวมภายนอกหลาย ๆ ด้านใน VB.NET โดยใช้ LINQ กับ 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

ใน VB.NET โดยใช้ฟังก์ชั่น

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

ฉันคิดว่าคุณควรจะสามารถที่จะปฏิบัติตามวิธีการที่ใช้ในการนี้โพสต์ มันดูน่าเกลียดจริง ๆ แต่ฉันคิดว่าคุณสามารถทำได้สองครั้งและรับผลลัพธ์ที่คุณต้องการ

ฉันสงสัยว่านี่เป็นกรณีที่คุณควรใช้DataContext.ExecuteCommand(...)แทนการแปลงเป็น linq หรือไม่


0

ฉันใช้คำสั่ง linq นี้สำหรับแอปพลิเคชันของฉัน หากตรงกับความต้องการของคุณคุณสามารถอ้างอิงได้ ที่นี่ฉันได้เข้าร่วม (Left outer join) พร้อม 3 ตาราง

 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()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.