Delen via


Overzicht van standaard query-operators

De standaardqueryoperators zijn de trefwoorden en methoden die het LINQ-patroon vormen. De C#-taal definieert LINQ-querytrefwoorden die u gebruikt voor de meest voorkomende query-expressie. De compiler vertaalt expressies met behulp van deze trefwoorden naar de equivalente methode-aanroepen. De twee vormen zijn synoniem. Andere methoden die deel uitmaken van de System.Linq naamruimte hebben geen equivalente querytrefwoorden. In die gevallen moet u de syntaxis van de methode gebruiken. In deze sectie worden alle trefwoorden van de queryoperator behandeld. De runtime en andere NuGet-pakketten voegen meer methoden toe die zijn ontworpen om elke release te werken met LINQ-query's. In deze sectie worden de meest voorkomende methoden behandeld, waaronder methoden met trefwoordequivalenten voor query's. Zie de API-documentatie voor de System.Linq.Enumerable volledige lijst met querymethoden die worden ondersteund door .NET Runtime. Naast de methoden die hier worden behandeld, bevat deze klasse methoden voor het samenvoegen van gegevensbronnen, het berekenen van één waarde uit een gegevensbron, zoals een som, gemiddelde of andere waarde.

Belangrijk

In deze voorbeelden wordt een System.Collections.Generic.IEnumerable<T> gegevensbron gebruikt. Gegevensbronnen gebaseerd op System.Linq.IQueryProvider maken gebruik van System.Linq.IQueryable<T> gegevensbronnen en expressiebomen. Expressiestructuren hebben beperkingen voor de toegestane C#-syntaxis. Bovendien kan elke IQueryProvider gegevensbron, zoals EF Core , meer beperkingen opleggen. Raadpleeg de documentatie voor uw gegevensbron.

De meeste van deze methoden werken op reeksen, waarbij een reeks een object is waarvan het type de IEnumerable<T> interface of de IQueryable<T> interface implementeert. De standaardqueryoperators bieden querymogelijkheden, waaronder filteren, projectie, aggregatie, sorteren en meer. De methoden waaruit elke set bestaat, zijn respectievelijk statische leden van de Enumerable en Queryable klassen. Ze worden gedefinieerd als uitbreidingsmethoden van het type waarop ze werken.

Het onderscheid tussen IEnumerable<T> en IQueryable<T> reeksen bepaalt hoe de query tijdens runtime wordt uitgevoerd.

Voor IEnumerable<T> worden de argumenten die aan de methode zijn doorgegeven vastgelegd in het geretourneerde enumerate-object. Wanneer dat object is geïnventariseerd, wordt de logica van de queryoperator gebruikt en worden de queryresultaten geretourneerd.

De IQueryable<T>query wordt omgezet in een expressiestructuur. De expressiestructuur kan worden vertaald naar een systeemeigen query wanneer de gegevensbron de query kan optimaliseren. Bibliotheken zoals Entity Framework vertalen LINQ-query's naar systeemeigen SQL-query's die worden uitgevoerd in de database.

In het volgende codevoorbeeld ziet u hoe de standaardqueryoperators kunnen worden gebruikt om informatie over een reeks te verkrijgen.

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

Waar mogelijk gebruiken de query's in deze sectie een reeks woorden of getallen als invoerbron. Voor query's waarbij complexere relaties tussen objecten worden gebruikt, worden de volgende bronnen gebruikt die een school modelleren:

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; }
}

Elk Student heeft een cijferniveau, een primaire afdeling en een reeks scores. Een Teacher heeft ook een City eigenschap die de campus identificeert waar de docent klassen heeft. A Department heeft een naam en een verwijzing naar een Teacher persoon die als afdelingshoofd fungeert.

U vindt de gegevensset in de bronopslagplaats.

Soorten queryoperators

De standaardqueryoperators verschillen in de timing van de uitvoering, afhankelijk van of ze een singleton-waarde of een reeks waarden retourneren. Deze methoden die een singleton-waarde (zoals Average en Sum) retourneren, worden onmiddellijk uitgevoerd. Methoden die een reeks retourneren, stellen de uitvoering van de query uit en retourneren een opsommingsobject. U kunt de uitvoervolgorde van één query gebruiken als invoerreeks voor een andere query. Aanroepen naar querymethoden kunnen in één query worden gekoppeld, waardoor query's willekeurig complex kunnen worden.

Queryoperators

In een LINQ-query moet u eerst de gegevensbron opgeven. In een LINQ-query komt de from component eerst voor het introduceren van de gegevensbron (students) en de bereikvariabele (student).

//queryAllStudents is an IEnumerable<Student>
var queryAllStudents = from student in students
                        select student;

