1. LINQ, qu'est-ce que c'est ?

Le Framework .Net 3.5 a apporté quelques améliorations et évolutions dont une qui fait beaucoup parler d'elle dans le petit monde des développeurs .Net, il s'agit de LINQ (pour Language Integrated Query). Il s'agit en fait d'un ensemble de classes et de méthodes permettant de requêter des objets et des sources de données au sens large un peu à la manière de SQL directement dans le code .Net. Vous allez me dire il y "a déjà SQL pour cela", oui mais non, en effet LINQ permet de requêter des bases de données, mais également des objets, des collections, des fichiers XML, des datasets...

En effet jusqu'à maintenant quand il fallait faire des recherches dans des listes génériques en fonction de critères précis cela s'avérait souvent fastidieux. Imaginez une collection contenant 10000 objets développeurs, s'il faut retourner les développeurs (les objets développeur) dont le nom est complété, dont l'âge est au moins 25 ans, dont le salaire est inférieur à 30000 euros, et tout cela trié par ordre croissant sur le nom de la société à laquelle ils appartiennent. Cela est certes faisable mais faire cela simplement et en quelques lignes de code n'était à ce jour par possible en .Net, avec LINQ rien de plus simple !

Avant de rentrer un peu plus dans le code et "le comment" voyons un peu plus en détail ce qu'est LINQ.

Il existe actuellement 5 versions de LINQ fournies par défaut dans le Framework .Net 3.5 qui permettent de requêter des sources de données qui peuvent être les suivantes :

  • Base SQL
  • Objets
  • Entités
  • XML
  • Dataset
Microsoft .Net



LINQ offre un modèle ouvert et il est par exemple possible d'implémenter ses propres opérateurs. LINQ s'appui sur un certain nombre de nouveautés apportées par C# 3.0 et VB.Net 9.0 pour pouvoir s'intégrer au mieux dans ces langages.

2. LINQ to objects par le code

2.1. Requêter une collection

Pour bien comprendre le fonctionnement de LINQ voyons ce que cela donne dans le code quand l'on souhaite requêter une collection. Nous allons commencer avec un exemple simple en créant une liste générique de chaînes de caractères, puis en la requêtant à l'aide de LINQ.

 
Sélectionnez

            List<Developer> developers = new List<Developer>
            {
                new Developer{ Firstname = "Pierre", Lastname = "Martin", Age= 27, Company="Microsoft", Payroll=25000 },
                new Developer{ Firstname = "Jean", Lastname = "Dupond", Age= 47, Company="Sun", Payroll=75000 },
                new Developer{ Firstname = "Paul", Lastname = "Leroi", Age= 21, Company="Google", Payroll=20000 },
                new Developer{ Firstname = "Victor", Lastname = "Duchemin", Age= 32, Company="IBM", Payroll=35000 },
                new Developer{ Firstname = "Louis", Lastname = "Dupont", Age= 28, Company="Intel", Payroll=55000 },
                new Developer{ Firstname = "Henry", Lastname = "Duclos", Age= 29, Company="Dell", Payroll=18000 },
                new Developer{ Firstname = "Michel", Lastname = null, Age= 29, Company="Bull", Payroll=18000 },
                new Developer{ Firstname = "Stephane", Lastname = "", Age= 29, Company="Amiga", Payroll=18000 },
                new Developer{ Firstname = "Marcel", Lastname = "Merlin", Age= 29, Company="AMD", Payroll=45000 },
            };

            var requestedDevelopers = from dev in developers
                                      where dev.Age > 25 && dev.Payroll < 30000 && dev.Lastname != null && dev.Lastname != string.Empty
                                      orderby dev.Company ascending
                                      select dev;

Comme on le voit grâce aux instructions de LINQ, très proches de celles du langage SQL, il est possible de filtrer les données selon des critères et des paramètres précis, exactement comme lorsque l'on requête une base de données, mais tout cela directement dans notre code .Net. Il sera donc par exemple très facile de débugger notre code. Comme SQL, LINQ nous offre de nombreux opérateurs, voici la liste des plus communs :

  • Select, SelectMany
  • Where
  • Join
  • Reverse, OrderBy
  • Sum, Max, Min, Average, Count

