Introdução a consultas LINQ (C#)Introduction to LINQ Queries (C#)

Uma consulta é uma expressão que recupera dados de uma fonte de dados.A query is an expression that retrieves data from a data source. As consultas normalmente são expressas em uma linguagem de consulta especializada.Queries are usually expressed in a specialized query language. Diferentes linguagens foram desenvolvidas ao longo do tempo para os diversos tipos de fontes de dados, por exemplo, SQL para bancos de dados relacionais e o 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. Portanto, os desenvolvedores precisaram aprender uma nova linguagem de consulta para cada tipo de fonte de dados ou formato de dados que eles tinham que oferecer suporte.Therefore, developers have had to learn a new query language for each type of data source or data format that they must support. O LINQLINQ simplifica essa situação ao oferecer um modelo consistente para trabalhar com os dados entre vários tipos de fontes e formatos de dados.LINQLINQ simplifies this situation by offering a consistent model for working with data across various kinds of data sources and formats. Em uma consulta LINQLINQ, você está sempre trabalhando com objetos.In a LINQLINQ query, you are always working with objects. Você usa os mesmos padrões básicos de codificação para consultar e transformar dados em documentos XML, bancos de dados SQL, conjuntos de dados do ADO.NETADO.NET, coleções do .NET e qualquer outro formato para o qual um provedor LINQLINQ estiver disponível.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.

Três Partes de uma Operação de ConsultaThree Parts of a Query Operation

Todos as operações de consulta LINQLINQ consistem em três ações distintas:All LINQLINQ query operations consist of three distinct actions:

  1. Obter a fonte de dados.Obtain the data source.

  2. Criar a consulta.Create the query.

  3. Executar a consulta.Execute the query.

O exemplo a seguir mostra como as três partes de uma operação de consulta são expressas em código-fonte.The following example shows how the three parts of a query operation are expressed in source code. O exemplo usa uma matriz de inteiros como uma fonte de dados para sua conveniência. No entanto, os mesmos conceitos também se aplicam a outras fontes de dados.The example uses an integer array as a data source for convenience; however, the same concepts apply to other data sources also. Faremos referência a este exemplo todo o restante deste tópico.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);
        }
    }
}

A ilustração a seguir mostra a operação de consulta completa.The following illustration shows the complete query operation. No LINQLINQ, a execução da consulta é diferente da própria consulta. Em outras palavras, você não recupera dados apenas criando uma variável 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.

Operação de consulta LINQ completaComplete LINQ Query Operation

A Fonte de DadosThe Data Source

No exemplo anterior, como a fonte de dados é uma matriz, ela dá suporte à interface genérica IEnumerable<T> de forma implícita.In the previous example, because the data source is an array, it implicitly supports the generic IEnumerable<T> interface. Isso significa que ela pode ser consultada com o LINQLINQ.This fact means it can be queried with LINQLINQ. Uma consulta é executada em uma instrução foreach, e foreach requer IEnumerable ou IEnumerable<T>.A query is executed in a foreach statement, and foreach requires IEnumerable or IEnumerable<T>. Tipos que dão suporte a IEnumerable<T> ou uma interface derivada, como a genérica IQueryable<T>, são chamados tipos passíveis de consulta.Types that support IEnumerable<T> or a derived interface such as the generic IQueryable<T> are called queryable types.

Um tipo passível de consulta não exige modificação ou tratamento especial para servir como uma fonte de dados do LINQLINQ.A queryable type requires no modification or special treatment to serve as a LINQLINQ data source. Se os dados de origem ainda não estiverem na memória como um tipo passível de consulta, o provedor do LINQLINQ deverá representá-los como tal.If the source data is not already in memory as a queryable type, the LINQLINQ provider must represent it as such. Por exemplo, LINQ to XMLLINQ to XML carrega um documento XML em um tipo XElement passível de consulta: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");

Com o LINQ to SQLLINQ to SQL, primeiro você cria um mapeamento relacional de objeto em tempo de design, manualmente ou usando as Ferramentas LINQ to SQL no 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. Você escreve suas consultas aos objetos e o LINQ to SQLLINQ to SQL manipula a comunicação com o banco de dados em tempo de execução.You write your queries against the objects, and at run-time LINQ to SQLLINQ to SQL handles the communication with the database. No exemplo a seguir, Customers representa uma tabela específica no banco de dados, e o tipo do resultado da consulta, IQueryable<T>, 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 obter mais informações sobre como criar tipos específicos de fontes de dados, consulte a documentação para os diversos provedores do LINQLINQ.For more information about how to create specific types of data sources, see the documentation for the various LINQLINQ providers. No entanto, a regra básica é muito simples: uma fonte de dados LINQLINQ é qualquer objeto que dá suporte à interface genérica IEnumerable<T> ou uma interface que herda dela.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.

Observação

