Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Les opérateurs de requête standard sont les mots clés et méthodes qui forment le modèle LINQ. Le langage C# définit des mots clés de requête LINQ que vous utilisez pour l’expression de requête la plus courante. Le compilateur traduit des expressions à l’aide de ces mots clés en appels de méthode équivalents. Les deux formes sont synonymes. Les autres méthodes qui font partie de l’espace System.Linq de noms n’ont pas de mots clés de requête équivalents. Dans ce cas, vous devez utiliser la syntaxe de méthode. Cette section couvre tous les mots clés de l’opérateur de requête. Le runtime et d’autres packages NuGet ajoutent d’autres méthodes conçues pour fonctionner avec des requêtes LINQ chaque version. Les méthodes les plus courantes, y compris celles qui ont des équivalents de mot clé de requête, sont abordées dans cette section. Pour obtenir la liste complète des méthodes de requête prises en charge par le runtime .NET, consultez la documentation de l’API System.Linq.Enumerable . Outre les méthodes décrites ici, cette classe contient des méthodes pour concaténer des sources de données, en calculant une valeur unique à partir d’une source de données, telle qu’une somme, une moyenne ou une autre valeur.
Importante
Ces exemples utilisent une source de données System.Collections.Generic.IEnumerable<T>. Les sources de données basées sur System.Linq.IQueryProvider utilisent des sources de données System.Linq.IQueryable<T> et des arborescences d’expressions. Les arborescences d’expressions présentent des limitations sur la syntaxe C# autorisée. De plus, chaque source de données IQueryProvider
, telle que EF Core peut imposer des restrictions supplémentaires. Consultez la documentation de votre source de données.
La plupart de ces méthodes fonctionnent sur des séquences, où une séquence est un objet dont le type implémente l’interface IEnumerable<T> ou l’interface IQueryable<T> . Les opérateurs de requête standard offrent des fonctionnalités de requête, notamment le filtrage, la projection, l’agrégation, le tri et bien plus encore. Les méthodes qui composent chaque ensemble sont des membres statiques des classes Enumerable et Queryable, respectivement. Ils sont définis en tant que méthodes d’extension du type sur lequel ils opèrent.
La distinction entre IEnumerable<T> et IQueryable<T> séquences détermine la façon dont la requête est exécutée au moment de l’exécution.
Pour IEnumerable<T>
, l’objet énumérable retourné capture les arguments passés à la méthode. Lorsque cet objet est énuméré, la logique de l’opérateur de requête est utilisée et les résultats de la requête sont retournés.
Pour IQueryable<T>
, la requête est traduite en arborescence d’expressions. L’arborescence d’expressions peut être traduite en requête native lorsque la source de données peut optimiser la requête. Les bibliothèques telles que Entity Framework traduisent des requêtes LINQ en requêtes SQL natives qui s’exécutent sur la base de données.
L’exemple de code suivant montre comment les opérateurs de requête standard peuvent être utilisés pour obtenir des informations sur une séquence.
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
Dans la mesure du possible, les requêtes de cette section utilisent une séquence de mots ou de nombres comme source d’entrée. Pour les requêtes où des relations plus complexes entre les objets sont utilisées, les sources suivantes qui modélisent une école sont utilisées :
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; }
}
Chaque Student
a un niveau scolaire, un département principal et une série de notes. Un Teacher
a également une propriété City
qui identifie le campus où l’enseignant donne des cours. Un Department
a un nom, et une référence à un Teacher
qui est responsable du département.
Vous trouverez le jeu de données dans le référentiel source.
Types d’opérateurs de requête
Les opérateurs de requête standard diffèrent dans le minutage de leur exécution, selon qu’ils retournent une valeur singleton ou une séquence de valeurs. Ces méthodes qui retournent une valeur singleton (par exemple Average et Sum) s’exécutent immédiatement. Méthodes qui retournent une séquence reportent l’exécution de la requête et retournent un objet énumérable. Vous pouvez utiliser la séquence de sortie d’une requête comme séquence d’entrée pour une autre requête. Les appels aux méthodes de requête peuvent être chaînés dans une requête, ce qui permet aux requêtes de devenir arbitrairement complexes.
Opérateurs de requête
Dans une requête LINQ, la première étape consiste à spécifier la source de données. Dans une requête LINQ, la from
clause est d’abord disponible pour introduire la source de données (students
) et la variable de plage (student
).
//queryAllStudents is an IEnumerable<Student>
var queryAllStudents = from student in students
select student;
La variable de plage est semblable à la variable d’itération dans une foreach
boucle, sauf qu’aucune itération réelle ne se produit dans une expression de requête. Lorsque la requête est exécutée, la variable de plage sert de référence à chaque élément successif dans students
. Étant donné que le compilateur peut déduire le type de student
, vous n'avez pas besoin de le spécifier explicitement. Vous pouvez introduire d’autres variables de plage dans une let
clause. Pour plus d’informations, consultez let, clause.
Remarque
Pour les sources de données non génériques telles que ArrayList, la variable de plage doit être typée explicitement. Pour plus d’informations, consultez Comment interroger un ArrayList avec LINQ (C#) et la clause from.
Une fois que vous avez obtenu une source de données, vous pouvez effectuer n’importe quel nombre d’opérations sur cette source de données :
-
Filtrez les données à l’aide du
where
mot clé. -
Commandez des données à l’aide des
orderby
mots clés et éventuellementdescending
. -
Regroupez les données à l’aide des
group
mots clés et éventuellementinto
. -
Joignez des données à l’aide du
join
mot clé. -
Données de projet à l’aide du
select
mot clé.
Table de syntaxe d’expression de requête
Le tableau suivant répertorie les opérateurs de requête standard qui ont des clauses d’expression de requête équivalentes.
Transformations de données avec LINQ
Language-Integrated Query (LINQ) ne concerne pas seulement la récupération des données. Il s’agit également d’un outil puissant pour transformer des données. À l’aide d’une requête LINQ, vous pouvez utiliser une séquence source comme entrée et la modifier de plusieurs façons pour créer une séquence de sortie. Vous pouvez modifier la séquence elle-même sans modifier les éléments eux-mêmes en triant et en regroupant. Mais la fonctionnalité la plus puissante des requêtes LINQ est peut-être la possibilité de créer de nouveaux types. La clause select crée un élément de sortie à partir d’un élément d’entrée. Vous l’utilisez pour transformer un élément d’entrée en élément de sortie :
- Fusionnez plusieurs séquences d’entrée en une seule séquence de sortie qui a un nouveau type.
- Créez des séquences de sortie dont les éléments se composent d’une ou plusieurs propriétés de chaque élément dans la séquence source.
- Créez des séquences de sortie dont les éléments sont constitués des résultats des opérations effectuées sur les données sources.
- Créez des séquences de sortie dans un autre format. Par exemple, vous pouvez transformer des données à partir de lignes SQL ou de fichiers texte en XML.
Ces transformations peuvent être combinées de différentes manières dans la même requête. En outre, la séquence de sortie d’une requête peut être utilisée comme séquence d’entrée pour une nouvelle requête. L’exemple suivant transforme les objets d’une structure de données en mémoire en éléments 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);
Le code produit la sortie XML suivante :
<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>
Pour plus d’informations, consultez Création d’arborescences XML en C# (LINQ to XML).
Vous pouvez utiliser les résultats d’une requête comme source de données pour une requête ultérieure. Cet exemple montre comment classer les résultats d’une opération de jointure. Cette requête crée une jointure groupée, puis trie les groupes en fonction de l’élément de catégorie, qui est encore dans la portée. Dans l’initialiseur de type anonyme, une sous-requête commande tous les éléments correspondants de la séquence de produits.
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
*/
La requête équivalente utilisant la syntaxe de méthode est illustrée dans le code suivant :
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}");
}
}
Bien que vous puissiez utiliser une orderby
clause avec une ou plusieurs séquences sources avant la jointure, nous ne le recommandons généralement pas. Certains fournisseurs LINQ peuvent ne pas conserver cette commande après la jointure. Pour plus d’informations, consultez la clause de jointure .