2010-09-25 16 views

Respuesta

37

Normalmente se une a izquierda en LINQ se modelan con el grupo se une, a veces en conjunción con DefaultIfEmpty y SelectMany:

var leftJoin = p.Person.Where(n => n.FirstName.Contains("a")) 
         .GroupJoin(p.PersonInfo, 
            n => n.PersonId, 
            m => m.PersonId, 
            (n, ms) => new { n, ms = ms.DefaultIfEmpty() }) 
         .SelectMany(z => z.ms.Select(m => new { n = z.n, m)); 

que dará una secuencia de pares (n, m) donde n es la entrada de p.Person y m es la entrada de p.PersonInfo, pero m será nulo si no hay coincidencias.

(Es completamente probado, por cierto - pero debe darle la idea de todos modos :)

+1

primera proyección anónima no funciona - el compilador dice 'Declarador de miembro de tipo anónimo no válido. miembros de tipo anónimos deben declarar con una asignación miembro, nombre sencillo o acceso de este miembro – chester89

+1

@ chester89: fijo, gracias. –

11

Para tratar combinación externa izquierda siguiente consulta. Esto se prueba

var leftJoin = Table1 
       .GroupJoin(
           inner: Table2, 
        outerKeySelector: t1 => t1.Col1, 
        innerKeySelector: t2 => t2.Col2, 
         resultSelector: (t1, t2Rows) => new { t1, t2Rows.DefaultIfEmpty() } 
       ) 
       .SelectMany(z => 
        z.t2Rows.Select(t2 => 
         new { t1 = z.t1, t2 = t2 } 
        ) 
       ); 
3

Si alguien viene a través de esta pregunta y quiere un método de extensión para lograr esto, he creado uno utilizando el mismo enfoque que las otras respuestas. Tiene la misma firma que el método de extensión de combinación regular.

public static IEnumerable<TResult> LeftJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, 
     IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, 
     Func<TOuter, TInner, TResult> resultSelector) 
    { 
     return outer 
      .GroupJoin(inner, outerKeySelector, innerKeySelector, (outerObj, inners) => 
      new 
      { 
       outerObj, 
       inners= inners.DefaultIfEmpty() 
      }) 
     .SelectMany(a => a.inners.Select(innerObj => resultSelector(a.outerObj, innerObj))); 
    } 
Cuestiones relacionadas