Pour information LINQ offre plusieurs dizaines de mots clés et éléments !

Comme nous venons de le voir avec ce premier exemple, l'ordre des opérateurs est quasiment inverse par rapport à SQL, par exemple l'on commence par From et l'on termine par Select ! Ce n'est pas pour embêter le développeur mais entre autre pour pouvoir bénéficier de l'IntelliSense lors de l'écriture d'une requête.

Passons maintenant à la découverte de fonctionnalités de LINQ que vous risquez d'utiliser fréquemment.

2.2. Calcul d'agrégat

Un calcul d'agrégat permet de calculer une somme, une moyenne, un maximum... Prenons une liste de commandes et calculons le montant des commandes de plus de 100 euros :

Calcul d'une somme
Sélectionnez

            List<Order> orders = new List<Order>
            {
                new Order{ Amount = 8978M, CustomerName ="Dupond", Date = DateTime.Parse("01/01/2008") },
                new Order{ Amount = 78M, CustomerName ="Martin", Date = DateTime.Parse("01/01/2008") },
                new Order{ Amount = 157M, CustomerName ="Merlin", Date = DateTime.Parse("01/01/2008") },
            };

            var ordersSum = (from ord in orders
                             where ord.Amount > 100
                             select ord.Amount).Sum();

2.3. Regroupement

Nous allons voir ici comment regrouper les résultats d'une requête en fonction d'une clé déterminée, comme par exemple regrouper les commandes par clients. Voici comment procéder :

 
Sélectionnez

            List<Order> orders = new List<Order>
            {
                new Order{ Amount = 15M, CustomerName ="Martin", Date = DateTime.Parse("01/01/2008") },
                new Order{ Amount = 3M, CustomerName ="Martin", Date = DateTime.Parse("01/01/2008") },
                new Order{ Amount = 65M, CustomerName ="Martin", Date = DateTime.Parse("01/01/2008") },
                new Order{ Amount = 11M, CustomerName ="Dupond", Date = DateTime.Parse("01/01/2008") },
                new Order{ Amount = 43M, CustomerName ="Dupond", Date = DateTime.Parse("01/01/2008") },
                new Order{ Amount = 8M, CustomerName ="Dupond", Date = DateTime.Parse("01/01/2008") },
                new Order{ Amount = 157M, CustomerName ="Merlin", Date = DateTime.Parse("01/01/2008") },
                new Order{ Amount = 7M, CustomerName ="Merlin", Date = DateTime.Parse("01/01/2008") },
                new Order{ Amount = 76M, CustomerName ="Merlin", Date = DateTime.Parse("01/01/2008") },
                new Order{ Amount = 9M, CustomerName ="Merlin", Date = DateTime.Parse("01/01/2008") },
            };

            var ordersGroupedByName = from ord in orders
                                      group ord by ord.CustomerName;

2.4. Classement

Avec l'opérateur OrderBy il est possible de classer les résultats d'une requête dans l'ordre croissant ou décroissant sur un champ donné.

 
Sélectionnez

            List<Order> orders = new List<Order>
            {
                new Order{ Amount = 78M, CustomerName ="Martin", Date = DateTime.Parse("01/01/2008") },
                new Order{ Amount = 8978M, CustomerName ="Dupond", Date = DateTime.Parse("01/01/2008") },
                new Order{ Amount = 157M, CustomerName ="Merlin", Date = DateTime.Parse("01/01/2008") },
            };

            var ordersByName = from ord in orders
                               orderby ord.CustomerName ascending
                               select ord.CustomerName;

3. Conclusion

J'espère au travers de cet article vous avoir montré dans les grandes lignes les possibilités offertes par LINQ to object. Avec LINQ il est désormais possible de requêter des listes d'objets très facilement de manière aussi poussée que ce que l'on pourrait faire avec SQL sur une base de données. Il est de plus important de garder à l'esprit que LINQ ne se limite pas aux objets seulement mais à une grande variété de sources de données. A bientôt pour d'autres articles consacrés à LINQ.

Ressources