Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Die Standardabfrageoperatoren sind die Schlüsselwörter und Methoden, die das LINQ-Muster bilden. Die C#-Sprache definiert LINQ-Abfragestichwörter , die Sie für den am häufigsten verwendeten Abfrageausdruck verwenden. Der Compiler übersetzt Ausdrücke mithilfe dieser Schlüsselwörter in die entsprechenden Methodenaufrufe. Die beiden Formen sind synonym. Andere Methoden, die Teil des System.Linq Namespaces sind, verfügen nicht über entsprechende Abfragestichwörter. In diesen Fällen müssen Sie die Methodensyntax verwenden. In diesem Abschnitt werden alle Schlüsselwörter des Abfrageoperators behandelt. Die Laufzeit- und anderen NuGet-Pakete fügen mit jeder veröffentlichten Version mehr Methoden hinzu, die für LINQ-Abfragen entwickelt wurden. Die am häufigsten verwendeten Methoden, einschließlich der Methoden, die Abfragestichwortentsprechungen aufweisen, werden in diesem Abschnitt behandelt. Eine vollständige Liste der abfragemethoden, die von .NET Runtime unterstützt werden, finden Sie in der System.Linq.Enumerable API-Dokumentation. Zusätzlich zu den hier behandelten Methoden enthält diese Klasse Methoden zum Verketten von Datenquellen, zum Berechnen eines einzelnen Werts aus einer Datenquelle, z. B. einer Summe, eines Mittelwerts oder eines anderen Werts.
Von Bedeutung
In diesen Beispielen wird eine System.Collections.Generic.IEnumerable<T>-Datenquelle verwendet. Datenquellen, die auf System.Linq.IQueryProvider basieren, verwenden System.Linq.IQueryable<T>-Datenquellen und Ausdrucksbaumstrukturen. Ausdrucksbaumstrukturen haben Einschränkungen für die zulässige C#-Syntax. Darüber hinaus kann jede IQueryProvider
-Datenquelle, z. B. EF Core, weitere Einschränkungen erzwingen. Konsultieren Sie die Dokumentation für Ihre Datenquelle.
Die meisten dieser Methoden werden auf Sequenzen ausgeführt, wobei es sich bei einer Sequenz um ein Objekt handelt, dessen Typ die IEnumerable<T> Schnittstelle oder schnittstelle IQueryable<T> implementiert. Die Standardabfrageoperatoren bieten Abfragefunktionen, einschließlich Filterung, Projektion, Aggregation, Sortierung und mehr. Die Methoden, aus denen die einzelnen Gruppen bestehen, sind statische Mitglieder der Enumerable bzw. Queryable Klassen. Sie werden als Erweiterungsmethoden des Typs definiert, auf dem sie arbeiten.
Die Unterscheidung zwischen IEnumerable<T> und IQueryable<T> Sequenz bestimmt, wie die Abfrage zur Laufzeit ausgeführt wird.
Für IEnumerable<T>
erfasst das zurückgegebene aufzählbare Objekt die Argumente, die an die Methode übergeben wurden. Wenn dieses Objekt aufgezählt wird, wird die Logik des Abfrageoperators verwendet, und die Abfrageergebnisse werden zurückgegeben.
Für IQueryable<T>
wird die Abfrage in einen expression tree übersetzt. Der Ausdrucksbaum kann in eine systeminterne Abfrage übersetzt werden, wenn die Datenquelle die Abfrage optimieren kann. Bibliotheken wie Entity Framework übersetzen LINQ-Abfragen in systemeigene SQL-Abfragen, die in der Datenbank ausgeführt werden.
Im folgenden Codebeispiel wird veranschaulicht, wie die Standardabfrageoperatoren verwendet werden können, um Informationen zu einer Sequenz abzurufen.
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
Wenn möglich, verwenden die Abfragen in diesem Abschnitt eine Abfolge von Wörtern oder Zahlen als Eingabequelle. Bei Abfragen, bei denen kompliziertere Beziehungen zwischen Objekten verwendet werden, werden die folgenden Quellen verwendet, die eine Schule modellieren:
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; }
}
Allen Student
sind eine Klassenstufe, ein primärer Fachbereich und mehrere Bewertungen zugeordnet.
Teacher
verfügen auch über eine City
-Eigenschaft, die den Campus identifiziert, auf dem die Lehrkraft unterrichtet. Eine Department
hat einen Namen und einen Verweis auf eine Teacher
, die den Fachbereich leitet.
Sie finden das Dataset im Quell-Repository.
Abfrageoperatorentypen
Die Standardabfrageoperatoren unterscheiden sich im Zeitpunkt ihrer Ausführung, je nachdem, ob sie einen einzelnen Wert oder eine Folge von Werten zurückgeben. Diese Methoden, die einen Singletonwert (z. B. Average und Sum) zurückgeben, werden sofort ausgeführt. Methoden, die eine Sequenz zurückgeben, verzögern die Abfrageausführung und geben ein aufzählbares Objekt zurück. Sie können die Ausgabesequenz einer Abfrage als Eingabesequenz für eine andere Abfrage verwenden. Aufrufe von Abfragemethoden können in einer Abfrage verkettet werden, wodurch Abfragen beliebig komplex werden können.
Abfrageoperatoren
In einer LINQ-Abfrage besteht der erste Schritt darin, die Datenquelle anzugeben. In einer LINQ-Abfrage kommt die from
Klausel zuerst, um die Datenquelle (students
) und die Bereichsvariable (student
) einzuführen.
//queryAllStudents is an IEnumerable<Student>
var queryAllStudents = from student in students
select student;
Die Bereichsvariable ist wie die Iterationsvariable in einer foreach
Schleife, mit der Ausnahme, dass keine tatsächliche Iteration in einem Abfrageausdruck auftritt. Wenn die Abfrage ausgeführt wird, dient die Bereichsvariable als Verweis auf jedes aufeinander folgende Element in students
. Da der Compiler den Typ von student
ableiten kann, müssen Sie ihn nicht explizit angeben. Sie können weitere Bereichsvariablen in einer let
Klausel einführen. Weitere Informationen finden Sie unter let-Klausel.
Hinweis
Bei nicht generischen Datenquellen wie ArrayListz. B. muss die Bereichsvariable explizit eingegeben werden. Weitere Informationen finden Sie unter How to query an ArrayList with LINQ (C#) und from clause.
Nachdem Sie eine Datenquelle erhalten haben, können Sie eine beliebige Anzahl von Vorgängen für diese Datenquelle ausführen:
-
Filtern sie Daten mithilfe des Schlüsselworts
where
. -
Ordnen Sie die Daten unter Verwendung der Schlüsselwörter
orderby
und optionaldescending
. -
Gruppieren Sie Daten mithilfe der
group
Schlüsselwörter und optionalinto
. -
Verknüpfen sie Daten mithilfe des Schlüsselworts
join
. -
Projektdaten mit dem
select
Schlüsselwort.
Abfrageausdrucks-Syntax-Tabelle
In der folgenden Tabelle sind die Standardabfrageoperatoren aufgeführt, die über entsprechende Abfrageausdrucksklauseln verfügen.
Methode | Syntax des C#-Abfrageausdrucks |
---|---|
Cast | Verwenden Sie eine explizit eingegebene Bereichsvariable:from int i in numbers (Weitere Informationen finden Sie unter from-Klausel.) |
GroupBy | group … by -oder- group … by … into … (Weitere Informationen finden Sie unter "group clause".) |
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 … (Weitere Informationen finden Sie unter join-Klausel.) |
Join<TOuter,TInner,TKey,TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter,TKey>, Func<TInner,TKey>, Func<TOuter,TInner,TResult>) | join … in … on … equals … (Weitere Informationen finden Sie unter join-Klausel.) |
OrderBy<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>) | orderby (Weitere Informationen finden Sie unter orderby-Klausel.) |
OrderByDescending<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>) | orderby … descending (Weitere Informationen finden Sie unter orderby-Klausel.) |
Select | select (Weitere Informationen finden Sie unter Select-Klausel.) |
SelectMany | Mehrere from Klauseln.(Weitere Informationen finden Sie unter from-Klausel.) |
ThenBy<TSource,TKey>(IOrderedEnumerable<TSource>, Func<TSource,TKey>) | orderby …, … (Weitere Informationen finden Sie unter orderby-Klausel.) |
ThenByDescending<TSource,TKey>(IOrderedEnumerable<TSource>, Func<TSource,TKey>) | orderby …, … descending (Weitere Informationen finden Sie unter orderby-Klausel.) |
Where | where (Weitere Informationen finden Sie unter where clause.) |
Datentransformationen mit LINQ
Bei der sprachintegrierten Abfrage (LINQ) geht es nicht nur um das Abrufen von Daten. Es ist auch ein leistungsfähiges Tool zum Transformieren von Daten. Mithilfe einer LINQ-Abfrage können Sie eine Quellsequenz als Eingabe verwenden und auf vielfältige Weise ändern, um eine neue Ausgabesequenz zu erstellen. Sie können die Sequenz selbst ändern, ohne die Elemente selbst durch Sortieren und Gruppieren zu ändern. Vielleicht ist aber das leistungsstärkste Feature von LINQ-Abfragen die Möglichkeit, neue Typen zu erstellen. Die Auswahlklausel erstellt ein Ausgabeelement aus einem Eingabeelement. Sie verwenden es, um ein Eingabeelement in ein Ausgabeelement zu transformieren:
- Führen Sie mehrere Eingabesequenzen in einer einzelnen Ausgabesequenz mit einem neuen Typ zusammen.
- Erstellen Sie Ausgabesequenzen, deren Elemente aus nur einer oder mehreren Eigenschaften jedes Elements in der Quellsequenz bestehen.
- Erstellen Sie Ausgabesequenzen, deren Elemente aus den Ergebnissen von Vorgängen bestehen, die für die Quelldaten ausgeführt werden.
- Erstellen Sie Ausgabesequenzen in einem anderen Format. Sie können z. B. Daten aus SQL-Zeilen oder Textdateien in XML transformieren.
Diese Transformationen können auf unterschiedliche Weise in derselben Abfrage kombiniert werden. Darüber hinaus kann die Ausgabesequenz einer Abfrage als Eingabesequenz für eine neue Abfrage verwendet werden. Im folgenden Beispiel werden Objekte in einer Speicherdatenstruktur in XML-Elemente umgewandelt.
// 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);
Der Code erzeugt die folgende XML-Ausgabe:
<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>
Weitere Informationen finden Sie unter Creating XML Trees in C# (LINQ to XML).
Sie können die Ergebnisse einer Abfrage als Datenquelle für eine nachfolgende Abfrage verwenden. In diesem Beispiel wird gezeigt, wie die Ergebnisse eines Verknüpfungsvorgangs sortiert werden. Diese Abfrage erstellt eine Gruppenverknüpfung und sortiert die Gruppen anschließend anhand des Elements der Kategorie, das sich noch im Geltungsbereich befindet. Innerhalb des anonymen Typinitialisierers sortiert eine Unterabfrage alle übereinstimmenden Elemente aus der Produktsequenz.
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
*/
Die entsprechende Abfrage mit Methodensyntax ist im folgenden Code dargestellt:
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}");
}
}
Obwohl Sie eine orderby
Klausel mit einer oder mehreren Quellsequenzen vor der Verknüpfung verwenden können, wird dies im Allgemeinen nicht empfohlen. Einige LINQ-Anbieter behalten diese Sortierung nach dem Beitritt möglicherweise nicht bei. Weitere Informationen finden Sie unter join-Klausel.