LINQ
# LINQ

LINQ (Abkürzung für Language Integrated Query; Aussprache Link) ist ein programmtechnisches Verfahren von Microsoft zum Zugriff auf Daten. LINQ wurde federführend von Erik Meijer entwickelt und erschien erstmals mit .NET Framework 3.5.

## Ziel von LINQ

Die Daten, auf die ein Programm zugreift, stammen aus unterschiedlichen Quellen. Dazu gehören

* interne Quellen wie Felder sowie Objekt-Listen und -Hierarchien;
* externe Quellen wie XML-Dokumente, Datenbanktabellen, Textdateien, Excel-Dateien, E-Mail-Nachrichten, SharePoint-Listen und viele andere.

Jede dieser Datenquellen hat ihre eigenen Zugriffsmethoden. Dies führt dazu, dass sich der Programmierer in jedem Einzelfall mit den Details der jeweiligen Methode beschäftigen muss. Ferner muss jedes Mal das Programm geändert werden, wenn Daten aus einer Quelle in eine Quelle eines anderen Typs verschoben werden.

LINQ versucht dieses Problem zu beseitigen, indem es innerhalb des .Net-Frameworks eine einheitliche Methode für jeglichen Datenzugriff zur Verfügung stellt. Die Syntax der Abfragen in LINQ ist ähnlich der von SQL. Im Unterschied zu SQL stellt LINQ jedoch auch Sprachelemente zur Verfügung, die zum Zugriff auf hierarchische und Netzwerk-Strukturen geeignet sind, indem sie die dort vorhandenen Beziehungen ausnutzen.

## Arbeitsweise

LINQ ist eine Sammlung von Erweiterungsmethoden, die auf Monaden operieren. Zudem gibt es in einigen .NET-Sprachen wie C#, VB.NET und F# eigene Schlüsselwörter für eine vorbestimmte Menge an LINQ-Methoden. Monaden werden in .NET als generische Klassen oder Interfaces mit einzelnem Typargument (z. B. IEnumerable<T>, IObservable<T>) abgebildet.

LINQ-Anweisungen sind unmittelbar als Quelltext in .NET-Programme eingebettet. Somit kann der Code durch den Compiler auf Fehler geprüft werden. Andere Verfahren wie ADO und ODBC hingegen verwenden Abfragestrings. Diese können erst zur Laufzeit interpretiert werden; dann wirken Fehler gravierender und sind schwieriger zu analysieren.

Innerhalb des Quellprogramms in C# oder VB.NET präsentiert LINQ die Abfrage-Ergebnisse als streng typisierte Aufzählungen. Somit gewährleistet es Typsicherheit bereits zur Übersetzungszeit.

Sogenannte LINQ-Anbieter (englisch LINQ provider) übersetzen die LINQ-Anweisungen in die speziellen Zugriffsmethoden der jeweiligen Datenquelle. Innerhalb der .NET-Plattform stehen unter anderem folgende Anbieter zur Verfügung:

* LINQ to Objects zum Zugriff auf Objektlisten und -Hierarchien im Arbeitsspeicher
* LINQ to SQL zur Abfrage und Bearbeitung von Daten in MS-SQL-Datenbanken
* LINQ to Entities zur Abfrage und Bearbeitung von Daten im relationalen Modell von ADO.NET;
* LINQ to XML zum Zugriff auf XML-Inhalte
* LINQ to DataSet zum Zugriff auf ADO.NET-Datensammlungen und -Tabellen
* LINQ to SharePoint zum Zugriff auf SharePoint-Daten.

## Wichtige Konzepte

Die Beispiele sind, sofern nicht anders angegeben, in C#.

### Verzögerte Auswertung

LINQ-Ausdrücke werden nicht bei ihrer Definition ausgeführt, sondern wenn der Wert abgefragt wird. Dies wird als Lazy Evaluation (auch deferred evaluation) bezeichnet. Dadurch kann die Abfrage auch mehrfach verwendet werden.

Die verzögerte Auswertung kann auf verschiedene Weisen implementiert werden. Beispielsweise verwendet LINQ to Objects Delegates, während LINQ to SQL stattdessen das IQueryable<T>-Interface implementiert. Um die Veränderung des Ergebnisses der Abfrage zu verhindern, muss diese in einen anderen Typ konvertiert (englisch: conversion) werden. Hierzu dienen Konvertierungsmethoden wie AsEnumerable, ToArray, ToList, ToDictionary, ToLookup usw.

Falls die LINQ-Abfrage eine Funktion aufruft, die eine Ausnahmebehandlung erfordert, so muss der Try-Catch-Block die Verwendung der Abfrage umklammern und nicht deren Erstellung.

### Auflösung von Erweiterungsmethoden

LINQ-Funktionen werden als Erweiterungsmethoden (englisch: extension method) implementiert. Gegeben sei eine Aufzählung von Elementen eines Typs:

Über eine Erweiterungsmethode kann nun etwa die Where-Methode zur Filterung nach beliebigen Kriterien (re-)implementiert werden:

Bestimmte .NET-Sprachen besitzen eigene Schlüsselwörter, um die Methoden aufzurufen:

Diese Schlüsselwörter werden vom Compiler in die entsprechenden Methodenaufrufe aufgelöst:

Da es sich um Erweiterungsmethoden handelt, muss der Compiler die Methodenaufrufe in einen Aufruf der Methoden der passenden Erweiterungsklasse auflösen:

## Wichtige Operatoren

### From

From definiert die Datenquelle einer Abfrage (query) oder Unterabfrage (subquery), sowie eine Bereichsvariable (range variable) die ein einzelnes Element der Datenquelle (data source) repräsentiert.

Abfragen können mehrere from-Operationen besitzen, um Joins von mehreren Datenquellen zu ermöglichen. Hierbei gilt zu beachten, dass die Join-Bedingung bei mehreren from-Operationen durch die Datenstruktur definiert wird und sich vom Konzept eines Joins in Relationalen Datenbanken unterscheidet.

oder kürzer:

### Where

Where definiert einen Filter auf den auszuwählenden Daten.

### Select

Select definiert eine Projektion bzw. die Form des Ergebnisses der LINQ-Abfrage.

Häufig wird eine Teilmenge von Eigenschaften projiziert, wobei dafür anonyme Klassen verwendet werden (d. h. new { …, … }) bzw. ab C# 7.0 auch Wertetupel ((…, …)).

### Group

Group wird verwendet um Elemente nach einem bestimmten Schlüssel zu gruppieren:

Als Schlüssel kann auch ein anonymer Typ verwendet werden, der sich aus mehreren Schlüsseln zusammensetzt:

### Into

Into kann verwendet werden um das Ergebnis einer select, group oder join-Operation in einer temporären Variable zu speichern.

### OrderBy und ThenBy

OrderBy und ThenBy wird verwendet um eine Liste von Elementen in aufsteigender Reihenfolge zu sortieren.

Mit Hilfe von OrderByDescending und ThenByDescending wird die Liste in absteigender Reihenfolge sortiert:

### Reverse

Reverse kehrt die Reihenfolge der Elemente um.

### Join

Join ermöglicht Inner Joins, Group Joins und Left Outer Joins.

**Inner Join**


    Ein Inner Join bildet die äußere Datenquelle auf die innere Datenquelle ab und liefert ein „flaches“ Ergebnis zurück. Elemente der äußeren Datenquelle, zu denen kein passendes Element der inneren Datenquelle existiert, werden verworfen.

**Group Join**


    Ein Group Join erzeugt eine hierarchische Ergebnismenge. Hierbei werden die Elemente der inneren Datenquelle mit den entsprechenden Elementen der äußeren Datenquelle gruppiert. Elemente zu denen kein entsprechendes Element der äußeren Datenquelle existiert, werden mit einem leeren Array verbunden.
    Ein Group Join ist in SQL nicht abbildbar, da SQL keine hierarchische Ergebnismenge zulässt. VB.NET besitzt mit Group Join ein eigenes Schlüsselwort.

