Consultas en LINQ to Entities
Una consulta es una expresión que recupera datos de un origen de datos. Las consultas se suelen expresar en un lenguaje de consulta especializado, como SQL para bases de datos relacionales y XQuery para XML. Por lo tanto, los programadores han tenido que aprender un lenguaje de consultas nuevo para cada tipo de origen de datos o formato de datos que consultan. Language-Integrated Query (LINQ) ofrece un modelo coherente y más sencillo para trabajar con los datos de varios formatos y orígenes de datos. En una consulta de LINQ siempre se trabaja con objetos de programación.
Una operación de consulta de LINQ consta de tres acciones: obtener el origen o los orígenes de datos, crear la consulta y ejecutar la consulta.
Los orígenes de datos que implementan las interfaces genéricas IEnumerable o IQueryable pueden consultarse a través de LINQ. Las instancias de la clase ObjectQuery, que implementa la interfaz genérica IQueryable, actúan como origen de datos para las consultas LINQ to Entities. La clase ObjectQuery genérica representa una consulta que devuelve una instancia o colección de entidades con tipo. El programador crea una instancia de ObjectContext, que es la clase principal para interactuar con un Entity Data Model (EDM) como objetos de CLR.
En la consulta se especifica exactamente la información que se desea recuperar del origen de datos. Una consulta también puede especificar cómo se debe ordenar, agrupar y conformar esa información antes de que se devuelva. En LINQ, una consulta se almacena en una variable. Si la consulta devuelve una secuencia de valores, la propia variable de la consulta debe ser de un tipo que se pueda consultar. Esta variable de consulta no realiza ninguna acción y no devuelve datos; solamente almacena la información de la consulta. Tras crear una consulta debe ejecutarla para recuperar los datos.
En una consulta que devuelve una secuencia de valores, la variable de consulta por sí misma nunca conserva los resultados de la consulta y sólo almacena sus comandos. La ejecución de la consulta se aplaza hasta que la variable de consulta se recorre en iteración en un bucle foreach o For Each. Esto se denomina ejecución aplazada; es decir, la ejecución de la consulta se produce después de que se cree la consulta. Esto significa que se puede ejecutar una consulta con la frecuencia que se desee. Esto es útil cuando, por ejemplo, se tiene una base de datos que otras aplicaciones están actualizando. En su aplicación puede crear una consulta para recuperar la información más reciente y ejecutar de forma repetida la consulta, devolviendo cada vez la información actualizada.
A diferencia de las consultas aplazadas, que devuelven una secuencia de valores, las consultas que devuelven un valor singleton se ejecutan inmediatamente. Algunos ejemplos de consultas singleton son Count, Max, Average y First. Se ejecutan inmediatamente porque se necesitan los resultados de la consulta para calcular el resultado singleton. También puede usar los métodos ToList o ToArray en una consulta para forzar la ejecución inmediata de una consulta que no crea un valor singleton. Esas técnicas para forzar la ejecución inmediata pueden ser útiles si desea almacenar en memoria caché los resultados de una consulta. Para obtener más información acerca de la ejecución de consultas aplazadas e inmediatas, vea introducción a LINQ.
Consultas
Las consultas de LINQ to Entities se pueden formular en dos sintaxis diferentes: sintaxis de expresiones de consulta y sintaxis de consultas basadas en métodos. La sintaxis de expresiones de consulta es nueva en C# 3.0 y Visual Basic 9.0, y consta de un conjunto de cláusulas escritas en una sintaxis declarativa similar a Transact-SQL o XQuery. No obstante, Common Language Runtime (CLR) de .NET Framework no puede leer la sintaxis de expresiones de consulta por sí mismo. Por lo tanto, en tiempo de compilación, las expresiones de consulta se convierten en algo que CLR no comprende: las llamadas a métodos. Esos métodos se conocen como operadores de consulta estándar. Como programador, tiene la opción de llamarlos directamente utilizando la sintaxis de método en lugar de la sintaxis de consulta. Para obtener más información, vea Sintaxis de consultas y Sintaxis de métodos (LINQ). Para obtener más información sobre cómo usar los operadores de consulta estándar, vea Guía de programación general con LINQ.
Sintaxis de expresiones de consulta
Las expresiones de consulta son una sintaxis de consulta declarativa. Esta sintaxis permite a un programador escribir consultas en un lenguaje de alto nivel que tenga un formato similar al de Transact-SQL. Si se utiliza la sintaxis de expresiones de consulta, se pueden realizar incluso operaciones complejas de filtrado, ordenación y agrupamiento en orígenes de datos con código mínimo. Para obtener más información, vea Expresiones de consultas con LINQ (Guía de programación de C#) y Operaciones básicas de consulta (Visual Basic).
En el ejemplo siguiente se usa Select para devolver todas las filas de Product y mostrar los nombres de producto.
Using AWEntities As New AdventureWorksEntities
Dim products As ObjectQuery(Of Product) = AWEntities.Product
Dim productNames = _
From p In products _
Select p.Name
Console.WriteLine("Product Names:")
For Each productName In productNames
Console.WriteLine(productName)
Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
ObjectQuery<Product> products = AWEntities.Product;
IQueryable<string> productNames =
from p in products
select p.Name;
Console.WriteLine("Product Names:");
foreach (var productName in productNames)
{
Console.WriteLine(productName);
}
}
Sintaxis de consultas basadas en métodos
Otra forma de formular consultas de LINQ to Entities es usar las consultas basadas en métodos. La sintaxis de consultas basadas en métodos es una secuencia de llamadas directas a los métodos de operador de LINQ que pasan expresiones lambda como parámetros. Para obtener más información, vea Expresiones lambda (Guía de programación de C#).
En este ejemplo se usa Select para devolver todas las filas de Product y mostrar los nombres de producto.
Using AWEntities As New AdventureWorksEntities
Dim productNames = AWEntities.Product.Select(Function(p) p.Name)
Console.WriteLine("Product Names:")
For Each productName In productNames
Console.WriteLine(productName)
Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
ObjectQuery<Product> products = AWEntities.Product;
IQueryable<string> productNames = products.Select(p => p.Name);
Console.WriteLine("Product Names:");
foreach (var productName in productNames)
{
Console.WriteLine(productName);
}
}
Crear consultas
Tal y como se ha mencionado anteriormente en este tema, la variable de consulta sólo almacena los comandos de la consulta cuando ésta se diseña para devolver una secuencia de valores. Si la consulta no contiene un método que origine una ejecución inmediata, la ejecución real de la consulta se aplazará hasta que la variable de consulta se recorra en iteración en un bucle foreach o For Each. La ejecución aplazada permite combinar varias consultas o ampliar una consulta. Cuando se amplía una consulta, se modifica para incluir las nuevas operaciones. La ejecución final reflejará los cambios. En el siguiente ejemplo, la primera consulta devuelve todos los productos. La segunda consulta amplía la primera usando Where para devolver todos los productos de tamaño "L":
Using AWEntities As New AdventureWorksEntities()
Dim products As ObjectQuery(Of Product) = AWEntities.Product
Dim productsQuery = _
From p In products _
Select p
Dim largeProducts = _
productsQuery.Where(Function(p) p.Size = "L")
Console.WriteLine("Products of size 'L':")
For Each product In largeProducts
Console.WriteLine(product.Name)
Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
ObjectQuery<Product> products = AWEntities.Product;
IQueryable<Product> productsQuery =
from p in products
select p;
IQueryable<Product> largeProducts = productsQuery.Where(p => p.Size == "L");
Console.WriteLine("Products of size 'L':");
foreach (var product in largeProducts)
{
Console.WriteLine(product.Name);
}
}
Una vez ejecutada una consulta, todas las consultas sucesivas utilizarán los operadores de LINQ en memoria. Si se recorre en iteración la variable de la consulta utilizando una instrucción foreach o For Each o llamando a uno de los operadores de conversión de LINQ, se producirá la ejecución inmediata. Entre estos operadores de conversión se incluyen los siguientes: ToList, ToArray, ToLookup y ToDictionary.
En el siguiente ejemplo, la primera consulta devuelve todos los productos. La segunda consulta amplía la primera una vez que esta se haya ejecutado para devolver los productos de color rojo.
Using AWEntities As New AdventureWorksEntities()
Dim products As ObjectQuery(Of Product) = AWEntities.Product
Dim productsQuery = _
From p In products _
Select p
Console.WriteLine("The list of products:")
For Each Product As Product In productsQuery
Console.WriteLine(Product.Name)
Next
Dim redProducts = productsQuery _
.Where(Function(p) p.Color = "Red") _
.Select(Function(p) p)
Console.WriteLine("")
Console.WriteLine("The list of red products:")
For Each redProduct As Product In redProducts
Console.WriteLine(redProduct.Name)
Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
ObjectQuery<Product> products = AWEntities.Product;
IQueryable<Product> productsQuery =
from p in products
select p;
Console.WriteLine("The list of products:");
foreach (Product product in productsQuery)
{
Console.WriteLine(product.Name);
}
IQueryable<Product> redProducts = productsQuery
.Where(p => p.Color == "Red")
.Select(p => p);
Console.WriteLine("");
Console.WriteLine("The list of red products:");
foreach (Product redProduct in redProducts)
{
Console.WriteLine(redProduct.Name);
}
}
Vea también
Otros recursos
LINQ to Entities
Introducción a LINQ en C#
Introducción a LINQ en Visual Basic