Escrevendo a primeira consulta LINQ (Visual Basic)

Uma consulta é uma expressão que recupera dados de uma fonte de dados. As consultas são expressas em uma linguagem de consulta dedicada. 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. Isso torna necessário que o desenvolvedor de aplicativos aprenda uma nova linguagem de consulta para cada tipo de fonte de dados ou formato de dados com suporte.

O LINQ simplifica essa situação ao oferecer um modelo consistente para trabalhar com os dados em vários tipos de fontes e formatos de dados. Em uma consulta LINQ, você está sempre trabalhando com objetos. 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.NET, coleções do .NET e qualquer outro formato para o qual um provedor LINQ estiver disponível. Este documento descreve as três fases da criação e do uso de consultas LINQ básicas.

Três Estágios de uma Operação de Consulta

Todos as operações de consulta LINQ consistem em três ações distintas:

  1. Obtenha a fonte de dados ou fontes.

  2. Criar a consulta.

  3. Executar a consulta.

No LINQ, a execução de uma consulta é distinta da criação da consulta. Você não recupera nenhum dado apenas criando uma consulta. Esse ponto é abordado com mais detalhes posteriormente neste tópico.

O exemplo a seguir ilustra as três partes de uma operação de consulta. O exemplo usa uma matriz de inteiros como uma fonte de dados conveniente para fins de demonstração. No entanto, os mesmos conceitos também se aplicam a outras fontes de dados.

Observação

Na Página de Compilação, Designer de Projeto (Visual Basic), verifique se a Opção Inferir está Ativada.

' Data source.
Dim numbers() As Integer = {0, 1, 2, 3, 4, 5, 6}

' Query creation.
Dim evensQuery = From num In numbers
                 Where num Mod 2 = 0
                 Select num

' Query execution.
For Each number In evensQuery
    Console.Write(number & " ")
Next

Saída:

0 2 4 6

A Fonte de Dados

No exemplo anterior, como a fonte de dados é uma matriz, ela dá suporte à interface genérica IEnumerable<T> de forma implícita. É esse fato que permite que você use uma matriz como fonte de dados para uma consulta LINQ. 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.

Um tipo passível de consulta não exige modificação ou tratamento especial para servir como uma fonte de dados do LINQ. O mesmo vale para qualquer tipo de coleção compatível, incluindo o genéricoIEnumerable<T>, List<T>e outras Dictionary<TKey,TValue>classes na biblioteca de classes .NET Framework.

