Linq a Sql: múltiples combinaciones externas izquierdas


160

Tengo algunos problemas para descubrir cómo usar más de una combinación externa izquierda usando LINQ to SQL. Entiendo cómo usar una combinación externa izquierda. Estoy usando VB.NET. A continuación se muestra mi sintaxis 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

Respuestas:


247

Esto puede ser más limpio ( no necesita todas las intodeclaraciones ):

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

Aquí hay otro ejemplo de combinación izquierda

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: No, en realidad obtienes sentencias LEFT OUTER JOIN (sin selecciones anidadas). Bastante loco ¿eh?
Amir

66
Me gusta más este enfoque que usar todas las declaraciones into. ¡Gracias por publicar esto!
Bryan Roth

77
Esto es todo tipo de dulce. Sin embargo: ¿por qué no hay una unión izquierda en linq si hay una unión? ¿Qué mundo basado en conjuntos solo une internamente? Grrr.
jcollum

2
Esto solo puso una gran sonrisa en mi cara. Gracias por el ejemplo fácil de seguir.
nycdan

2
Intenté esto y fue un orden de magnitud más lento que el método de @ tvanfosson. No lo estaba haciendo directamente contra una base de datos, sino estrictamente en linq a los objetos. Tenía el equivalente de 500000 gastos, 4000 categoryDtos y 4000 gastoTypeDtos. Tardó 1 minuto en correr. Con la sintaxis de tvanfosson, lleva 6 segundos.
Chris

49

No tengo acceso a VisualStudio (estoy en mi Mac), pero utilizo la información de http://bhaidar.net/cs/archive/2007/08/01/left-outer-join-in-linq-to -sql.aspx parece que puede hacer algo como esto:

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

Descubrí cómo usar múltiples combinaciones externas izquierdas en VB.NET usando 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

En VB.NET usando 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 

3

Creo que deberías poder seguir el método utilizado en este publicación. Se ve muy feo, pero creo que podría hacerlo dos veces y obtener el resultado que desea.

Me pregunto si este es realmente un caso en el que sería mejor usarlo en DataContext.ExecuteCommand(...)lugar de convertirlo a linq.


0

Estoy usando esta consulta linq para mi aplicación. si esto coincide con su requerimiento, puede referirlo. aquí me he unido (combinación externa izquierda) con 3 tablas.

 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()
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.