De bereikvariabele is net als de iteratievariabele in een foreach lus, behalve dat er geen werkelijke iteratie plaatsvindt in een query-expressie. Wanneer de query wordt uitgevoerd, fungeert de bereikvariabele als verwijzing naar elk opeenvolgend element in students. Omdat de compiler het type studentkan afleiden, hoeft u deze niet expliciet op te geven. U kunt meer bereikvariabelen in een let clausule introduceren. Voor meer informatie, zie let-clausule.

Notitie

Voor niet-algemene gegevensbronnen, zoals ArrayList, moet de bereikvariabele expliciet worden getypt. Zie Hoe een ArrayList opvragen met LINQ (C#) en from-clausule voor meer informatie.

Zodra u een gegevensbron hebt verkregen, kunt u een willekeurig aantal bewerkingen uitvoeren op die gegevensbron:

Syntaxistabel voor query-expressies

De volgende tabel bevat de standaardqueryoperators met equivalente queryexpressieclausules.

Methode C#-query-expressie-syntaxis
Cast Gebruik een expliciet getypte bereikvariabele:

from int i in numbers

(Zie voor meer informatie FROM-clausule.)
GroupBy group … by

– of –

group … by … into …

(Zie de groepsclausule voor meer informatie.)
GroupJoin<TOuter,TInner,TKey,TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter,TKey>, Func<TInner,TKey>, Func<TOuter,IEnumerable<TInner>, TResult>) join … in … on … equals … into …

(Zie join-clausule voor meer informatie.)
Join<TOuter,TInner,TKey,TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter,TKey>, Func<TInner,TKey>, Func<TOuter,TInner,TResult>) join … in … on … equals …

(Zie join-clausule voor meer informatie.)
OrderBy<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>) orderby

(Zie ORDER BY-instructie voor meer informatie.)
OrderByDescending<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>) orderby … descending

(Zie ORDER BY-instructie voor meer informatie.)
Select select

(Zie select-clause voor meer informatie.)
SelectMany Meerdere from clausules.

(Zie voor meer informatie FROM-clausule.)
ThenBy<TSource,TKey>(IOrderedEnumerable<TSource>, Func<TSource,TKey>) orderby …, …

(Zie ORDER BY-instructie voor meer informatie.)
ThenByDescending<TSource,TKey>(IOrderedEnumerable<TSource>, Func<TSource,TKey>) orderby …, … descending

(Zie ORDER BY-instructie voor meer informatie.)
Where where

(Zie where-clausule voor meer informatie.)

Gegevenstransformaties met LINQ

Language-Integrated Query (LINQ) gaat niet alleen over het ophalen van gegevens. Het is ook een krachtig hulpmiddel voor het transformeren van gegevens. Met behulp van een LINQ-query kunt u een bronreeks als invoer gebruiken en deze op veel manieren wijzigen om een nieuwe uitvoerreeks te maken. U kunt de volgorde zelf wijzigen zonder de elementen zelf te wijzigen door te sorteren en groeperen. Maar misschien is de krachtigste functie van LINQ-query's de mogelijkheid om nieuwe typen te maken. Met de select-component maakt u een uitvoerelement van een invoerelement. U gebruikt dit om een invoerelement te transformeren in een uitvoerelement:

  • Voeg meerdere invoerreeksen samen in één uitvoerreeks met een nieuw type.
  • Maak uitvoerreeksen waarvan de elementen uit slechts één of meerdere eigenschappen van elk element in de bronreeks bestaan.
  • Uitvoerreeksen maken waarvan de elementen bestaan uit de resultaten van bewerkingen die worden uitgevoerd op de brongegevens.
  • Maak uitvoerreeksen in een andere indeling. U kunt bijvoorbeeld gegevens van SQL-rijen of tekstbestanden transformeren in XML.

Deze transformaties kunnen op verschillende manieren in dezelfde query worden gecombineerd. Bovendien kan de uitvoervolgorde van één query worden gebruikt als invoerreeks voor een nieuwe query. In het volgende voorbeeld worden objecten in een gegevensstructuur in het geheugen omgezet in XML-elementen.


// 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);

De code produceert de volgende XML-uitvoer:

<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>

Zie XML-structuren maken in C# (LINQ naar XML) voor meer informatie.

U kunt de resultaten van één query gebruiken als de gegevensbron voor een volgende query. In dit voorbeeld ziet u hoe u de resultaten van een joinbewerking kunt ordenen. Met deze query maakt u een groepsdeelname en sorteert u vervolgens de groepen op basis van het categorieelement, dat nog steeds binnen het bereik valt. In de initialisatiefunctie van het anonieme type worden alle overeenkomende elementen uit de productenreeks door een subquery georderd.

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
*/

De equivalente query met behulp van de methodesyntaxis wordt weergegeven in de volgende code:

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}");
    }
}

Hoewel u vóór de join een orderby component met een of meer bronreeksen kunt gebruiken, wordt dit over het algemeen niet aanbevolen. Sommige LINQ-providers behouden die volgorde mogelijk niet na de join. Voor meer informatie, zie join-clausule.

Zie ook