Se os dados de origem ainda não forem implementados IEnumerable<T>, um provedor LINQ será necessário para implementar a funcionalidade dos operadores de consulta padrão para essa fonte de dados. Por exemplo, LINQ to XML manipula o trabalho de carregar um documento XML em um tipo consultávelXElement, conforme mostrado no exemplo a seguir. Para obter mais informações sobre os operadores de consulta padrão, consulte Visão geral de operadores de consulta padrão (C#).

' Create a data source from an XML document.
Dim contacts = XElement.Load("c:\myContactList.xml")

Com o LINQ 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. Você escreve suas consultas aos objetos e o LINQ to SQL manipula a comunicação com o banco de dados em tempo de execução. No exemplo a seguir, customers representa uma tabela específica no banco de dados, e Table<TEntity> suporta o IQueryable<T> genérico.

' Create a data source from a SQL table.
Dim db As New DataContext("C:\Northwind\Northwnd.mdf")
Dim customers As Table(Of Customer) = db.GetTable(Of Customer)

Para obter mais informações sobre como criar tipos específicos de fontes de dados, consulte a documentação para os diversos provedores LINQ. (Para obter uma lista desses provedores, consulte LINQ (Consulta Integrada à Linguagem).) No entanto, a regra básica é muito simples: uma fonte de dados do LINQ é qualquer objeto que dá suporte à interface genérica IEnumerable<T> ou uma interface que herda dela.

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 LINQ. Para obter um exemplo que usa um ArrayList, consulte Como consultar um ArrayList com LINQ (Visual Basic).

A consulta

Na consulta, você especifica exatamente as informações que deseja recuperar da fonte de dados. Você também tem a opção de especificar como essas informações devem ser classificadas, agrupadas ou estruturadas antes de serem retornadas. Para habilitar a criação de consulta, o Visual Basic incorporou uma nova sintaxe de consulta ao idioma.

Quando ele é executado, a consulta no exemplo a seguir retorna todos os números par de uma matriz de inteiros. numbers

' Data source.
Dim numbers() As Integer = {0, 1, 2, 3, 4, 5, 6}

' Query creation.
Dim evensQuery = From num In numbers
                 Where num Mod 2 = 0
                 Select num

' Query execution.
For Each number In evensQuery
    Console.Write(number & " ")
Next

A expressão de consulta contém três cláusulas: From, Where e Select. A função específica e a finalidade de cada cláusula de expressão de consulta são discutidas em Operações básicas de consulta (Visual Basic). Para obter mais informações, confira Consultas. Observe que, no LINQ, uma definição de consulta geralmente é armazenada em uma variável e executada posteriormente. A variável de consulta, como evensQuery no exemplo anterior, deve ser um tipo consultável. O tipo de evensQuery é IEnumerable(Of Integer)atribuído pelo compilador usando inferência de tipo local.

É importante lembrar que a variável de consulta não faz nada e não retorna nenhum dado. Ele armazena apenas a definição de consulta. No exemplo anterior, é o For Each loop que executa a consulta.

Execução da consulta

A execução da consulta é separada da criação da consulta. A criação de consulta define a consulta, mas a execução é disparada por um mecanismo diferente. Uma consulta pode ser executada assim que definida (execução imediata) ou a definição pode ser armazenada e a consulta pode ser executada posteriormente (execução adiada).

Execução Adiada

Uma consulta LINQ típica se assemelha à do exemplo anterior, na qual evensQuery é definida. Ele cria a consulta, mas não a executa imediatamente. Em vez disso, a definição de consulta é armazenada na variável evensQueryde consulta. Execute a consulta posteriormente, normalmente usando um For Each loop, que retorna uma sequência de valores ou aplicando um operador de consulta padrão, como Count ou Max. Esse processo é chamado de execução adiada.

' Query execution that results in a sequence of values.
For Each number In evensQuery
    Console.Write(number & " ")
Next

' Query execution that results in a single value.
Dim evens = evensQuery.Count()

Para uma sequência de valores, você acessa os dados recuperados usando a variável de iteração no For Each loop (number no exemplo anterior). Como a variável evensQueryde consulta contém a definição de consulta em vez dos resultados da consulta, você pode executar uma consulta quantas vezes quiser usando a variável de consulta mais de uma vez. Por exemplo, você pode ter um banco de dados que está sendo atualizado continuamente por um aplicativo separado. Depois de criar uma consulta que recupera dados desse banco de dados, você pode usar um For Each loop para executar a consulta repetidamente, recuperando os dados mais recentes sempre.

O exemplo a seguir demonstra como funcionam trabalhos de execução deferidos. Depois evensQuery2 de definido e executado com um For Each loop, como nos exemplos anteriores, alguns elementos na fonte numbers de dados são alterados. Em seguida, um segundo For Each loop é executado evensQuery2 novamente. Os resultados são diferentes na segunda vez, porque o For Each loop executa a consulta novamente, usando os novos valores em numbers.

Dim numberArray() = {0, 1, 2, 3, 4, 5, 6}

Dim evensQuery2 = From num In numberArray
                  Where num Mod 2 = 0
                  Select num

Console.WriteLine("Evens in original array:")
For Each number In evensQuery2
    Console.Write("  " & number)
Next
Console.WriteLine()

' Change a few array elements.
numberArray(1) = 10
numberArray(4) = 22
numberArray(6) = 8

' Run the same query again.
Console.WriteLine(vbCrLf & "Evens in changed array:")
For Each number In evensQuery2
    Console.Write("  " & number)
Next
Console.WriteLine()

Saída:

Evens in original array:

0 2 4 6

Evens in changed array:

0 10 2 22 8

Execução Imediata

Na execução adiada de consultas, a definição de consulta é armazenada em uma variável de consulta para execução posterior. Na execução imediata, a consulta é executada no momento de sua definição. A execução é disparada quando você aplica um método que requer acesso a elementos individuais do resultado da consulta. A execução imediata geralmente é forçada usando um dos operadores de consulta padrão que retornam valores únicos. Exemplos são Count, Max, e AverageFirst. Esses operadores de consulta padrão executam a consulta assim que são aplicados para calcular e retornar um resultado singleton. Para obter mais informações sobre operadores de consulta padrão que retornam valores únicos, consulte Operações de Agregação, Operações de Elemento e Operações quantificadoras.

A consulta a seguir retorna uma contagem de números pares na matriz de inteiros. A definição de consulta não é salva e numEvens é simples Integer.

Dim numEvens = (From num In numbers
                Where num Mod 2 = 0
                Select num).Count()

Você pode obter o mesmo resultado usando o Aggregate método.

Dim numEvensAgg = Aggregate num In numbers
                  Where num Mod 2 = 0
                  Select num
                  Into Count()

Você também pode forçar a execução de uma consulta chamando o método ou ToList o ToArray método em uma consulta (imediata) ou variável de consulta (adiada), conforme mostrado no código a seguir.

' Immediate execution.
Dim evensList = (From num In numbers
                 Where num Mod 2 = 0
                 Select num).ToList()

' Deferred execution.
Dim evensQuery3 = From num In numbers
                  Where num Mod 2 = 0
                  Select num
' . . .
Dim evensArray = evensQuery3.ToArray()

Nos exemplos anteriores, evensQuery3 é uma variável de consulta, mas evensList é uma lista e evensArray é uma matriz.

Usar ToList ou ToArray forçar a execução imediata é especialmente útil em cenários nos quais você deseja executar a consulta imediatamente e armazenar em cache os resultados em um único objeto de coleção. Para obter mais informações sobre esses métodos, consulte Converter tipos de dados.

Você também pode fazer com que uma consulta seja executada usando um IEnumerable método como o IEnumerable.GetEnumerator método.

Confira também