Introducción a las consultas LINQ (C#)Introduction to LINQ Queries (C#)

Una consulta es una expresión que recupera datos de un origen de datos.A query is an expression that retrieves data from a data source. Las consultas se suelen expresar en un lenguaje de consultas especializado.Queries are usually expressed in a specialized query language. Con el tiempo se han desarrollado diferentes lenguajes para los distintos tipos de orígenes de datos, como SQL para las bases de datos relacionales y XQuery para XML.Different languages have been developed over time for the various types of data sources, for example SQL for relational databases and XQuery for 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 deben admitir.Therefore, developers have had to learn a new query language for each type of data source or data format that they must support. LINQLINQ simplifica esta situación al ofrecer un modelo coherente para trabajar con los datos de varios formatos y orígenes. simplifies this situation by offering a consistent model for working with data across various kinds of data sources and formats. En una consulta LINQLINQ siempre se trabaja con objetos.In a LINQLINQ query, you are always working with objects. Se usan los mismos modelos de codificación básicos para consultar y transformar los datos en documentos XML, bases de datos SQL, conjuntos de datos ADO.NETADO.NET, colecciones de .NET y cualquier otro formato para el que está disponible un proveedor de LINQLINQ.You use the same basic coding patterns to query and transform data in XML documents, SQL databases, ADO.NETADO.NET Datasets, .NET collections, and any other format for which a LINQLINQ provider is available.

Las tres partes de una operación de consultaThree Parts of a Query Operation

Todas las operaciones de consulta LINQLINQ constan de tres acciones distintas:All LINQLINQ query operations consist of three distinct actions:

  1. Obtener el origen de datos.Obtain the data source.

  2. Crear la consulta.Create the query.

  3. Ejecutar la consulta.Execute the query.

En el siguiente ejemplo se muestra cómo se expresan las tres partes de una operación de consulta en código fuente.The following example shows how the three parts of a query operation are expressed in source code. En el ejemplo se usa una matriz de enteros como origen de datos para su comodidad, aunque se aplican los mismos conceptos a otros orígenes de datos.The example uses an integer array as a data source for convenience; however, the same concepts apply to other data sources also. En el resto de este tema se hará referencia a este ejemplo.This example is referred to throughout the rest of this topic.

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);
        }
    }
}

En la siguiente ilustración se muestra toda la operación de consulta.The following illustration shows the complete query operation. En LINQLINQ, la ejecución de la consulta es distinta de la propia consulta; en otras palabras, no ha recuperado los datos creando una variable de consulta.In LINQLINQ the execution of the query is distinct from the query itself; in other words you have not retrieved any data just by creating a query variable.

Operación completa de consulta LINQComplete LINQ Query Operation

El origen de datosThe Data Source

En el ejemplo anterior, como el origen de datos es una matriz, admite implícitamente la interfaz genérica IEnumerable<T>.In the previous example, because the data source is an array, it implicitly supports the generic IEnumerable<T> interface. Este hecho implica que se puede consultar con LINQLINQ.This fact means it can be queried with LINQLINQ. Se ejecuta una consulta en una instrucción foreach, y foreach requiere IEnumerable o bien IEnumerable<T>.A query is executed in a foreach statement, and foreach requires IEnumerable or IEnumerable<T>. Los tipos compatibles con IEnumerable<T> o una interfaz derivada, como la interfaz genérica IQueryable<T>, se denominan tipos consultables.Types that support IEnumerable<T> or a derived interface such as the generic IQueryable<T> are called queryable types.

Un tipo consultable no requiere ninguna modificación ni ningún tratamiento especial para actuar como origen de datos de LINQLINQ.A queryable type requires no modification or special treatment to serve as a LINQLINQ data source. Si el origen de datos no está en la memoria como tipo consultable, el proveedor de LINQLINQ debe representarlo como tal.If the source data is not already in memory as a queryable type, the LINQLINQ provider must represent it as such. Por ejemplo, LINQ to XMLLINQ to XML carga un documento XML en un tipo XElement consultable:For example, LINQ to XMLLINQ to XML loads an XML document into a queryable XElement type:

