2009-05-11 10 views
8

Czy ktoś mógłby mi podać przykład wykonania operacji łączenia lewego za pomocą wyrażeń LINQ/lambda?Lewe sprzężenie za pomocą LINQ

+4

Wszyscy na pokład LINQ Lambda Express, – mquander

+3

Haha Mimo to, zamiast oglądania tego. post get get hammered downvotes, myślałem, że przerobię pytanie w przyzwoitym języku angielskim, ponieważ w rzeczywistości wydaje się być prawidłowy język angielski: – Noldorin

+2

@mquander: ::: Czyta oryginalny ve rsion of question ::: To i twój komentarz przyniósł chichot. – Brian

Odpowiedz

6

Numer LINQ to SQL samples page na stronie MSDN zawiera przykład tego, jak to zrobić. Kod powinien być prawie identyczny dla LINQ do Objects.

Kluczem tutaj jest połączenie z DefaultIfEmpty.

Dim q = From e In db.Employees _ 
     Group Join o In db.Orders On e Equals o.Employee Into ords = Group _ 
     From o In ords.DefaultIfEmpty _ 
     Select New With {e.FirstName, e.LastName, .Order = o} 

Jeśli potrzebujesz pomocy przy konwersji do C#, po prostu zapytaj.

0

Na przykład:

IQueryable<aspnet_UsersInRole> q = db.aspnet_Roles 
        .Select(p => p.aspnet_UsersInRoles 
         .SingleOrDefault(x => x.UserId == iduser)); 

daje listę ról z członkostwa asp.net, z null, jeżeli nie pasuje do określonego użytkownika (klawisz iduser)

0

The Way I odkryłem, że lubię połączyć OuterCollection.SelectMany() z InnerCollection.DefaultIfEmpty(). Możesz uruchomić następujące ustawienia w LINQPad, używając trybu "C# Statement".

var teams = new[] 
    { 
     new { Id = 1, Name = "Tigers" }, 
     new { Id = 2, Name = "Sharks" }, 
     new { Id = 3, Name = "Rangers" }, 
    }; 

var players = new[] 
    { 
     new { Name = "Abe", TeamId = 2}, 
     new { Name = "Beth", TeamId = 4}, 
     new { Name = "Chaz", TeamId = 1}, 
     new { Name = "Dee", TeamId = 2}, 
    }; 

// SelectMany generally aggregates a collection based upon a selector: from the outer item to 
// a collection of the inner item. Adding .DefaultIfEmpty ensures that every outer item 
// will map to something, even null. This circumstance makes the query a left outer join. 
// Here we use a form of SelectMany with a second selector parameter that performs an 
// an additional transformation from the (outer,inner) pair to an arbitrary value (an 
// an anonymous type in this case.) 
var teamAndPlayer = teams.SelectMany(
    team => 
     players 
     .Where(player => player.TeamId == team.Id) 
     .DefaultIfEmpty(), 
    (team, player) => new 
     { 
      Team = team.Name, 
      Player = player != null ? player.Name : null 
     }); 

teamAndPlayer.Dump(); 

// teamAndPlayer is: 
//  { 
//   {"Tigers", "Chaz"}, 
//   {"Sharks", "Abe"}, 
//   {"Sharks", "Dee"}, 
//   {"Rangers", null} 
//  } 

podczas eksperymentowania z tym, uważam, że czasami można pominąć zerową kontrolę player w instancji anonimowego typu. Myślę, że tak jest w przypadku używania LINQ-SQL w bazie danych (zamiast tych tablic, które moim zdaniem powodują LINQ-do-obiektów lub coś takiego.) Myślę, że pominięcie kontroli zerowej działa w LINQ -to-SQL, ponieważ zapytanie jest tłumaczone na SQL LEFT OUTER JOIN, które przechodzi bezpośrednio do łączenia wartości null z elementem zewnętrznym. (Zauważ, że wartość właściwości anonimowego obiektu musi być zerowa, więc jeśli chcesz bezpiecznie dołączyć int, powiedzmy, potrzebujesz czegoś takiego jak: new { TeamId = (int?)player.TeamId }.

0

dobrze próbowałem odtworzyć słynny lewy dołączyć gdzie klucz b jest zerowy, a wynik mam jest to metoda rozszerzenie (przy odrobinie wyobraźni można zmodyfikować go po prostu zrobić LEFT JOIN):

public static class extends 
{ 
    public static IEnumerable<T> LefJoinBNull<T, TKey>(this IEnumerable<T> source, IEnumerable<T> Target, Func<T, TKey> key) 
    { 
     if (source == null) 
      throw new ArgumentException("source is null"); 

     return from s in source 
       join j in Target on key.Invoke(s) equals key.Invoke(j) into gg 
       from i in gg.DefaultIfEmpty() 
       where i == null 
       select s; 
    } 
}