linq Tutorial
Erste Schritte mit linq
Suche…
Bemerkungen
LINQ ist eine Reihe von Funktionen, die in .NET Framework Version 3.5 eingeführt wurden und die Lücke zwischen der Objektwelt und der Datenwelt schließen.
In der Regel werden Abfragen gegen Daten als einfache Zeichenfolgen ohne Typüberprüfung zur Kompilierzeit oder als IntelliSense-Unterstützung ausgedrückt. Darüber hinaus müssen Sie für jede Art von Datenquelle eine andere Anfragesprache lernen: SQL-Datenbanken, XML-Dokumente, verschiedene Webdienste usw. LINQ macht eine Abfrage zu einem erstklassigen Sprachkonstrukt in C # und Visual Basic. Sie schreiben Abfragen für stark typisierte Objektgruppen, indem Sie Sprachschlüsselwörter und vertraute Operatoren verwenden.
Konfiguration
LINQ erfordert .NET 3.5 oder höher (oder .NET 2.0 mit LINQBridge ).
Fügen Sie einen Verweis auf System.Core hinzu , falls er noch nicht hinzugefügt wurde.
Importieren Sie den Namespace oben in der Datei:
- C #
using System;
using System.Linq;
- VB.NET
Imports System.Linq
Die verschiedenen Verknüpfungen in LINQ
In den folgenden Beispielen werden wir die folgenden Beispiele verwenden:
List<Product> Products = new List<Product>()
{
new Product()
{
ProductId = 1,
Name = "Book nr 1",
Price = 25
},
new Product()
{
ProductId = 2,
Name = "Book nr 2",
Price = 15
},
new Product()
{
ProductId = 3,
Name = "Book nr 3",
Price = 20
},
};
List<Order> Orders = new List<Order>()
{
new Order()
{
OrderId = 1,
ProductId = 1,
},
new Order()
{
OrderId = 2,
ProductId = 1,
},
new Order()
{
OrderId = 3,
ProductId = 2,
},
new Order()
{
OrderId = 4,
ProductId = NULL,
},
};
INNER JOIN
Abfragesyntax
var joined = (from p in Products
join o in Orders on p.ProductId equals o.ProductId
select new
{
o.OrderId,
p.ProductId,
p.Name
}).ToList();
Methodensyntax
var joined = Products.Join(Orders, p => p.ProductId,
o => o.OrderId,
=> new
{
OrderId = o.OrderId,
ProductId = p.ProductId,
Name = p.Name
})
.ToList();
Ergebnis:
{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" }
LINKE ÄUSSERE VERBINDUNG
var joined = (from p in Products
join o in Orders on p.ProductId equals o.ProductId into g
from lj in g.DefaultIfEmpty()
select new
{
//For the empty records in lj, OrderId would be NULL
OrderId = (int?)lj.OrderId,
p.ProductId,
p.Name
}).ToList();
Ergebnis:
{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" },
{ NULL, 3, "Book nr 3" }
CROSS JOIN
var joined = (from p in Products
from o in Orders
select new
{
o.OrderId,
p.ProductId,
p.Name
}).ToList();
Ergebnis:
{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" },
{ NULL, 3, "Book nr 3" },
{ 4, NULL, NULL }
GROUP JOIN
var joined = (from p in Products
join o in Orders on p.ProductId equals o.ProductId
into t
select new
{
p.ProductId,
p.Name,
Orders = t
}).ToList();
Die Propertie Orders
enthält nun eine IEnumerable<Order>
mit allen Inhalten aller gelinkten Bestellungen.
Ergebnis:
{ 1, "Book nr 1", Orders = { 1, 2 } },
{ 2, "Book nr 2", Orders = { 3 } },
{ 3, "Book nr 3", Orders = { } },
Wie kann man unter verschiedenen Bedingungen teilnehmen?
Beim Beitritt unter einer bestimmten Bedingung können Sie Folgendes verwenden:
join o in Orders
on p.ProductId equals o.ProductId
Verwenden Sie beim Beitritt zu mehreren:
join o in Orders
on new { p.ProductId, p.CategoryId } equals new { o.ProductId, o.CategoryId }
Stellen Sie sicher, dass beide anonymen Objekte die gleichen Eigenschaften haben. In VB.NET müssen sie als Key
markiert sein, obwohl VB.NET mehrere durch And
getrennte Equals
Klauseln zulässt.
Join o In Orders
On p.ProductId Equals o.ProductId And p.CategoryId Equals o.CategoryId
Abfragesyntax und Methodensyntax
Die Abfragesyntax und die Methodensyntax sind semantisch identisch, aber viele Benutzer finden die Abfragesyntax für einfacher und lesbarer. Nehmen wir an, wir müssen alle geraden Artikel in aufsteigender Reihenfolge aus einer Zahlenkollektion abrufen.
C #:
int[] numbers = { 0, 1, 2, 3, 4, 5, 6 };
// Query syntax:
IEnumerable<int> numQuery1 =
from num in numbers
where num % 2 == 0
orderby num
select num;
// Method syntax:
IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);
VB.NET:
Dim numbers() As Integer = { 0, 1, 2, 3, 4, 5, 6 }
' Query syntax: '
Dim numQuery1 = From num In numbers
Where num Mod 2 = 0
Select num
Order By num
' Method syntax: '
Dim numQuery2 = numbers.where(Function(num) num Mod 2 = 0).OrderBy(Function(num) num)
Denken Sie daran, dass einige Abfragen als Methodenaufrufe ausgedrückt werden müssen . Beispielsweise müssen Sie einen Methodenaufruf verwenden, um eine Abfrage auszudrücken, mit der die Anzahl der Elemente abgerufen wird, die einer angegebenen Bedingung entsprechen. Sie müssen auch einen Methodenaufruf für eine Abfrage verwenden, die das Element abruft, das den Maximalwert in einer Quellsequenz enthält. Das könnte ein Vorteil sein, wenn die Methodensyntax verwendet wird, um den Code konsistenter zu machen. Sie können die Methode jedoch natürlich immer nach einem Aufruf einer Abfragesyntax anwenden:
C #:
int maxNum =
(from num in numbers
where num % 2 == 0
select num).Max();
VB.NET:
Dim maxNum =
(From num In numbers
Where num Mod 2 = 0
Select num).Max();
LINQ-Methoden und IEnumerable vs IQueryable
LINQ-Erweiterungsmethoden für IEnumerable<T>
tatsächliche Methoden 1 , ob anonyme Methoden:
//C#
Func<int,bool> fn = x => x > 3;
var list = new List<int>() {1,2,3,4,5,6};
var query = list.Where(fn);
'VB.NET
Dim fn = Function(x As Integer) x > 3
Dim list = New List From {1,2,3,4,5,6};
Dim query = list.Where(fn);
oder benannte Methoden (Methoden, die explizit als Teil einer Klasse definiert wurden):
//C#
class Program {
bool LessThan4(int x) {
return x < 4;
}
void Main() {
var list = new List<int>() {1,2,3,4,5,6};
var query = list.Where(LessThan4);
}
}
'VB.NET
Class Program
Function LessThan4(x As Integer) As Boolean
Return x < 4
End Function
Sub Main
Dim list = New List From {1,2,3,4,5,6};
Dim query = list.Where(AddressOf LessThan4)
End Sub
End Class
Theoretisch ist es möglich, die IL der Methode zu analysieren , herauszufinden, was die Methode versucht, und die Logik dieser Methode auf jede zugrunde liegende Datenquelle anzuwenden, nicht nur auf Objekte im Speicher. Aber das Analysieren von IL ist nichts für schwache Nerven.
Glücklicherweise stellt .NET für dieses Szenario die IQueryable<T>
-Schnittstelle und die Erweiterungsmethoden unter System.Linq.Queryable
zur Verfügung. Diese Erweiterungsmethoden verwenden einen Ausdrucksbaum - eine Datenstruktur, die Code darstellt - anstelle einer tatsächlichen Methode, die der LINQ-Anbieter dann analysieren 2 und in eine geeignetere Form zur Abfrage der zugrunde liegenden Datenquelle konvertieren kann. Zum Beispiel:
//C#
IQueryable<Person> qry = PersonsSet();
// Since we're using a variable of type Expression<Func<Person,bool>>, the compiler
// generates an expression tree representing this code
Expression<Func<Person,bool>> expr = x => x.LastName.StartsWith("A");
// The same thing happens when we write the lambda expression directly in the call to
// Queryable.Where
qry = qry.Where(expr);
'VB.NET
Dim qry As IQueryable(Of Person) = PersonSet()
' Since we're using a variable of type Expression(Of Func(Of Person,Boolean)), the compiler
' generates an expression tree representing this code
Dim expr As Expression(Of Func(Of Person, Boolean)) = Function(x) x.LastName.StartsWith("A")
' The same thing happens when we write the lambda expression directly in the call to
' Queryable.Where
qry = qry.Where(expr)
Wenn diese Abfrage (beispielsweise) gegen eine SQL-Datenbank gerichtet ist, kann der Anbieter diesen Ausdruck in die folgende SQL-Anweisung konvertieren:
SELECT *
FROM Persons
WHERE LastName LIKE N'A%'
und führen Sie es gegen die Datenquelle aus.
Wenn die Abfrage jedoch gegen eine REST-API gerichtet ist, kann der Anbieter denselben Ausdruck in einen API-Aufruf konvertieren:
http://www.example.com/person?filtervalue=A&filtertype=startswith&fieldname=lastname
Das Anpassen einer Datenanforderung basierend auf einem Ausdruck bietet zwei Hauptvorteile (anstatt die gesamte Sammlung in den Speicher zu laden und lokal abzufragen):
- Die zugrunde liegende Datenquelle kann häufig effizienter abfragen. Beispielsweise kann es sehr gut einen Index für
LastName
. Das Laden der Objekte in den lokalen Speicher und das Abfragen des Arbeitsspeichers verliert diese Effizienz. - Die Daten können vor der Übertragung geformt und reduziert werden. In diesem Fall muss der Datenbank- / Web-Service nur die übereinstimmenden Daten zurückgeben, im Gegensatz zum gesamten Personenkreis, der in der Datenquelle verfügbar ist.
Anmerkungen
1. Technisch gesehen verwenden sie keine Methoden, sondern delegieren Instanzen, die auf Methoden verweisen . Diese Unterscheidung ist hier jedoch unerheblich.
2. Dies ist der Grund für Fehler wie " LINQ to Entities erkennt die Methode 'System.String ToString ()' nicht und diese Methode kann nicht in einen Speicherausdruck übersetzt werden. " Der LINQ-Anbieter (in diesem Fall der Entity Framework-Anbieter) kann nicht wissen, wie ein Aufruf von ToString
in entsprechende SQL- ToString
übersetzt wird.