2009-05-11 25 views
8

¿Podría alguien darme un ejemplo de cómo realizar una operación de unión a la izquierda utilizando expresiones LINQ/lambda?Unir a la izquierda con LINQ

+4

Todos a bordo del LINQ Lambda expreso – mquander

+3

Jaja Sin embargo, en lugar de ver esto. Después de recibir un castigo por los votos a favor, pensé que volvería a escribir la pregunta en un inglés decente, ya que de hecho parece ser válida. – Noldorin

+2

@mquander: ::: Lee el original Pregunta de respuesta: Eso y tu comentario provocaron una sonrisa. – Brian

Respuesta

6

El LINQ to SQL samples page en MSDN proporciona un ejemplo de cómo lograr esto. El código debería ser bastante idéntico para LINQ to Objects.

La clave aquí es la llamada al 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} 

Si necesita ayuda para convertir que a C#, solo pregunte.

0

Por ejemplo:

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

le dará una lista de los roles de los miembros asp.net, con nulos en los que no se corresponde con la tecla (idUser) de usuario especificado

0

La forma en que he encontrado que me gusta es combinar OuterCollection.SelectMany() con InnerCollection.DefaultIfEmpty(). Puede ejecutar lo siguiente en LINQPad usando el modo "Sentencias C#".

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} 
//  } 

Mientras se experimenta con esto, me encontré con que a veces se puede omitir la comprobación de nulo player en la creación de instancias del tipo anónimo. Creo que este es el caso cuando uso LINQ-to-SQL en una base de datos (en lugar de estas matrices aquí, lo cual creo que lo convierte en LINQ-to-objects o algo así). Creo que la omisión del cheque nulo funciona en LINQ -to-SQL porque la consulta se traduce en un SQL LEFT OUTER JOIN, que se salta directamente para unir nulo con el elemento externo. (Tenga en cuenta que el valor de la propiedad del objeto anónimo debe ser anulable, por lo que si desea incluir de manera segura un int, necesitará algo como: new { TeamId = (int?)player.TeamId }.

0

intenté reproducir el famoso left join donde b key es nula y el resultado lo que tengo es este método de extensión (con un poco de imaginación se puede modificarlo para simplemente hacer una izquierda unirse a):

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; 
    } 
} 
Cuestiones relacionadas