linq Tutoriel
Démarrer avec linq
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.