2010-09-25 4 views

risposta

37

Normalmente unisce sinistra in LINQ sono modellati con gruppo unisce, a volte in combinazione con DefaultIfEmpty e 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)); 

che darà una sequenza di coppie (n, m) dove n è la voce da p.Person e m è la voce da p.PersonInfo, ma m sarà nullo se non ci sono corrispondenze.

(E 'completamente testato, btw - ma dovrebbe darvi l'idea comunque :)

+1

la prima proiezione anonima non funziona - il compilatore dice "Dichiaratore di membro di tipo anonimo non valido. I membri di tipo anonimo devono essere dichiarati con un compito membro, nome semplice o accesso membro ' – chester89

+1

@ chester89: Risolto, grazie. –

11

Per join esterno sinistro provare seguente query. Questo è testato

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

Se qualcuno si imbatte in questa domanda e vuole un metodo di estensione per ottenere questo risultato, ho creato uno utilizzando lo stesso approccio delle altre risposte. Ha la stessa firma del metodo di estensione della join regolare.

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))); 
    }