Recherche…


Remarques

LINQ est un ensemble de fonctionnalités introduites dans le .NET Framework version 3.5 qui comble le fossé entre le monde des objets et le monde des données.

Traditionnellement, les requêtes sur les données sont exprimées sous forme de chaînes simples sans vérification de type au moment de la compilation ou du support IntelliSense. En outre, vous devez apprendre un langage de requête différent pour chaque type de source de données: bases de données SQL, documents XML, divers services Web, etc. LINQ fait une requête une construction de langage de première classe en C # et Visual Basic. Vous écrivez des requêtes sur des collections d'objets fortement typées en utilisant des mots-clés de langage et des opérateurs familiers.

Installer

LINQ nécessite .NET 3.5 ou version ultérieure (ou .NET 2.0 avec LINQBridge ).

Ajoutez une référence à System.Core , si elle n'a pas encore été ajoutée.

En haut du fichier, importez l'espace de noms:

  • C #
  using System;
  using System.Linq;
  • VB.NET
  Imports System.Linq

Les différentes jointures dans LINQ

Dans les exemples suivants, nous utiliserons les exemples suivants:

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,
  },
};

JOINTURE INTERNE

Syntaxe de requête

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

Syntaxe de la méthode

var joined = Products.Join(Orders, p => p.ProductId, 
                                   o => o.OrderId, 
                                     => new 
                                    { 
                                      OrderId   = o.OrderId, 
                                      ProductId = p.ProductId, 
                                      Name      = p.Name 
                                    })
                     .ToList();

Résultat:

{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" }

JOINTURE EXTERNE GAUCHE

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

Résultat:

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

Résultat:

{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" },
{ NULL, 3, "Book nr 3" },
{ 4, NULL, NULL }

GROUPE REJOIGNEZ

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

Les Orders propriétés contiennent désormais un IEnumerable<Order> avec toutes les commandes liées.

Résultat:

{ 1, "Book nr 1", Orders = { 1, 2 } },
{ 2, "Book nr 2", Orders = { 3 } },
{ 3, "Book nr 3", Orders = { } },

Comment adhérer à plusieurs conditions

Lorsque vous vous joignez à une seule condition, vous pouvez utiliser:

join o in Orders 
  on p.ProductId equals o.ProductId

Lorsque vous vous joignez à plusieurs, utilisez:

join o in Orders 
  on new { p.ProductId, p.CategoryId } equals new { o.ProductId, o.CategoryId }

Assurez-vous que les deux objets anonymes ont les mêmes propriétés, et dans VB.NET, ils doivent être marqués comme étant Key , bien que VB.NET autorise plusieurs clauses Equals séparées par And :

Join o In Orders 
  On p.ProductId Equals o.ProductId And p.CategoryId Equals o.CategoryId

Syntaxe de requête et syntaxe de méthode

La syntaxe et la syntaxe de la requête sont identiques sur le plan sémantique, mais de nombreuses personnes trouvent la syntaxe de la requête plus simple et plus facile à lire. Disons que nous devons récupérer tous les articles, même ordonnés, dans un ordre croissant à partir d'une collection de nombres.

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)

N'oubliez pas que certaines requêtes doivent être exprimées sous forme d'appels de méthode. Par exemple, vous devez utiliser un appel de méthode pour exprimer une requête qui extrait le nombre d'éléments correspondant à une condition spécifiée. Vous devez également utiliser un appel de méthode pour une requête qui récupère l'élément qui a la valeur maximale dans une séquence source. Cela pourrait donc être un avantage d'utiliser la syntaxe de la méthode pour rendre le code plus cohérent. Cependant, vous pouvez bien sûr toujours appliquer la méthode après un appel de syntaxe de requête:

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

Méthodes LINQ et IEnumerable vs IQueryable

Les méthodes d'extension LINQ sur IEnumerable<T> utilisent des méthodes réelles 1 , qu'il s'agisse de méthodes anonymes:

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

ou méthodes nommées (méthodes explicitement définies dans le cadre d'une classe):

//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

En théorie, il est possible d' analyser l'IL de la méthode , de déterminer ce que la méthode tente de faire et d'appliquer la logique de cette méthode à toute source de données sous-jacente, et pas seulement aux objets en mémoire. Mais analyser l'IL n'est pas pour les faibles de cœur.


Heureusement, .NET fournit l'interface IQueryable<T> et les méthodes d'extension de System.Linq.Queryable pour ce scénario. Ces méthodes d'extension utilisent un arbre d'expression - une structure de données représentant du code - au lieu d'une méthode réelle, que le fournisseur LINQ peut ensuite analyser 2 et convertir en un format plus approprié pour interroger la source de données sous-jacente. Par exemple:

//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)

Si (par exemple) cette requête concerne une base de données SQL, le fournisseur peut convertir cette expression en l'instruction SQL suivante:

SELECT *
FROM Persons
WHERE LastName LIKE N'A%'

et l'exécuter avec la source de données.

En revanche, si la requête est associée à une API REST, le fournisseur peut convertir la même expression en appel API:

http://www.example.com/person?filtervalue=A&filtertype=startswith&fieldname=lastname

Il y a deux avantages principaux à adapter une demande de données basée sur une expression (au lieu de charger toute la collection en mémoire et d'interroger localement):

  • La source de données sous-jacente peut souvent interroger plus efficacement. Par exemple, il peut très bien y avoir un index sur LastName . Le chargement des objets dans la mémoire locale et l'interrogation en mémoire perd cette efficacité.
  • Les données peuvent être mises en forme et réduites avant d'être transférées. Dans ce cas, la base de données / service Web doit uniquement renvoyer les données correspondantes, par opposition à l'ensemble des personnes disponibles à partir de la source de données.

Remarques
1. Techniquement, ils ne prennent pas de méthodes, mais délèguent plutôt des instances qui pointent vers des méthodes . Cependant, cette distinction est sans importance ici.
2. C'est la raison des erreurs comme " LINQ to Entities ne reconnaît pas la méthode" System.String ToString () ", et cette méthode ne peut pas être traduite en une expression de magasin. ". Le fournisseur LINQ (dans ce cas, le fournisseur Entity Framework) ne sait pas analyser et traduire un appel à ToString en SQL équivalent.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow