Linq to Sql:多个左外部联接


160

我在弄清楚如何使用LINQ to 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

Answers:


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语句(没有嵌套选择)。相当疯狂吧?
阿米尔(Amir)2010年

6
与使用所有in语句相比,我更喜欢这种方法。感谢您发布!
布莱恩·罗斯

7
这是各种各样的甜食。但是:wtf如果有联接,为什么在linq中没有左联接?内部联接只在哪个基于集合的世界中进行?rr
jcollum

2
这只是在我脸上露出灿烂的笑容。感谢您易于遵循的示例。
nycdan

2
我尝试了一下,它比@tvanfosson的方法慢了一个数量级。我不是直接针对数据库,而是严格按照对象进行操作。我有相当于500000的费用,4000的categoryDtos和4000的费用TypeDtos。运行了1分钟。使用tvanfosson的语法,需要6秒钟。
克里斯,


22

我想出了如何使用LINQ to SQL在VB.NET中使用多个左外部联接:

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查询。如果这符合您的要求,您可以参考。在这里,我加入了(左外部联接)与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()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.