Looking for linq Keywords? Try Ask4Keywords

linqErste Schritte mit linq


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.

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.

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();
 

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