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:
Obtenha a fonte de dados ou fontes.
Criar a consulta.
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 evensQuery
de 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 evensQuery
de 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 Average
First
. 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.