Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Os operadores de consulta padrão são as palavras-chave e os métodos que formam o padrão LINQ. A linguagem C# define palavras-chave de consulta LINQ que você usa para a expressão de consulta mais comum. O compilador traduz expressões usando essas palavras-chave para as chamadas de método equivalentes. As duas formas são sinónimos. Outros métodos que fazem parte do System.Linq namespace não têm palavras-chave de consulta equivalentes. Nesses casos, você deve usar a sintaxe do método. Esta seção abrange todas as palavras-chave do operador de consulta. Os pacotes runtime e outros pacotes NuGet adicionam mais métodos projetados para trabalhar com consultas LINQ a cada nova versão. Os métodos mais comuns, incluindo aqueles que têm equivalentes de palavra-chave de consulta são abordados nesta seção. Para obter a lista completa de métodos de consulta suportados pelo .NET Runtime, consulte a documentação da System.Linq.Enumerable API. Além dos métodos abordados aqui, essa classe contém métodos para concatenar fontes de dados, calcular um único valor de uma fonte de dados, como uma soma, média ou outro valor.
Importante
Esses exemplos usam uma fonte de System.Collections.Generic.IEnumerable<T> dados. Fontes de dados baseadas em System.Linq.IQueryProvider utilizam fontes de dados System.Linq.IQueryable<T> e árvores de expressão . As árvores de expressão têm limitações na sintaxe C# permitida. Além disso, cada IQueryProvider
fonte de dados, como o EF Core , pode impor mais restrições. Verifique a documentação da sua fonte de dados.
A maioria desses métodos operam em sequências, onde uma sequência é um objeto cujo tipo implementa a IEnumerable<T> interface ou a IQueryable<T> interface. Os operadores de consulta padrão fornecem recursos de consulta, incluindo filtragem, projeção, agregação, classificação e muito mais. Os métodos que compõem cada conjunto são membros estáticos das Enumerable classes e Queryable , respectivamente. Eles são definidos como métodos de extensão do tipo em que operam.
A distinção entre IEnumerable<T> e IQueryable<T> sequências determina como a consulta é executada em tempo de execução.
Para IEnumerable<T>
, o objeto enumerável retornado captura os argumentos que foram passados para o método. Quando esse objeto é enumerado, a lógica do operador de consulta é empregada e os resultados da consulta são retornados.
Para IQueryable<T>
, a consulta é convertida em uma árvore de expressão. A árvore de expressões pode ser convertida em uma consulta nativa quando a fonte de dados pode otimizar a consulta. Bibliotecas como o Entity Framework convertem consultas LINQ em consultas SQL nativas que são executadas no banco de dados.
O exemplo de código a seguir demonstra como os operadores de consulta padrão podem ser usados para obter informações sobre uma sequência.
string sentence = "the quick brown fox jumps over the lazy dog";
// Split the string into individual words to create a collection.
string[] words = sentence.Split(' ');
// Using query expression syntax.
var query = from word in words
group word.ToUpper() by word.Length into gr
orderby gr.Key
select new { Length = gr.Key, Words = gr };
// Using method-based query syntax.
var query2 = words.
GroupBy(w => w.Length, w => w.ToUpper()).
Select(g => new { Length = g.Key, Words = g }).
OrderBy(o => o.Length);
foreach (var obj in query)
{
Console.WriteLine($"Words of length {obj.Length}:");
foreach (string word in obj.Words)
Console.WriteLine(word);
}
// This code example produces the following output:
//
// Words of length 3:
// THE
// FOX
// THE
// DOG
// Words of length 4:
// OVER
// LAZY
// Words of length 5:
// QUICK
// BROWN
// JUMPS
Sempre que possível, as consultas nesta secção utilizam uma sequência de palavras ou números como fonte de entrada. Para consultas em que são usadas relações mais complicadas entre objetos, as seguintes fontes que modelam uma escola são usadas:
public enum GradeLevel
{
FirstYear = 1,
SecondYear,
ThirdYear,
FourthYear
};
public class Student
{
public required string FirstName { get; init; }
public required string LastName { get; init; }
public required int ID { get; init; }
public required GradeLevel Year { get; init; }
public required List<int> Scores { get; init; }
public required int DepartmentID { get; init; }
}
public class Teacher
{
public required string First { get; init; }
public required string Last { get; init; }
public required int ID { get; init; }
public required string City { get; init; }
}
public class Department
{
public required string Name { get; init; }
public int ID { get; init; }
public required int TeacherID { get; init; }
}
Cada Student
tem um nível de grau, um departamento principal e vários resultados. A Teacher
também tem uma City
propriedade que identifica o campus onde o professor tem aulas. A Department
tem um nome, e uma referência a um Teacher
que serve como chefe de departamento.
Você pode encontrar o conjunto de dados no repositório de origem.
Tipos de operadores de consulta
Os operadores de consulta padrão diferem no tempo de sua execução, dependendo se eles retornam um valor singleton ou uma sequência de valores. Os métodos que retornam um valor singleton (como Average e Sum) são executados imediatamente. Os métodos que retornam uma sequência adiam a execução da consulta e retornam um objeto enumerável. Você pode usar a sequência de saída de uma consulta como a sequência de entrada para outra consulta. As chamadas para métodos de consulta podem ser encadeadas em uma consulta, o que permite que as consultas se tornem arbitrariamente complexas.
Operadores de consulta
Em uma consulta LINQ, a primeira etapa é especificar a fonte de dados. Em uma consulta LINQ, a from
cláusula vem primeiro para introduzir a fonte de dados (students
) e a variável range (student
).
//queryAllStudents is an IEnumerable<Student>
var queryAllStudents = from student in students
select student;
A variável range é como a variável de iteração em um foreach
loop, exceto que nenhuma iteração real ocorre em uma expressão de consulta. Quando a consulta é executada, a variável range serve como referência para cada elemento sucessivo no students
. Como o compilador pode inferir o tipo de student
, você não precisa especificá-lo explicitamente. Você pode introduzir mais variáveis de intervalo em uma let
cláusula. Para obter mais informações, consulte cláusula let.
Observação
Para fontes de dados não genéricas, como ArrayList, a variável range deve ser explicitamente digitada. Para obter mais informações, consulte Como consultar uma ArrayList com LINQ (C#) e from clause.
Depois de obter uma fonte de dados, você pode executar qualquer número de operações nessa fonte de dados:
-
Filtre os dados usando a
where
palavra-chave. -
Encomende os dados usando as
orderby
palavras-chave e, opcionalmentedescending
. -
Agrupe dados usando as
group
palavras-chave e, opcionalmenteinto
. -
Juntar dados usando a
join
palavra-chave. -
Dados do projeto usando a
select
palavra-chave.
Tabela de sintaxe de expressão de consulta
A tabela a seguir lista os operadores de consulta padrão que têm cláusulas de expressão de consulta equivalentes.
Transformações de dados com LINQ
Language-Integrated Query (LINQ) não se limita à recuperação de dados. É também uma ferramenta poderosa para transformar dados. Usando uma consulta LINQ, você pode usar uma sequência de origem como entrada e modificá-la de várias maneiras para criar uma nova sequência de saída. Você pode modificar a sequência em si sem modificar os próprios elementos classificando e agrupando. Mas talvez o recurso mais poderoso das consultas LINQ seja a capacidade de criar novos tipos. A cláusula select cria um elemento de saída a partir de um elemento de entrada. Você o usa para transformar um elemento de entrada em um elemento de saída:
- Mescle várias sequências de entrada em uma única sequência de saída que tenha um novo tipo.
- Crie sequências de saída cujos elementos consistem em apenas uma ou várias propriedades de cada elemento na sequência de origem.
- Crie sequências de saída cujos elementos consistam nos resultados das operações executadas nos dados de origem.
- Crie sequências de saída em um formato diferente. Por exemplo, você pode transformar dados de linhas SQL ou arquivos de texto em XML.
Essas transformações podem ser combinadas de várias maneiras na mesma consulta. Além disso, a sequência de saída de uma consulta pode ser usada como a sequência de entrada para uma nova consulta. O exemplo a seguir transforma objetos em uma estrutura de dados na memória em elementos XML.
// Create the query.
var studentsToXML = new XElement("Root",
from student in students
let scores = string.Join(",", student.Scores)
select new XElement("student",
new XElement("First", student.FirstName),
new XElement("Last", student.LastName),
new XElement("Scores", scores)
) // end "student"
); // end "Root"
// Execute the query.
Console.WriteLine(studentsToXML);
O código produz a seguinte saída XML:
<Root>
<student>
<First>Svetlana</First>
<Last>Omelchenko</Last>
<Scores>97,90,73,54</Scores>
</student>
<student>
<First>Claire</First>
<Last>O'Donnell</Last>
<Scores>56,78,95,95</Scores>
</student>
...
<student>
<First>Max</First>
<Last>Lindgren</Last>
<Scores>86,88,96,63</Scores>
</student>
<student>
<First>Arina</First>
<Last>Ivanova</Last>
<Scores>93,63,70,80</Scores>
</student>
</Root>
Para obter mais informações, consulte Criando árvores XML em C# (LINQ to XML).
Você pode usar os resultados de uma consulta como fonte de dados para uma consulta subsequente. Este exemplo mostra como ordenar os resultados de uma operação de junção. Essa consulta cria uma associação de grupo e, em seguida, classifica os grupos com base no elemento categoria, que ainda está dentro do escopo. Dentro do inicializador de tipo anônimo, uma subconsulta ordena todos os elementos correspondentes da sequência de produtos.
var orderedQuery = from department in departments
join student in students on department.ID equals student.DepartmentID into studentGroup
orderby department.Name
select new
{
DepartmentName = department.Name,
Students = from student in studentGroup
orderby student.LastName
select student
};
foreach (var departmentList in orderedQuery)
{
Console.WriteLine(departmentList.DepartmentName);
foreach (var student in departmentList.Students)
{
Console.WriteLine($" {student.LastName,-10} {student.FirstName,-10}");
}
}
/* Output:
Chemistry
Balzan Josephine
Fakhouri Fadi
Popov Innocenty
Seleznyova Sofiya
Vella Carmen
Economics
Adams Terry
Adaobi Izuchukwu
Berggren Jeanette
Garcia Cesar
Ifeoma Nwanneka
Jamuike Ifeanacho
Larsson Naima
Svensson Noel
Ugomma Ifunanya
Engineering
Axelsson Erik
Berg Veronika
Engström Nancy
Hicks Cassie
Keever Bruce
Micallef Nicholas
Mortensen Sven
Nilsson Erna
Tucker Michael
Yermolayeva Anna
English
Andersson Sarah
Feng Hanying
Ivanova Arina
Jakobsson Jesper
Jensen Christiane
Johansson Mark
Kolpakova Nadezhda
Omelchenko Svetlana
Urquhart Donald
Mathematics
Frost Gaby
Garcia Hugo
Hedlund Anna
Kovaleva Katerina
Lindgren Max
Maslova Evgeniya
Olsson Ruth
Sammut Maria
Sazonova Anastasiya
Physics
Åkesson Sami
Edwards Amy E.
Falzon John
Garcia Debra
Hansson Sanna
Mattsson Martina
Richardson Don
Zabokritski Eugene
*/
A consulta equivalente usando sintaxe de método é mostrada no código a seguir:
var orderedQuery = departments
.GroupJoin(students, department => department.ID, student => student.DepartmentID,
(department, studentGroup) => new
{
DepartmentName = department.Name,
Students = studentGroup.OrderBy(student => student.LastName)
})
.OrderBy(department => department.DepartmentName);
foreach (var departmentList in orderedQuery)
{
Console.WriteLine(departmentList.DepartmentName);
foreach (var student in departmentList.Students)
{
Console.WriteLine($" {student.LastName,-10} {student.FirstName,-10}");
}
}
Embora você possa usar uma orderby
cláusula com uma ou mais sequências de origem antes da junção, geralmente não a recomendamos. Alguns provedores LINQ podem não preservar esse pedido após a adesão. Para obter mais informações, consulte cláusula de junção.