Tipos, como ArrayList, que dão suporte à interface IEnumerable não genérica também podem ser usados como uma fonte de dados LINQLINQ.Types such as ArrayList that support the non-generic IEnumerable interface can also be used as a LINQLINQ data source. Para obter mais informações, confira Como: Consultar uma ArrayList com LINQ (C#).For more information, see How to: Query an ArrayList with LINQ (C#).

A consultaThe Query

A consulta especifica quais informações devem ser recuperadas da fonte (ou fontes) de dados.The query specifies what information to retrieve from the data source or sources. Opcionalmente, uma consulta também especifica como essas informações devem ser classificadas, agrupadas e moldadas antes de serem retornadas.Optionally, a query also specifies how that information should be sorted, grouped, and shaped before it is returned. Uma consulta é armazenada em uma variável de consulta e é inicializada com uma expressão de consulta.A query is stored in a query variable and initialized with a query expression. Para tornar mais fácil escrever consultas, o C# introduziu uma nova sintaxe de consulta.To make it easier to write queries, C# has introduced new query syntax.

A consulta no exemplo anterior retorna todos os números pares da matriz de inteiros.The query in the previous example returns all the even numbers from the integer array. A expressão de consulta contém três cláusulas: from, where e select.The query expression contains three clauses: from, where and select. (Se você estiver familiarizado com o SQL, deve ter percebido que a ordem das cláusulas é invertida em relação à ordem no SQL). A cláusula from especifica a fonte de dados, a cláusula where aplica o filtro e a cláusula select especifica o tipo dos elementos retornados.(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. Essas e outras cláusulas de consulta são discutidas detalhadamente na seção Expressões de consulta LINQ.These and the other query clauses are discussed in detail in the LINQ Query Expressions section. Por enquanto, o ponto importante é que, no LINQLINQ, a variável de consulta não faz nada e não retorna nenhum dado.For now, the important point is that in LINQLINQ, the query variable itself takes no action and returns no data. Ele apenas armazena as informações necessárias para produzir os resultados quando a consulta for executada em um momento posterior.It just stores the information that is required to produce the results when the query is executed at some later point. Para obter mais informações sobre como as consultas são construídas nos bastidores, consulte Visão geral de operadores de consulta padrão (C#).For more information about how queries are constructed behind the scenes, see Standard Query Operators Overview (C#).

Observação

As consultas também podem ser expressas usando a sintaxe de método.Queries can also be expressed by using method syntax. Para obter mais informações, consulte Sintaxe de consulta e sintaxe de método em LINQ.For more information, see Query Syntax and Method Syntax in LINQ.

Execução da ConsultaQuery Execution

Execução AdiadaDeferred Execution

Conforme mencionado anteriormente, a variável de consulta armazena somente os comandos da consulta.As stated previously, the query variable itself only stores the query commands. A execução real da consulta é adiada até que você itere sobre a variável de consulta em uma instrução foreach.The actual execution of the query is deferred until you iterate over the query variable in a foreach statement. Esse conceito é conhecido como execução adiada e é demonstrado no exemplo a seguir: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);
}

A instrução foreach também é o local em que os resultados da consulta são recuperados.The foreach statement is also where the query results are retrieved. Por exemplo, na consulta anterior, a variável de iteração num armazena cada valor (um de cada vez) na sequência retornada.For example, in the previous query, the iteration variable num holds each value (one at a time) in the returned sequence.

Como a própria variável de consulta nunca armazena os resultados da consulta, você poderá executá-la quantas vezes desejar.Because the query variable itself never holds the query results, you can execute it as often as you like. Por exemplo, você pode ter um banco de dados que está sendo atualizado continuamente por um aplicativo separado.For example, you may have a database that is being updated continually by a separate application. Em seu aplicativo, você poderia criar uma consulta que recupera os dados mais recentes e poderia executá-la repetidamente em algum intervalo para recuperar resultados diferentes a 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.

Forçando Execução ImediataForcing Immediate Execution

As consultas que realizam funções de agregação em um intervalo de elementos de origem devem primeiro iterar sobre esses elementos.Queries that perform aggregation functions over a range of source elements must first iterate over those elements. Exemplos dessas consultas são Count, Max, Average e First.Examples of such queries are Count, Max, Average, and First. Essas consultas são executadas sem uma instrução foreach explícita porque a consulta em si deve usar foreach para retornar um resultado.These execute without an explicit foreach statement because the query itself must use foreach in order to return a result. Observe também que esses tipos de consultas retornam um valor único e não uma coleção IEnumerable.Note also that these types of queries return a single value, not an IEnumerable collection. A consulta a seguir retorna uma contagem de números pares na matriz de origem: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 forçar a execução imediata de qualquer consulta e armazenar seus resultados em cache, você pode chamar os métodos ToList ou 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();

Você também pode forçar a execução colocando o loop foreach imediatamente após a expressão de consulta.You can also force execution by putting the foreach loop immediately after the query expression. No entanto, ao chamar ToList ou ToArray, você também armazena em cache todos os dados em um único objeto de coleção.However, by calling ToList or ToArray you also cache all the data in a single collection object.

Consulte tambémSee also