Anstatt für die relationalen Datenbanken SQL oder für XML XQuery zu erlernen, kann ein Entwickler mit LINQ einheitlich auf die meisten Datenquellen zuzugreifen. Das funktioniert auch mit Listen oder ADO.NET-Datasets.
LINQ-Abfrage
Die LINQ-Abfrage besteht aus 3 Teilen.1. Die Datenquelle muss bekannt sein/gemacht werden.
2. Die Abfrage wird erstellt.
3. Die Abfrage wird ausgeführt.
Hier ein kleines Beispiel mit C#:
Zuerst wird eine neue Klasse "Person" definiert mit welcher wir arbeiten werden:
class Person
{
public Person(string Vorname, string Nachname, string Wohnort)
{
this.Vorname = Vorname;
this.Nachname = Nachname;
this.Wohnort = Wohnort;
}
public string Vorname
{
set;
get;
}
public string Nachname
{
set;
get;
}
public string Wohnort
{
set;
get;
}
}
Nun wird wie bereits erwähnt eine Datenquelle definiert.
Wir erstellen hier eine List mit der Klasse Person als Objekte und fügen ihr gleich einige Personen hinzu:
List
datenquelle.Add(new Person("Till", "Schnegg", "Wabern"));
datenquelle.Add(new Person("Max", "Muster", "Zürich"));
datenquelle.Add(new Person("Lorenz", "Müller", "Zürich"));
datenquelle.Add(new Person("C", "Sharp", "Bern"));
Dann wird die Abfrage definiert. Sie besteht aus mindestens 2 Teilen.
Der 1. Teil ist die from-Klausel, welche die Datenquelle angibt.
Der 2. Teil ist die select-Klausel, welche den Typ der zurückgegebenen Elemente angibt.
Ich werde hier gleich noch 2 weitere Teile zeigen.
Die where-Klausel welche zum filtern der Daten verwendet werden kann und die orderby-Klausel mit welcher man die Daten sortieren kann.
Die Abfrage muss noch in eine Variable gespeichert werden, was dann so aussieht:
var abfrage = from person in datenquelle
where person.Wohnort == "Zürich"
orderby person.Vorname
select person;
Hier werden nun alle "Person"-Objekte in der Liste datenquelle, welche als Wohnort "Zürich" eingetragen haben herausgefiltert und nach ihren Vornamen sortiert.
In der where-Klausel können auch die AND(&&) und OR(||) Operatoren verwendet werden um mehrere Bedingungen zu prüfen.
Im Moment enthält die Variable abfrage nur die Abfrage selbst und noch keine Daten. Erst wenn die Abfrage ausgeführt wird, werden die Daten effektiv ausgelesen.
Dazu wird z.B. eine foreach-Schlaufe verwendet:
foreach (Person person in abfrage)
{
MessageBox.Show(person.Vorname + " " + person.Nachname + "
Wohnhaft in: " + person.Wohnort);
}
Mit dieser Art werden jedes Mal, wenn auf die variable abfrage zugegriffen wird, die Daten neu aus der Datenquelle gelesen.
Möchte ich das jedoch nur 1-mal tun und die Daten anschliessend nicht neu Laden, kann ich das mit der Methode ToList() erreichen. Dazu wird die ganze Abfrage in eine Klammer gepackt und am Ende die Methode aufgerufen:
List
where person.Wohnort == "Zürich"
orderby person.Vorname
select person)
.ToList();
LINQ Methodensyntax (Lambda-Ausdrücke)
In der .NET Common Language Runtime (CLR) kann diese Abfragesyntax nicht direkt verwendet werden. Deshalb werden sie beim Kompilieren in Methodenaufrufe übersetzt, welche die CLR verwenden kann.Der Entwickler selbst kann diese Methodenaufrufe jedoch auch selbst von Anfang an verwenden, falls er das möchte. In einzelnen Fällen ist es meines Wissens sogar notwendig.
Sie ist nicht ganz so simpel wie die normale Abfragesyntax und ist daher nicht ganz so einfach lesbar.
Die oben gezeigte Abfrage wird z.B. mit Methodenaufrufen so dargestellt:
var abfrage = datenquelle
.Where(person => person.Wohnort == "Zürich")
.OrderBy(person => person.Vorname);
Diese Abfrage besteht schon aus weniger Teilen, bewirkt jedoch genau das gleiche.
Diese Ausdrücke, welche die Parameter für die Methoden Where() und OrderBy() bereitstellen, nennen sich Lambda-Ausdrücke. Wie genau man diese Ausdrücke ohne die Lambda-Syntax programmieren müsste, weiss ich nicht. Die Lambda-Syntax selbst, ist jedoch leicht zu verstehen und erklärt sich fast von selbst.
Auf der linken Seite kann eine beliebige Zeichenfolge eingegeben werden. Anschliessend muss der Lambda-Operator => verwendet werden. Mit der links eingegebenen Zeichenfolge, kann nun auf die Klasse, welche in der Datenquelle verwendet wird zugegriffen werden. So kann nun in der Where() Methode eine Bedingung definiert oder in der OrderBy() Methode eine Eigenschaft angegeben werden.
Möchte ich hier genau gleich wie oben die Daten direkt holen und nicht jedes Mal neu abfragen, kann ich das auch mit der .ToList() Methode machen. Da ich hier jedoch bereits mit der normalen Objektorientierten Syntax programmiere brauche ich keine Klammern:
var abfrage = datenquelle
.Where(person => person.Wohnort == "Zürich")
.OrderBy(person => person.Vorname)
.ToList();
Es gibt weitere solche Methoden, welche direkt Daten auslesen.
Mit First() kann ich z.B. direkt das erste Objekt aus der Liste nehmen. Würde ich z.B. mit einer Datenbank arbeiten und mit der ID eines Objekts suchen, so wäre klar dass ich nur 1 Objekt zurückbekommen kann.
LINQ Datentransformationen
Mit LINQ kann man neue Typen bzw. Klassen erstellen. Dies kann direkt mit der select-Klausel erstellt werden. Dadurch ist sie auch nicht so nutzlos wie sie einem zuerst erschien.Angenommen ich möchte jetzt nicht alle Personen welche in Zürich leben sondern bloss die Nachnamen.
Um das zu erreichen muss ich anstelle von "select person" einfach "select person.Nachname" angeben.
Dadurch bekomme ich eine List zurück, welche Strings enthält.
Noch interessanter wird es, wenn ich verschiedene Datenquellen habe, welche verschiedene Objekte speichern.
Habe ich z.B. zusätzlich zu meiner Personenliste noch eine Liste in der ich Tiere speichere.
Die Eigenschaften dieser Klasse definiere ich jetzt einfach mal so:
- Name
- Tierart
- Wohnort
Möchte ich nun die Namen aller Tiere und Menschen auslesen, welche in Zürich wohnen, kann ich das ganz einfach mit der Methode Concat() machen:
var abfrage = (from person in datenquelle
where person.Wohnort == "Zürich"
select person.Vorname)
.Concat
(from tier in datenquelle2
where tier.Wohnort == "Zürich"
select tier.Name);
Diese Abfrage wird ebenfalls eine List mit Strings zurückgeben.
Möchte ich nun z.B. nicht nur den Namen wissen, sondern ebenfalls welche Tierart das Tier hat und auch die Menschen erkennen will so kann ich nicht nur vorhandene Klassen verwenden sondern auch neue kreieren:
var abfrage = (from person in datenquelle
where person.Wohnort == "Zürich"
select new { Art = "Mensch", Name = person.Vorname + " " + person.Nachname })
.Concat
(from tier in datenquelle2
where tier.Wohnort == "Zürich"
select new { Art = tier.Tierart, Name = tier.Name });
Nun wird in dieser Liste eine Klasse ohne Namen aber mit den Eigenschaften Art und Name zurückgegeben.
Die Art ist beim Menschen dabei immer "Mensch" und beim Tier die gespeicherte Tierart.
Der Name setzt sich beim Menschen aus Vor- und Nachname zusammen und beim Tier wird einfach die Eigenschaft Name übernommen.
Keine Kommentare:
Kommentar veröffentlichen