// Create a data source from an XML document.
// using System.Xml.Linq;
XElement contacts = XElement.Load(@"c:\myContactList.xml");

Con LINQ to SQLLINQ to SQL, primero se crea una asignación relacional de objetos en tiempo de diseño ya sea manualmente o mediante las herramientas de LINQ to SQL de Visual Studio.With LINQ to SQLLINQ to SQL, you first create an object-relational mapping at design time either manually or by using the LINQ to SQL Tools in Visual Studio in Visual Studio. Después, se escriben las consultas en los objetos y, en tiempo de ejecución, LINQ to SQLLINQ to SQL controla la comunicación con la base de datos.You write your queries against the objects, and at run-time LINQ to SQLLINQ to SQL handles the communication with the database. En el ejemplo siguiente, Customers representa una tabla específica en una base de datos, y el tipo del resultado de la consulta, IQueryable<T>, se deriva de IEnumerable<T>.In the following example, Customers represents a specific table in the database, and the type of the query result, IQueryable<T>, derives from IEnumerable<T>.

Northwnd db = new Northwnd(@"c:\northwnd.mdf");  

// Query for customers in London.  
IQueryable<Customer> custQuery =  
    from cust in db.Customers  
    where cust.City == "London"  
    select cust;  

Para obtener más información sobre cómo crear tipos específicos de orígenes de datos, vea la documentación de los distintos proveedores de LINQLINQ.For more information about how to create specific types of data sources, see the documentation for the various LINQLINQ providers. Aun así, la regla básica es muy sencilla: un origen de datos de LINQLINQ es cualquier objeto que admita la interfaz genérica IEnumerable<T> o una interfaz que la haya heredado.However, the basic rule is very simple: a LINQLINQ data source is any object that supports the generic IEnumerable<T> interface, or an interface that inherits from it.

Nota