**Left Outer Join**


    Ein Left Outer Join bildet die äußere Datenquelle auf die innere Datenquelle ab und liefert ein „flaches“ Ergebnis zurück. Elemente der äußeren Datenquelle, zu denen kein passendes Element der inneren Datenquelle existiert, werden mit einem Standardwert versehen. Um den Standardwert zu definieren, wird die DefaultIfEmpty-Erweiterungsmethode verwendet, die leere Aufzählungen in eine einelementige Aufzählung mit einem Standardwert wandelt:

### Let

Let ermöglicht es das Ergebnis einer Teilabfrage in einer Variable zu speichern, um diese später in der Abfrage verwenden zu können.

### Any

Any wird verwendet, um festzustellen, ob eine Sequenz leer ist oder ein bestimmtes Prädikat enthält.

### Contains

Contains wird verwendet um festzustellen, ob ein bestimmter Wert in einer Sequenz enthalten ist.

### Skip und Take

Skip wird verwendet, um eine bestimmte Anzahl von Elementen einer Sequenz zu überspringen. Take wird verwendet, um eine maximale Anzahl von Elementen einer Sequenz auszuwählen.

Zusätzlich sind die Erweiterungsmethoden SkipWhile und TakeWhile definiert, für die in VB.NET eigene Schlüsselwörter definiert sind. Diese Methoden erlauben die Verwendung eines Prädikats, welches definiert welche Elemente übersprungen bzw. ausgewählt werden.

### Distinct

Distinct wird verwendet, um eindeutige Elemente einer Sequenz auszuwählen.

### Union, Intersect und Except

Für eine Liste von Elementen können die Mengenoperatoren Union, Intersect und Except eingesetzt werden:

### Aggregate

Aggregate wird verwendet, um eine Aggregat-Funktion auf eine Datenquelle anzuwenden.

Zudem sind wichtige Aggregat-Funktionen vordefiniert. Vordefinierte Aggregat-Funktionen sind etwa Count, LongCount, Sum, Min, Max und Average.

### Zip

Zip kombiniert zwei Sequenzen miteinander, bis eine Sequenz zu Ende ist.

### Concat

Concat hängt an eine Sequenz eine weitere Sequenz gleichen Typs.

### SequenceEqual

SequenceEqual prüft, ob zwei Sequenzen die gleiche Länge aufweisen und ob die Elemente an der jeweiligen Position der entsprechenden Sequenzen gleich sind. Zum Vergleich wird entweder das IEqualityComparer<T> Interface, die Equals-Methode von TSource oder die GetHashCode-Methode abgefragt.

### SelectMany

SelectMany wird im Wesentlichen dazu eingesetzt, eine Hierarchie abzuflachen. SelectMany funktioniert hierbei wie der Bind-Operator >>=, auch shovel (Schaufel) genannt, in Haskell.

Ein typischer Anwendungsfall für die Abflachung einer Hierarchie ist es, alle Dateien in einem Verzeichnis sowie den Unterverzeichnissen des Verzeichnisses aufzulisten.

### Skalar-Selektoren

LINQ definiert verschiedene Selektoren für skalare Ergebnisse:

skalare LINQ Selektoren :

