Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Vanliga frågeoperatorer är nyckelord och metoder som utgör LINQ-mönstret. C#-språket definierar LINQ-frågenyckelord som du använder för det vanligaste frågeuttrycket. Kompilatorn översätter uttryck med hjälp av dessa nyckelord till motsvarande metodanrop. De två formerna är synonyma. Andra metoder som ingår i System.Linq namnområdet har inte motsvarande frågenyckelord. I sådana fall måste du använda metodsyntaxen. Det här avsnittet beskriver alla nyckelord för frågeoperatorn. Körtiden och andra NuGet-paket lägger vid varje släpp till fler metoder som är utformade för att fungera med LINQ-frågor. De vanligaste metoderna, inklusive de som har frågenyckelordsekvivalenter, beskrivs i det här avsnittet. En fullständig lista över frågemetoder som stöds av .NET Runtime finns i API-dokumentationen System.Linq.Enumerable . Förutom de metoder som beskrivs här innehåller den här klassen metoder för att sammanfoga datakällor, beräkna ett enda värde från en datakälla, till exempel en summa, ett genomsnitt eller ett annat värde.
Viktigt!
Dessa exempel använder en System.Collections.Generic.IEnumerable<T> datakälla. Datakällor baserade på System.Linq.IQueryProvider använder System.Linq.IQueryable<T> datakällor och uttrycksträd. Uttrycksträd har begränsningar för den tillåtna C#-syntaxen. Dessutom kan varje IQueryProvider datakälla, till exempel EF Core , införa fler begränsningar. Kontrollera dokumentationen för din datakälla.
De flesta av dessa metoder fungerar på sekvenser, där en sekvens är ett objekt vars typ implementerar IEnumerable<T> gränssnittet eller IQueryable<T> gränssnittet. Vanliga frågeoperatorer tillhandahåller frågefunktioner som filtrering, projektion, aggregering, sortering med mera. Metoderna som utgör varje uppsättning är statiska medlemmar i Enumerable klasserna respektive Queryable . De definieras som tilläggsmetoder av den typ som de arbetar med.
Skillnaden mellan IEnumerable<T>- och IQueryable<T>-sekvenser avgör hur förfrågan utförs vid körning.
För IEnumerable<T>samlar det returnerade uppräkningsbara objektet in argumenten som skickades till metoden. När objektet räknas upp används logiken för frågeoperatorn och frågeresultatet returneras.
För IQueryable<T>översätts frågan till ett uttrycksträd. Uttrycksträdet kan översättas till en intern fråga när datakällan kan optimera frågan. Bibliotek som Entity Framework översätter LINQ-frågor till interna SQL-frågor som körs i databasen.
Följande kodexempel visar hur standardfrågeoperatorerna kan användas för att hämta information om en sekvens.
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
När det är möjligt använder frågorna i det här avsnittet en sekvens med ord eller siffror som indatakälla. För frågor där mer komplicerade relationer mellan objekt används används följande källor som modellerar en skola:
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; }
}
Varje Student har en betygsnivå, en primär avdelning och en serie resultat. En Teacher har också en City egenskap som identifierar det campus där läraren har klasser. A Department har ett namn och en referens till en Teacher som fungerar som avdelningschef.
Du hittar datauppsättningen i källdatabasen.
Typer av frågeoperatorer
Standardfrågeoperatorerna skiljer sig åt i tidpunkten för körningen, beroende på om de returnerar ett singleton-värde eller en sekvens med värden. De metoder som returnerar ett singleton-värde (till exempel Average och Sum) körs omedelbart. Metoder som returnerar en sekvens skjuter upp frågekörningen och returnerar ett uppräkningsbart objekt. Du kan använda utdatasekvensen för en fråga som indatasekvens till en annan fråga. Anrop till frågemetoder kan länkas samman i en fråga, vilket gör det möjligt för frågor att bli godtyckligt komplexa.
Frågeoperatorer
I en LINQ-fråga är det första steget att ange datakällan. I en LINQ-fråga from kommer satsen först för att introducera datakällan (students) och intervallvariabeln (student).
//queryAllStudents is an IEnumerable<Student>
var queryAllStudents = from student in students
                        select student;
Intervallvariabeln liknar iterationsvariabeln i en foreach loop förutom att ingen faktisk iteration sker i ett frågeuttryck. När frågan körs fungerar intervallvariabeln som en referens till varje efterföljande element i students. Eftersom kompilatorn kan härleda typen av studentbehöver du inte ange den explicit. Du kan introducera fler intervallvariabler i en let sats. För mer information, se let-satsen.
Anmärkning
För icke-generiska datakällor som ArrayList, måste intervallvariabeln uttryckligen skrivas. För mer information, se Hur man gör frågor mot en ArrayList med LINQ (C#) och from-klausul.
När du har hämtat en datakälla kan du utföra valfritt antal åtgärder på datakällan:
- 
              Filtrera data med nyckelordet where.
- 
              Sortera data med hjälp av orderbyoch valfrittdescendingnyckelord.
- 
              Gruppera data med nyckelorden groupoch eventuelltinto.
- 
              Sammanfoga data med nyckelordet join.
- 
              Projektdata med nyckelordet select.
Syntaxtabell för frågeuttryck
I följande tabell visas de standardfrågasoperatorer som har motsvarande frågeuttryckssatser.
Datatransformeringar med LINQ
Language-Integrated Query (LINQ) handlar inte bara om att hämta data. Det är också ett kraftfullt verktyg för att transformera data. Genom att använda en LINQ-fråga kan du använda en källsekvens som indata och ändra den på många sätt för att skapa en ny utdatasekvens. Du kan ändra själva sekvensen utan att ändra själva elementen genom att sortera och gruppera. Men den kanske mest kraftfulla funktionen i LINQ-frågor är möjligheten att skapa nya typer. Select-satsen skapar ett utdataelement från ett indataelement. Du använder det för att omvandla ett indataelement till ett utdataelement:
- Sammanfoga flera indatasekvenser till en enda utdatasekvens som har en ny typ.
- Skapa utdatasekvenser vars element endast består av en eller flera egenskaper för varje element i källsekvensen.
- Skapa utdatasekvenser vars element består av resultatet av åtgärder som utförs på källdata.
- Skapa utdatasekvenser i ett annat format. Du kan till exempel omvandla data från SQL-rader eller textfiler till XML.
Dessa transformeringar kan kombineras på olika sätt i samma fråga. Dessutom kan utdatasekvensen för en fråga användas som indatasekvens för en ny fråga. I följande exempel transformeras objekt i en minnesintern datastruktur till XML-element.
// 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);
Koden genererar följande XML-utdata:
<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>
Mer information finns i Skapa XML-träd i C# (LINQ till XML).
Du kan använda resultatet av en fråga som datakälla för en efterföljande fråga. Det här exemplet visar hur du beställer resultatet av en kopplingsåtgärd. Den här frågan skapar en gruppkoppling och sorterar sedan grupperna baserat på elementet department , som fortfarande finns i omfånget. I den anonyma typinitieraren beställer en underfråga alla matchande element från sekvensen students .
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
*/
Motsvarande fråga med metodsyntax visas i följande kod:
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}");
    }
}
Även om du kan använda en orderby sats med en eller flera av källsekvenserna före kopplingen rekommenderar vi vanligtvis inte det. Vissa LINQ-leverantörer kanske inte bevarar beställningen efter kopplingen. Mer information finns i kopplingssatsen.