11.23.2008

Linq – Join sobre Múltiples Listas Genéricas de Objetos

En el post anterior, hicimos una consulta a una lista de productos utilizando Linq – Linq2Objects. Sin embargo, es normal buscar objetos desde múltiples fuentes de datos. En Linq tenemos la clausula join que nos permite unir múltiples fuentes de datos y no solamente desde base de datos.

Supongamos que tenemos una lista de clientes y un plan de millas de una aerolínea y tenemos que buscar todos los clientes que pertenecen a un plan específico definido por la aerolínea.

El primer paso, es crear la clase cliente y la clase plan de millas. El código de ambas clases se presenta a continuación.

public class Cliente
{
public int Id { get; set; }
public string Nombre { get; set; }
public string PaisResidencia { get; set; }
public int IdPlanDeMillas { get; set; }
}


public class PlanDeMillas
{
public int Id { get; set; }
public string Plan { get; set; }
public bool VencenMillas { get; set; }
}


Como podemos ver, el plan de millas esta asociado con el cliente a través del Id del plan de millas dentro de la clase cliente. Seguidamente mostramos dos métodos en donde se inicializan dos listas, una de clientes y otras de millas. En la lista de clientes se indica a cual plan de millas pertenece el cliente.



private static List<Cliente> GetListaClientes( )
{
return new List<Cliente>( )
{
new Cliente ()
{
Id = 0,
IdPlanDeMillas = 0,
Nombre = "Juan Romero",
PaisResidencia = "Guatemala"
},
new Cliente ()
{
Id = 1,
IdPlanDeMillas = 1,
Nombre = "Carlos Jimenez",
PaisResidencia = "Uruguay"
},
new Cliente ()
{
Id = 2,
IdPlanDeMillas = 2,
Nombre = "Elisa Perez",
PaisResidencia = "Guatemala"
},
new Cliente ()
{
Id = 3,
IdPlanDeMillas = 2,
Nombre = "Sebastian Ortuño",
PaisResidencia = "Uruguay"
},
new Cliente ()
{
Id = 4,
IdPlanDeMillas = 0,
Nombre = "Luis Barquero",
PaisResidencia = "Costa Rica"
},
new Cliente ()
{
Id = 5,
IdPlanDeMillas = 1,
Nombre = "Ana Rodriguez",
PaisResidencia = "Costa Rica"
},
};
}



private static List<PlanDeMillas> GetListaPlanes( )
{
return new List<PlanDeMillas>( )
{
new PlanDeMillas ()
{
Id = 0,
Plan = "Estándar",
VencenMillas = true
},
new PlanDeMillas ()
{
Id = 1,
Plan = "Oro",
VencenMillas = false
},
new PlanDeMillas ()
{
Id = 2,
Plan = "Platino",
VencenMillas = false
}
};
}


Por último, creamos la sentencia Linq para hacer un join de ambas colecciones a través del Id del Plan de Millas. El código completo con la llamada a la inicialización de las listas, la consulta Linq, y su despliegue en la consola se muestra a continuación.



 



List<Cliente> listaClientes = GetListaClientes( );
List<PlanDeMillas> listaPlanes = GetListaPlanes( );

var resultado = from cliente in listaClientes
join plan in listaPlanes
on
cliente.IdPlanDeMillas equals plan.Id
select new
{
cliente.Nombre,
cliente.PaisResidencia,
plan.Plan,
plan.VencenMillas
};

Console.WriteLine("--------------------------------------");
Console.WriteLine("Reporte de plan de millas por usuario");
Console.WriteLine("--------------------------------------");
foreach (var clientePlan in resultado)
{
Console.WriteLine("Cliente: {0}", clientePlan.Nombre);
Console.WriteLine("Tipo de Plan: {0}", clientePlan.Plan);
Console.WriteLine("Vencen las millas: {0}", clientePlan.VencenMillas);
Console.WriteLine("--------------------------------------");
}



Al analizar la consulta linq en el código anterior, podemos identificar las siguientes características de la consulta:





  1. El uso del join para hacer la consulta. En este caso, estamos llevando a cabo esta operación en base al Id del plan de millas en la clase PlanDeMillas y el Id del plan incluido en el cliente.




  2. La selección de un objeto customizado como parte de la consulta. En este caso, deseamos una lista de objetos de un tipo que no tenemos definido, por lo tanto, al crear el nuevo objeto que se va a agregar a la lista de forma iterativa no indicamos el tipo del objeto que vamos a almacenar en la lista, si no que simplemente inicializamos un tipo anónimo. En este caso, el compilador genera un nombre único para el nuevo tipo.




  3. El uso del tipo var. Dado que la clausula select retorna un tipo anónimo, no se puede definir un tipo explícito tal como IEnumerable<T> para contener el resultado de la consulta en la lista. En este caso el compilador infiere el tipo de la variable a partir de su inicialización, y declara la lista en base a este. Esta característica en C# 3.0 y superior se conoce como variables locales tipadas implícitamente.




El resultado al ejecutar la consulta anterior se muestra en la siguiente pantalla.



image

1 comentario:

Gochoa dijo...

Hola, soy nueva en linq y tengo la necesidad de hacer un mètodo para que reciba una lista donde viene solo el cod.proceso, yo debo revisar uno a uno si este codigo existe en la entidad Proceso que tengo en mi modelo. Y retornar una lista con todos los procesos que si existen y otra con los procesos no validos. No sè cuál función de todas las que has explicado puedo usar, si tenemos en cuenta que pueden llegar hasta 20mil registros en dicha lista. Cuál es la forma más eficiente para hacerlo con linq ó llamando un Store procedure?