| Methode | Ergebnis |
| - | - |
| ElementAt(n) | Gibt das n-te Element zurück, falls die Anfrage ein oder mehrere Ergebnisse liefert. Wirft eine Exception, falls weniger als n Ergebnisse zurückgeliefert werden. |
| ElementAtOrDefault(n) | Gibt das n-te Element zurück, falls die Anfrage ein oder mehrere Ergebnisse liefert. Gibt den Standardwert zurück, falls weniger als n Ergebnisse zurückgeliefert werden. |
| First | Gibt das erste Element zurück, falls die Anfrage ein oder mehrere Ergebnisse liefert. Wirft eine Exception, falls keine Ergebnisse zurückgeliefert werden. |
| FirstOrDefault | Gibt das erste Element zurück, falls die Anfrage ein oder mehrere Ergebnisse liefert. Gibt den Standardwert zurück, falls keine Ergebnisse zurückgeliefert werden. |
| Last | Gibt das letzte Element zurück, falls die Anfrage ein oder mehrere Ergebnisse liefert. Wirft eine Exception, falls keine Ergebnisse zurückgeliefert werden. |
| LastOrDefault | Gibt das letzte Element zurück, falls die Anfrage ein oder mehrere Ergebnisse liefert. Gibt den Standardwert zurück, falls keine Ergebnisse zurückgeliefert werden. |
| Single | Gibt das eine Element zurück, welches die Anfrage liefert. Wirft eine Exception, falls keine oder mehrere Ergebnisse zurückgeliefert werden. |
| SingleOrDefault | Gibt das eine Element zurück, welches die Anfrage liefert. Gibt den Standardwert zurück, falls keine Ergebnisse geliefert werden. Wirft eine Exception, falls mehrere Ergebnisse zurückgeliefert werden. |

## Erweitern von LINQ

### Definition eigener Monaden

LINQ kann auf beliebige Monaden angewendet werden. Monaden sind hierbei Adapter (englisch: wrapper) für einen bestimmten Typ. Vordefinierte Monaden sind z. B. IEnumerable<T>, IList<T>, Nullable<T> und Task<T>.

Jedoch können auch eigene Monaden wie z. B. IRepository<T> oder IHandler<T> erstellt werden, um die Funktionalität von LINQ zu erweitern. Hierfür müssen passende Erweiterungsmethoden definiert werden. Die Verwendung von Monaden dient hierbei dazu die Menge an Boilerplate-Code zu reduzieren.

**Identität**

Die einfachste Monade ist die Identität, welche in .NET üblicherweise als Identity<T> bezeichnet wird:

Für diese Klasse lassen sich nun die folgenden Erweiterungsmethoden erstellen:

Diese Monade kann nun als Lambda-Ausdruck (als Arbitrary Composition) verwendet werden:

Um die Monade in LINQ verwenden zu können, muss eine SelectMany-Erweiterungsmethode implementiert werden. Diese ist lediglich ein Alias für Bind. Es besteht daher die Möglichkeit

* die Bind-Methode umzubenennen bzw. zu kapseln
* die Bind-Methode mit Funktionskomposition zu erstellen und umzubenennen bzw. zu kapseln
* beides:

Die Monade kann nun mit Hilfe von LINQ-Schlüsselwörtern verarbeitet werden:

**Maybe**

Eine weitere einfache Monade ist Maybe<T>, welche ähnlich funktioniert wie die Nullable<T>-Struktur. Die Maybe-Monade lässt sich hierbei auf verschiedene Arten implementieren:

**Maybe**

**Variante 1**


    HasValue-Eigenschaft bestimmt ob Maybe Nothing (d. h. leer) ist.

Definition der Monade:

Definition der Unit-Methode:

Definition der Bind-Methode:

Verwendung:

**Maybe**

**Variante 2**


    konkreter Typ bestimmt ob Nothing oder Something

Definition der Monade:

Definition der Unit-Methode:

Definition der Bind-Methode:

Verwendung:

### Definieren eigener Operatoren

Operatoren in LINQ lassen sich erweitern, indem eine passende Erweiterungsmethode bereitgestellt wird. Hierbei können auch Standardoperatoren überschrieben werden.

**Beispiel 1**


    Rückgabe von Personen, die zu einem bestimmten Datum Geburtstag haben.
    Aufrufen der neuen Erweiterungsmethode

**Beispiel 2**


    Definition einer Methode, welche die Menge der ältesten Personen einer Liste zurückliefert. Es soll zudem eine Delegate-Funktion angegeben werden können, um etwa verstorbene Personen auszufiltern.
    Aufrufen der neuen Erweiterungsmethode

### Implementierung eigener LINQ-Provider

