LINQ
Introducción a LINQ
Una consulta es una expresión que recupera datos de un origen de datos. Las
consultas normalmente se expresan en un lenguaje de consultas especializado.
A lo largo del tiempo se han ido desarrollando lenguajes diferentes para los
distintos tipos de orígenes de datos, como SQL para las bases de datos
relacionales y XQuery para XML. Por tanto, los desarrolladores han tenido que
aprender un nuevo lenguaje de consulta para cada tipo de origen de datos o
formato de datos que deben usar. LINQ simplifica esta situación al
proporcionar un modelo coherente para trabajar con los datos de varios tipos
de formatos y orígenes de datos. En una consulta LINQ, siempre se trabaja con
objetos. Se utilizan los mismos modelos de codificación básicos para consultar
y transformar datos de documentos XML, bases de datos SQL, conjuntos de
datos ADO.NET, colecciones .NET y cualquier otro formato para el que haya
disponible un proveedor LINQ.
Las tres partes de una operación de consulta
class IntroToLINQ
{
static void Main()
{
// The Three Parts of a LINQ Query:
// 1. Data source.
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
// 2. Query creation.
// numQuery is an IEnumerable<int>
var numQuery =
from num in numbers
where (num % 2) == 0
select num;
// 3. Query execution.
foreach (int num in numQuery)
{
Console.Write("{0,1} ", num);
}
}
}
Para obtener más información sobre cómo crear tipos de orígenes de datos
específicos, consulte la documentación de los distintos proveedores LINQ. Sin
embargo, la regla básica es muy simple: un origen de datos LINQ es cualquier
objeto que admite la interfaz genérica IEnumerable<T> o una interfaz que
herede de ella.
Nota
La consulta del ejemplo anterior devuelve todos los números pares de la matriz
de enteros. La expresión de consulta contiene tres cláusulas: from, where y
select. (Si está familiarizado con SQL, habrá observado que el orden de las
cláusulas se invierte respecto al orden de SQL.) La cláusula from especifica el
origen de datos, la cláusula where aplica el filtro y la cláusula select especifica
el tipo de los elementos devueltos. Ésta y las demás cláusulas de consulta se
analizan con detalle en la sección Expresiones de consultas LINQ (Guía de
programación de C#). Aquí, lo importante es que, en LINQ, la propia variable
de consulta no realiza ninguna acción ni devuelve datos. Simplemente
almacena la información necesaria para generar los resultados cuando la
consulta se ejecute posteriormente. Para obtener más información sobre cómo
se construyen las consultas en segundo plano, vea Información general sobre
operadores de consulta estándar.
Nota
Ejecución diferida
// Query execution.
foreach (int num in numQuery)
{
Console.Write("{0,1} ", num);
}
var evenNumQuery =
from num in numbers
where (num % 2) == 0
select num;
List<int> numQuery2 =
(from num in numbers
where (num % 2) == 0
select num).ToList();
// or like this:
// numQuery3 is still an int[]
var numQuery3 =
(from num in numbers
where (num % 2) == 0
select num).ToArray();
Las consultas LINQ se basan en tipos genéricos, que se incluyeron por primera
vez en la versión 2.0 de .NET Framework. No se requieren conocimientos
avanzados de los tipos genéricos para poder empezar a escribir consultas. Sin
embargo, quizás necesite conocer dos conceptos básicos:
Para obtener más información acerca de los tipos genéricos, vea Genéricos
(Guía de programación de C#).
IEnumerable<Customer> customerQuery =
from cust in customers
where cust.City == "London"
select cust;
var customerQuery2 =
from cust in customers
where cust.City == "London"
select cust;
Nota
Si ya está familiarizado con un lenguaje de consultas como SQL o XQuery,
puede omitir la mayoría de este tema. Lea la parte dedicada a la cláusula from
en la sección siguiente para obtener información sobre el orden de las
cláusulas en las expresiones de consulta LINQ.
Obtener un origen de datos
En una consulta LINQ, el primer paso es especificar el origen de datos. En C#,
como en la mayoría de los lenguajes de programación, se debe declarar una
variable antes de poder utilizarla. En una consulta LINQ, la cláusula from
aparece en primer lugar para introducir el origen de datos (customers) y la
variable de rango (cust).
//queryAllCustomers is an IEnumerable<Customer>
var queryAllCustomers = from cust in customers
select cust;
Nota
Para los orígenes de datos no genéricos, como ArrayList, el tipo de la variable
de rango debe establecerse explícitamente. Para obtener más información, vea
Cómo: Consultar un objeto ArrayList con LINQ y from (Cláusula, Referencia de
C#).
Filtrar
Puede utilizar los operadores lógicos AND y OR de C#, con los que ya estará
familiarizado, para aplicar las expresiones de filtro que sean necesarias en la
cláusula where. Por ejemplo, para devolver sólo los clientes con dirección en
"London" AND cuyo nombre sea "Devon", escribiría el código siguiente:
Para devolver los clientes con dirección en Londres o París, escribiría el código
siguiente:
Ordering
var queryLondonCustomers3 =
from cust in customers
where cust.City == "London"
orderby cust.Name ascending
select cust;
Grupo
Nota
En los ejemplos siguientes, los tipos son explícitos, para ilustrar el concepto.
También podría utilizar tipos implícitos para custQuery, group y customer,
para que el compilador determine el tipo exacto.
Al finalizar una consulta con una cláusula group, los resultados adoptan la
forma de una lista de listas. Cada elemento de la lista es un objeto que tiene
un miembro Key y una lista de elementos agrupados bajo esa clave. Al
procesar una iteración en una consulta que genera una secuencia de grupos,
debe utilizar un bucle foreach anidado. El bucle exterior recorre en iteración
cada grupo y el bucle interior recorre en iteración los miembros de cada grupo.
Combinación
var innerJoinQuery =
from cust in customers
join dist in distributors on cust.City equals dist.City
select new { CustomerName = cust.Name, DistributorName = dist.Name };
En LINQ no es necesario utilizar join tan a menudo como en SQL, porque las
claves externas en LINQ se representan en el modelo de objetos como
propiedades que contienen una colección de elementos. Por ejemplo, un objeto
Customer contiene una colección de objetos Order. En lugar de realizar una
combinación, se tiene acceso a los pedidos utilizando la notación de punto:
Selección (proyecciones)