Los tipos como ArrayList, compatibles con la interfaz no genérica IEnumerable, también se pueden usar como origen de datos de LINQLINQ.Types such as ArrayList that support the non-generic IEnumerable interface can also be used as a LINQLINQ data source. Para obtener más información, vea How to: Query an ArrayList with LINQ (C#) (Consultar un objeto ArrayList con LINQ (C#)).For more information, see How to: Query an ArrayList with LINQ (C#).

La consultaThe Query

La consulta especifica la información que se debe recuperar de los orígenes de datos.The query specifies what information to retrieve from the data source or sources. Opcionalmente, una consulta también especifica cómo se debe ordenar, agrupar y conformar esa información antes de que se devuelva.Optionally, a query also specifies how that information should be sorted, grouped, and shaped before it is returned. Las consultas se almacenan en una variable de consulta y se inicializan con una expresión de consulta.A query is stored in a query variable and initialized with a query expression. Para facilitar la escritura de consultas, C# ha incorporado una nueva sintaxis de consulta.To make it easier to write queries, C# has introduced new query syntax.

La consulta del ejemplo anterior devuelve todos los números pares de la matriz de enteros.The query in the previous example returns all the even numbers from the integer array. La expresión de consulta contiene tres cláusulas: from, where y selectThe query expression contains three clauses: from, where and 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.(If you are familiar with SQL, you will have noticed that the ordering of the clauses is reversed from the order in SQL.) The from clause specifies the data source, the where clause applies the filter, and the select clause specifies the type of the returned elements. Estas y otras cláusulas de consulta se tratan con detalle en la sección Expresiones de consulta LINQ.These and the other query clauses are discussed in detail in the LINQ Query Expressions section. Por ahora, lo importante es que en LINQLINQ la variable de consulta no efectúa ninguna acción y no devuelve ningún dato.For now, the important point is that in LINQLINQ, the query variable itself takes no action and returns no data. Lo único que hace es almacenar la información necesaria para generar los resultados cuando se ejecuta la consulta en algún momento posterior.It just stores the information that is required to produce the results when the query is executed at some later point. 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 (C#).For more information about how queries are constructed behind the scenes, see Standard Query Operators Overview (C#).

Nota

Las consultas también se pueden expresar empleando una sintaxis de método.Queries can also be expressed by using method syntax. Para obtener más información, vea Query Syntax and Method Syntax in LINQ (Sintaxis de consulta y sintaxis de método en LINQ).For more information, see Query Syntax and Method Syntax in LINQ.

Ejecución de la consultaQuery Execution

Ejecución aplazadaDeferred Execution

Como se ha indicado anteriormente, la variable de consulta solo almacena los comandos de consulta.As stated previously, the query variable itself only stores the query commands. La ejecución real de la consulta se aplaza hasta que se procese una iteración en la variable de consulta en una instrucción foreach.The actual execution of the query is deferred until you iterate over the query variable in a foreach statement. Este concepto se conoce como ejecución aplazada y se muestra en el ejemplo siguiente:This concept is referred to as deferred execution and is demonstrated in the following example:

//  Query execution. 
foreach (int num in numQuery)
{
    Console.Write("{0,1} ", num);
}

La instrucción foreach es también donde se recuperan los resultados de la consulta.The foreach statement is also where the query results are retrieved. Por ejemplo, en la consulta anterior, la variable de iteración num contiene cada valor (de uno en uno) en la secuencia devuelta.For example, in the previous query, the iteration variable num holds each value (one at a time) in the returned sequence.

Dado que la propia variable de consulta nunca contiene los resultados de la consulta, puede ejecutarla tantas veces como desee.Because the query variable itself never holds the query results, you can execute it as often as you like. Por ejemplo, se puede tener una base de datos que esté siendo actualizada de forma continua por otra aplicación.For example, you may have a database that is being updated continually by a separate application. En su aplicación, se puede crear una consulta que recupere los datos más recientes y se puede ejecutar repetidamente de acuerdo con un intervalo para recuperar resultados diferentes cada vez.In your application, you could create one query that retrieves the latest data, and you could execute it repeatedly at some interval to retrieve different results every time.

Forzar la ejecución inmediataForcing Immediate Execution

Las consultas que llevan a cabo funciones de agregación en un intervalo de elementos de origen primero deben recorrer en iteración dichos elementos.Queries that perform aggregation functions over a range of source elements must first iterate over those elements. Ejemplos de estas consultas son Count, Max, Average y First.Examples of such queries are Count, Max, Average, and First. Se ejecutan sin una instrucción foreach explícita, ya que la propia consulta debe usar foreach para poder devolver un resultado.These execute without an explicit foreach statement because the query itself must use foreach in order to return a result. Tenga en cuenta también que estos tipos de consultas devuelven un único valor, y no una colección IEnumerable.Note also that these types of queries return a single value, not an IEnumerable collection. La consulta siguiente devuelve un recuento de los números pares de la matriz de origen:The following query returns a count of the even numbers in the source array:

var evenNumQuery = 
    from num in numbers
    where (num % 2) == 0
    select num;

int evenNumCount = evenNumQuery.Count();

Para forzar la ejecución inmediata de cualquier consulta y almacenar en caché los resultados correspondientes, puede llamar a los métodos ToList o ToArray.To force immediate execution of any query and cache its results, you can call the ToList or ToArray methods.

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();

También puede forzar la ejecución colocando el bucle foreach justo después de la expresión de consulta,You can also force execution by putting the foreach loop immediately after the query expression. aunque, si se llama a ToList o a ToArray, también se almacenan en caché todos los datos de un objeto de colección.However, by calling ToList or ToArray you also cache all the data in a single collection object.

Vea tambiénSee Also

Introducción a LINQ en C#Getting Started with LINQ in C#
Tutorial: Escribir consultas en C#Walkthrough: Writing Queries in C#
Tutorial: Escribir consultas en C#Walkthrough: Writing Queries in C#
Expresiones de consulta LINQLINQ Query Expressions
foreach, inforeach, in
Palabras clave para consultas (LINQ)Query Keywords (LINQ)