Das schreiben eigener LINQ-Provider bietet sich an, wenn ein Service aufgerufen werden soll, welches eine bestimmte Syntax (SQL, XML etc.) verlangt. Um dies zu ermöglichen muss das IQueryable-Interface implementiert werden. Über dieses Interface kann der LINQ-Ausdrucksbaum analysiert und in das passende Zielformat umgewandelt werden.

## Reactive Extensions

Die Reactive Extensions (kurz: Rx) sind eine Erweiterung von LINQ, welche auf IObservable<T> statt IEnumerable<T> arbeitet. Es handelt sich dabei um eine Implementierung des Beobachter-Entwurfsmusters.

Vergleich von Rx mit LINQ :

| Operationsart gemäß dem CQS-Prinzip | Kommando (Command) | Abfrage (Query) |
| - | - | - |
| Definition | hat Seiteneffekte | liefert Daten zurück |
| Muster | Observer | Iterator |
| Implementierung im .NET Framework | Rx (IObservable) | LINQ (IEnumerable) |
| Muster | Pipes und Filter | Map/Reduce |
| Asynchronität | Alle Kommandos können asynchron implementiert werden. | Ergebnisse werden mit Hilfe von asynchronen Benachrichtigungen oder Tokens für Status-Polling zurückgeliefert. |

Die Rx ermöglichen eine Ereignisgesteuerte Programmierung ohne Rückruffunktionen. Gelegentlich werden die Rx dabei als „LINQ to Events“ beschrieben.

## Beispiele

### LINQ to DataSet

Folgendes Beispiel zeigt die Abfrage einer Tabelle mit Linq. Vorausgesetzt wird eine bestehende Access-Datenbank unter dem Pfad: C:\database.mdb mit einer Tabelle Products, die die Felder ID, Name und EanCode enthält.

Die Tabelle wird als Klasse nachgebildet und mittels Attributen mit Metadaten versehen, die das Mapping auf die Datenbank beschreiben.

Dazu muss in der Projektmappe unter References ein Verweis auf die System.Data.Linq.Dll hinzugefügt werden.

Nun kann man die Tabelle abfragen. In folgendem Beispiel werden alle Produkte aufgelistet, deren Produktbezeichnung mit einem A beginnt. Die Produkte werden nach ihrer ID sortiert.

Alternativ können auch sogenannte Erweiterungsmethoden mit Lambda-Ausdrücken verwendet werden. In solche werden LINQ-Abfragen auch vom Compiler übersetzt.

Mit der Funktion Single kann ein einzelner Datensatz ermittelt werden. Folgendes Beispiel ermittelt den Datensatz mit der ID 1.

Falls aber die Abfrage mehrere Datensätze ermittelt, wird eine InvalidOperationException geworfen.

### LINQ to XML

Nachstehend ein Beispiel das zeigt, wie LINQ verwendet werden kann, um Informationen aus einer XML-Datei auszulesen. Als XML-Datei dient folgende XML-Beispieldatei.

Wollte man beispielsweise die Artikelnummern (PartNumber) aller Einträge vom Typ <Item> auslesen, könnte man folgenden C# Code verwenden.

Eine andere Möglichkeit, unter Zuhilfenahme einer bedingten Abfrage, wäre alle Artikel auszuwählen, deren Wert mehr als 100 Dollar beträgt. Zusätzlich könnte man das Resultat der Abfrage mittels orderby nach den Artikelnummern, sortieren.

### LINQ mit Rx

Viele Erweiterungsmethoden von LINQ sind auch in Rx vorhanden. Im folgenden Beispiel wird eine Filterung mit Hilfe der Where-Klausel durchgeführt:

Die Erweiterungsmethoden von Rx sind zwar auf eine andere Monade definiert (IObservable<T> statt IEnumerable<T>), da die Bezeichnung der Erweiterungsmethoden jedoch identisch ist, kann auch die Comprehension Syntax von LINQ eingesetzt werden. Eine weitere Möglichkeit ist daher:

