Etude exploratoire de Linq

Dimension: px
Commencer à balayer dès la page:

Download "Etude exploratoire de Linq"

Transcription

1 Année académique Faculté des Sciences appliquées Etude exploratoire de Linq Directeur de mémoire : Dr. Ir. Hugues Bersini Mémoire présenté par Charles Schoonenbergh En vue de l obtention du diplôme de Master en ingénieur civil informaticien, spécialité ingénierie informatique

2 Abstract Linq est une technologie apparue avec C# 3 et VB 2008 et a été présenté comme un gigantesque bon en avant dans le domaine de la gestion des données. La présente étude se propose d explorer Linq depuis ses fondements jusqu à l analyse de plusieurs mises en situation. L étude débutera par l analyse des enrichissements syntaxiques apportés avec C# 3 pour ensuite définir le formalisme de requêtes utilisé par Linq. Linq se décline en une série d implémentations, celles-ci seront examinées en détails en commençant par Linq to Object. Ensuite viendra le tour de Linq to Sql. Cette implémentation étant source de beaucoup de controverse, une attention toute particulière y sera apportée. Plusieurs tests de mise en œuvre seront appliqués, notamment en ce qui concerne les performances relatives à un code équivalent rédigé avec la couche ADO.NET classique. D autres implémentations relationnelles seront étudiées comme Linq to DataSet, Linq to Entities exploitant la toute nouvelle technologie Entity Framework et une brève analyse de l implémentation Db Linq sera faite. L implémentation Linq to Xml sera ensuite étudiée, présentant les nouveautés liées à la gestion du contenu Xml. Un bilan des nouveautés proposées par Linq sera ensuite établi et l étude se terminera par l analyse des alternatives à Linq, que ce soit pour la plateforme.net ou pour d autres langages orientés objet, ainsi que Java, PHP ou Python.

3 Table des matières Conventions d écriture 1 Introduction 2 1. Vue d ensemble 3 2. Mécanismes sous-jacents Quelques rappels Généricité Délégués Méthodes anonymes Enrichissements syntaxiques Inférence sur le typage Expressions lambda Expressions arborescentes Extensions de méthode Formalisme d une requête Implémentation Objets Champ d application Quelques opérateurs à la loupe Projection groupée Inversion et indexes Groupement Quantificateurs Conversion en énumérable Exemple illustratif Implémentations relationnelles Entités en mémoire Linq to SQL Mapping Syntaxe au niveau du code Principe et fonctionnement Gestion par le DataContext 21

4 4.2.2 Opérations fondamentales Cas pratiques Erreurs et difficultés Performances Test d insertion Test en situation concurrentielle Conclusion Linq to DataSet Linq to Entities Concept fondateur Fonctionnement Mapping Rôlede Linq Db Linq Implémentation XML En pratique Ressenti général Points forts, points faibles Quelles alternatives? Java JDO Hibernate NET NHibernate Entity Framework Autres langages Persistance personnalisée Bases de données objets Evolutions de Linq Version Ce qui reste à améliorer Linq et Mono 49 Conclusion 50

5 Bibliographie 51 Annexe 1 : Code de l exemple Linq to object 52 Annexe 2 : Code de test de performance Linq to Sql 55 Annexe 3 : Utilisation d une base de données MySql avec Linq to DataSet 65

6 Conventions d écriture Afin de rendre plus aisée la lecture de ce document, des conventions d écriture ont été adoptées. Les termes faisant référence à une classe, un assemblage ou une méthode seront écrits en italique et dans le respect de la casse originale, comme ceci : Methode définie pour telle Classe. Les termes faisant références à des procédures ou à des techniques bien connues seront écrit avec une majuscule pour mieux ressortir, comme ceci : La clause Select du langage Sql. Les extraits de code seront présentés dans une police spéciale pour bien ressortir du texte principal. En outre, un alinéa supplémentaire sera observé, comme ceci : Ceci est un extrait de code; Les références à des sites internet se feront comme des références classiques lorsque le site contient de l information dont le présent écrit est inspiré. Lorsque du contenu est cité explicitement, une note de bas de page présentera l adresse web exacte.

7 Introduction Depuis l apparition des langages orientés objet, le problème de la persistance des données a toujours été crucial. Un programme incapable de retenir ce qui s est passé lors de sa précédente exécution ne présente qu un intérêt limité. Malheureusement aucun langage orienté objet n a de prise directe sur cette capacité de persistance. Des systèmes de stockage se sont développés, certains très antérieurs aux langages orientés objet eux-mêmes. C est le cas des bases de données relationnelles qui stockent l information sous forme de tables ayant des relations entre elles. Ce mode de stockage c est petit à petit imposé comme acteur principal lorsqu il s agit d enregistrer des informations depuis un programme. L ennui est que les langages de programmation actuels ne s interfacent pas parfaitement avec ce type de persistance. Depuis longtemps déjà, des solutions sont mises en œuvre pour palier à ce problème. Réaliser un interfaçage n est pas tout, il reste le problème de la dépendance au niveau du code. Si changer le système d enregistrement des données implique de réécrire la moitié de l application qui les utilise, la situation est gênante. L abstraction envers le stockage a ses limites, lui aussi. Les bases de données orientées objet et plus tard leurs homologues basées sur Xml sont venues s ajouter dans le paysage moderne de la persistance. Ces gestionnaires de données n utilisent cependant pas le même langage et passer de l un à l autre sans rien changer est tout simplement irréalisable. Nous avons donc actuellement affaire à des applications mêlant plusieurs langages de programmation, généralement de l orienté objet couplé à un langage de requêtes propre à la source de données. C est là que la tâche du développeur se complique. Il faut non seulement maîtriser plusieurs langages mais en plus pouvoir interfacer les deux de la façon la plus abstraite possible car un changement de politique de stockage est toujours possible. Linq a été introduit avec C# 3 et VB Derrière cet acronyme, Language INtegrated Query, se cache presque tout un paradigme. Une nouvelle manière d appréhender les données, spécialement celles qui sont persistantes. La présente étude se propose d explorer les différentes possibilités qui caractérisent Linq tout en gardant un œil critique sur ce que Microsoft annonce comme étant LA révolution dans le monde de la programmation. Nous tenterons dans un premier temps de mettre en lumière les solutions techniques qui ont été mises en œuvre avec Linq. La question du champ d application sera ensuite abordée, passant en revue les différentes implémentations de Linq : ce qu il peut faire ou ne pas faire et quels types de données il peut cibler. Nous nous intéresserons tout particulièrement au cas des données relationnelles qui restent, comme déjà précisé, un acteur incontournable dans le domaine de la gestion des données non volatiles. Après ces différentes études de cas, nous tenterons de faire le point sur les forces et faiblesses de Linq avant d envisager les alternatives à son utilisation. Viendra enfin un examen de son devenir et de ses éventuelles évolutions avant de conclure notre étude.

8 Chapitre 1 : Vue d ensemble Dans cette section nous allons donner un avant-goût de Linq et préciser la méthode générale qui sera suivie durant cette étude. Tout au long de ce rapport nous utiliserons le terme de Linq pour désigner l ensemble des fonctionnalités accessibles grâce à ses implémentations. Linq n est pas réellement un tout unifié mais davantage un regroupement de plusieurs API partageant une syntaxe commune. Il est bon de garder cela en tête pour éviter toute confusion. Ce chapitre est inspiré de [1]. Comme son acronyme l indique, Linq offre la possibilité de faire des requêtes intégrées au langage, mais que devons-nous comprendre par là? En réalité, le terme requête sera expliqué dans le prochain chapitre et lorsque nous parlons de langage il s agira de C# et VB Ces deux langages de programmation font partie de la plateforme.net (prononcé dotnet, à l Anglaise), parfois aussi appelé framework.net. Comme abordé dans l introduction, un problème majeur actuellement est de devoir mélanger des langages appartenant à des paradigmes différents : en général un pour la programmation orientée objet et l autre pour la gestion des données stockées. L ensemble des difficultés engendrées par la mixité des langages est souvent appelé «impedance mismatch» dans la littérature internationale. Ce problème d impédance entre langages résulte souvent en une baisse de productivité pour le développeur et une panoplie d erreurs difficiles à débusquer car n apparaissant potentiellement que très tard, à l exécution. Linq est présenté comme le remède à tous ces soucis, offrant un seul langage où tout est vérifié à la compilation. Reste à voir quel fossé existe entre ce genre d annonces publicitaires et la réalité de la conception d applications. Cette étude a pour but d explorer Linq et ses fonctionnalités, c'est-à-dire d examiner de quelle façon Linq se propose de faire la jonction entre le monde des objets et celui de leur persistance. Nous ne prétendons pas porter de jugement sur le choix de telle ou telle manière de réaliser le stockage des données. Il n est pas non plus de notre ressort d établir que tel langage de programmation est mieux qu un tel autre. Nous tâcherons également de rester aussi objectifs que possible dans nos considérations, il ne s agit pas de vanter Microsoft ou même Linq mais d étudier ce dernier. Nous essayerons de partir de sources documentées aussi officielles que possible pour ensuite mettre en œuvre des cas concrets. Diverses autres sources seront cependant mentionnées mais leur caractère non officiel sera précisé.

9 Chapitre 2 : Mécanismes sous-jacents 2.1 Quelques rappels Avant de se lancer dans l analyse des nouveautés syntaxiques, rappelons certains aspects intéressants déjà présents dans le deuxième framework de.net. Ces fonctionnalités sont à la base de Linq et constituaient déjà des avancées majeures dans le domaine de l abstraction en général. Il s agit des classes génériques, des méthodes anonymes ainsi que des délégués. Nous allons les passer rapidement en revue en montrant leur intérêt du point de vue de Linq ainsi que leur rôle. Les améliorations venues se greffer par-dessus ces mécanismes seront détaillées dans la prochaine section. L ensemble de cette section est principalement inspiré de *2+ pour le contenu et de *1+ pour sa structure Généricité La généricité, en tant que telle, a été introduite dans le langage C++ par le biais des classes templates. Le principe, rappelons-le brièvement, est de pouvoir considérer l exécution d un code sans avoir à spécifier quel type d objets il manipulera. C#, dans sa version 2, permettait l usage et la définition de classes, de structures, d interfaces et de fonctions génériques. En plus d apporter une plus grande sûreté dans la programmation 1, la généricité rend également un code plus réutilisable lorsqu elle est utilisée. De ce fait, l usage des génériques offre un niveau d abstraction facile d emploi. Une liste peut être définie de manière générique, car les principes d insertion, de recherche et de suppression ne sont aucunement liés au type de contenu. A l utilisation, la liste sera précisée comme étant une liste d entiers, de strings ou de n importe quel type d objets dont il sera question à ce moment-là. La définition de la liste représente bien une abstraction par rapport à son contenu et néanmoins, le compilateur remarquera les opérations illicites au niveau typage (impossible d ajouter un string à une liste d entiers par exemple). La généricité est importante pour envisager Linq, les manipulations de données (telles qu une insertion, une suppression ou une recherche, tout comme pour la liste) n étant pas liées directement au contenu. Comme nous le verrons plus loin, Linq utilise une interface générique pour manipuler des données Délégués Les délégués sont des objets (de classe Delegate ou d une de ses sous-classes) qui peuvent appeler une ou plusieurs fonctions, à la manière des pointeurs de fonctions en C++. Le principe n est pas nouveau, son origine remonte au C++ comme nous venons de le préciser. Ce qui est nouveau, en revanche, ce sont les facilités de syntaxes ainsi que la possibilité d ajouter un nombre variable de fonctions à un délégué. Un exemple illustratif inspiré de [2] mettra en lumière ces aspects à la page suivante. 1 La généricité dans les collections permet d encore accroître le typage et donc la vérification à la compilation.

10 class Exemple static void f1() Console.WriteLine("fct1"); static void f2() Console.WriteLine("fct2"); delegate void T(); //declaration du delegue static void Main(string[] args) T del = new T(f1); del += new T(f2); del(); //execute les deux fonctions pointees En lisant l exemple ci-dessus, la première chose qui va nous intéresser est la déclaration du délégué. Ceci correspond bien à une déclaration de type (ici un type nommé T) dont nous avons le choix de son nom (T) et le mot clé delegate précise qu il s agit d un type délégué. Il est possible d ajouter au délégué une ou plusieurs références à des fonctions à la condition que celles-ci respectent la signature du délégué (ici aucun paramètre et void comme retour). C est ce dont il s agit dans les deux premières lignes de la méthode Main. Lorsqu un délégué fait référence à plusieurs fonctions, il les exécute toutes dans l ordre avec lequel elles ont été assignées au délégué. Ainsi, le code de l exemple plus haut produirait en sortie le résultat suivant : Figure 1 : appels de délégués Le principe des délégués est à la base des expressions lambda fortement utilisées par Linq. Comme nous le verrons ces expressions sont spécialement utilisées dans la résolution des clauses de requêtes (select, where ) Méthodes anonymes Les méthodes anonymes ont été introduites avec la deuxième version de.net. Il s agit de suites d instructions jouant le rôle d une méthode, sans pour autant définir explicitement de fonction. Cela s utilise en conjonction avec les délégués, de la manière suivante : del += delegate string text = "Il est " + DateTime.Now.ToString(); Console.WriteLine(text); ; En effet aucun nom de méthode n a été spécifié. La seule contrainte d utilisation est qu il est impossible de faire marche arrière, puisque retirer la référence à cette méthode dans le délégué implique de pouvoir nommer cette référence. En poussant le raisonnement plus loin, pourquoi ne pas utiliser une méthode anonyme en paramètre d une autre méthode? La lisibilité et la compréhensibilité du code s en trouvent améliorées. Linq utilise les méthodes anonymes dans ce but, améliorer la lisibilité des requêtes. Vouloir obtenir «tous les étudiants tels que leur moyenne est supérieure ou égale à 10 et les grouper par section» s écrirait en pseudo code : etudiants.where(moyenne >= 10).OrderBy(section).Select(etudiant);

11 Etudiants désignant une collection de données, l appel à la méthode Where devrait prendre en paramètre une ou plusieurs conditions à tester. Comment effectuer ces tests sans savoir au préalable leur nombre et leur nature? Le recours à une méthode anonyme va permettre de manipuler une ou plusieurs conditions complexes 2 et d extraire ainsi les objets répondant à la condition pour passer cette nouvelle collection en paramètre de l appel suivant et ainsi de suite. Linq fait un usage extensif des méthodes anonymes en conjonction avec une syntaxe simplifiée (ce point sera développé lors de la présentation des expressions lambda) pour exprimer les clauses d une requête, comme le dernier exemple l a suggéré. 2.2 Enrichissements syntaxiques Comme nous venons de le voir, certains aspects du langage C# dans sa version 2 introduisent des fonctionnalités qui nous seront utiles pour mieux cerner les fondements de requêtes sur des données abstraites. Nous allons maintenant aborder de nouveaux éléments syntaxiques, pour la plupart basés sur les mécanismes que nous venons de passer en revue. Ces nouvelles fonctionnalités vont un cran plus loin et mettent en place les bases d un langage de requêtes. Nous allons y voir comment le compilateur peut désormais inférer le typage d un objet lorsque celui-ci n est pas spécifié, comment mettre en place les méthodes d interrogations proprement dites et enfin nous allons découvrir une nouvelle façon d écrire les méthodes anonymes au moyen des expressions lambda. Avec tous ces pré requis en place, nous allons pouvoir examiner la syntaxe globale d une requête au sens de Linq en y montrant le rôle de chacun des mécanismes vus jusque là. Cette section repose essentiellement sur des informations tirées de [4] et arrangées selon une structure inspirée de [1] Inférence sur le typage L inférence sur le typage permet au compilateur de déduire le type de variables sans que le développeur ait besoin de le lui signaler explicitement. Comme cette étape se passe à la compilation, les risques d erreur restent limités tout en autorisant une syntaxe plus libre. Le mot-clé var peut être utilisé en lieu et place du type d une variable et indique au compilateur que son type devra être inféré à la compilation. A noter toutefois que l inférence sur le typage est une opération locale et ne peut donc être appliquée au champ d une classe ni dans le cas d un paramètre. Il est important de parler, à ce stade, d une autre nouveauté introduite par la troisième version du framework.net, le typage anonyme. Le typage anonyme permet de créer une variable sans en spécifier le type ni l appel explicite au constructeur (cette dernière particularité constitue elle aussi une nouveauté et est disponible pour tous les types). Ainsi il est parfaitement licite d écrire le code suivant pour une classe Personne ayant comme attributs publics les champs Nom (de type string) et Age (de type int) : Personne p = new Personne Nom = "Tartempion", Age = 40 ; var montypeanonyme = new p.nom, p.age ; Linq étant présenté comme une couche d abstraction dans l accès aux données, l intérêt d intégrer une telle syntaxe est évident. Un changement dans le type du champ Age (passage de integer en short par exemple) laissera intacte la présentation des résultats de requêtes ou les modifications de valeurs impliquant ce champ. 2 Complexe est utilisé ici pour signifier qu on dépasse le cadre d un simple opérateur conditionnel tel que ==.

12 2.2.2 Expressions lambda Cette sous-section rassemble également des informations provenant de [1] et de [6]. Le type delegate introduit avec la version 2 du framework.net représente un moyen de faire pointer du code vers une fonction définie ailleurs. L expression lambda simplifie cette pratique et permet plus de souplesse à l utilisation. Ceci s avère particulièrement utile pour l écriture de méthodes anonymes, comme le montre l exemple suivant (trouvé sur [6]) : //methode anonyme recuperant les entiers positifs, ecrite avec la //syntaxe 2.0 List<int> list = new List<int>(new int[] -1, 2, -5, 45, 5 ); List<int> positivenumbers = list.findall(delegate(int i) return i > 0; ); //meme code ecrit avec une expression lambda List<int> list = new List<int>(new int[] -1, 2, -5, 45, 5 ); var positivenumbers = list.findall((int i) => i > 0); La syntaxe d une expression lambda est toute simple. Elle se compose d une liste de paramètres (un seul, dans l exemple ci-dessus, l entier i), du symbole «=>» intuitivement traduit par «tel que» et d une expression qui constitue en fait la valeur retournée par l expression lambda. Cette formulation est bien plus lisible et se prononce «tous les entiers i tels que la valeur de i est strictement supérieure à 0». Un autre avantage est que la valeur retournée par l expression lambda est typée implicitement, comme l indique le mot-clé var dans l exemple précédent. En plus d une simplicité d écriture pour les méthodes anonymes, les expressions lambda permettent de traiter des expressions proches des clauses Sql. Ainsi une clause Where dans une requête Sql peut se voir comme une condition de filtrage du résultat. Pour exprimer ceci en termes d expressions lambda, nous appelons notre condition de filtrage définie par une expression lambda sur le résultat, de cette manière résultat.filtrage(conditions). Le résultat de ce filtrage peut être lui-même soumis à d autres opérations de ce type, présentant l avantage de pouvoir lire les opérations séquentiellement de gauche à droite : résultat.filtre1( condition1.1, condition1.2).filtre2( condition2.1, condition2.n) et ainsi de suite. C est ainsi que Linq en fait usage, pour passer à chaque opérateur de clause le résultat créé par l appel des clauses précédentes : EnsembleFrom.Where(clause where).select(clause select).orderby(critère de tri). Nous ne parlons ici que des clauses au sens relationnel du terme, le Sql étant devenu en quelque sorte le standard pour interroger des données, nous nous contentons d utiliser ici l analogie. Nous verrons plus loin que Linq a adopté une syntaxe qui en est très proche Expressions arborescentes Agir sur une source de données implique de pouvoir naviguer, disons, parmi les nœuds de sa structure. La notion de relation entre des données stockées caractérise ceci au niveau conceptuel, mais en pratique, qu en est-il? Pour des collections d objets en mémoire, des itérateurs ou des méthodes de saut à un autre élément sont généralement fournis par la collection elle-même. Pour une structure relationnelle, les relations sont réalisées par des jointures entre plusieurs tables. Aucun mécanisme orienté objet ne permet d appeler une fonction qui sautera directement vers l élément désiré. Le problème est le même lorsqu on manipule des données en Xml bien que, dans ce cas, la syntaxe des requêtes soit plus proche du paradigme objet. Pour résoudre ce problème, les expressions arborescentes (expression tree, en Anglais) ont vu le jour. L intérêt n est pas tant de manipuler en soi la source de données mais plutôt de pouvoir naviguer dans un résultat et surtout dans une requête. Comprendre la notion de jointure est indispensable pour écrire une requête qui y

13 fait appel et l idée est ici que nous dotons notre programme orient objet d un outil capable de comprendre comment réaliser la navigation. Nous allons tenter de brièvement résumer son fonctionnement. Le concept des expressions arborescentes est dérivé de celui des expressions lambda. Premièrement, une expression arborescente est une expression lambda dont le code va être maintenu en mémoire. Deuxièmement, cette expression peut être parcourue lors de l exécution. Troisièmement, elle devra être compilée pour pouvoir être exécutée dans le langage propre à la source de données. Tentons maintenant de faire le lien entre ces trois propriétés. Le code sera maintenu en mémoire pour pouvoir être analysé pas à pas et modifié le cas échéant. L expression devra être compilée, donc son impact sur la source de données sera construit au moment de l exécution. Il faut comprendre ici le terme «compilé» comme signifiant «transformé dans le langage propre à la source de données et optimisé pour plusieurs exécutions successives» 3. La compilation classique, avec validation syntaxique, a bien entendu toujours lieu. Par exemple, si la requête implique une lecture dans une base de données relationnelle, la création de la requête Sql se fera à la volée. Une requête peut être jugée comme étant syntaxiquement correcte sans avoir besoin de connaître la nature de la source de données. Pour pouvoir être compilée, la requête doit disposer de son code en mémoire. Ce code sera parcouru de manière à créer des instructions pour la source de données. Ces instructions se composent de blocs logiques à la manière d une équation mathématique. La longueur de ces instructions n est pas fixée et l expression qui en représente une possède une structure en arbre, d où le terme d expressions arborescentes. En résumé, cela revient à dire qu une expression arborescente représente un traitement générique (les paramètres sont fournis à l exécution) et que le code de cette expression est compilé à la volée, durant l exécution du programme. L intérêt est de pouvoir construire des requêtes dont les paramètres seront fournis à l exécution et de choisir quand exécuter cette requête dans une optique d optimisation. Cet aspect générique va permettre au développeur d écrire une requête Linq paramétrique et de choisir à quel moment et vers quelle cible il décidera de l exécuter. Cette requête pourra ainsi être traduite en une expression Sql si la source de données est relationnelle ou au contraire en une requête XQuery à destination d un fichier Xml. Jusqu ici rien n a été cité pour justifier l utilisation d autre chose qu une expression lambda adaptée. En réalité, les possibilités offertes par les expressions lambda sont limitées lorsqu un certain nombre d appels, récursifs ou non, sont nécessaires en leur sein. Considérons le code suivant (le code et l explication y afférante sont tirés de *1+): fac => x => == 0? 1 : x * fac(x-1) Ce code ne compilera pas tel quel, il est impossible d appeler une expression lambda depuis sa définition, ce que tente pourtant de faire l appel «fac(x-1)». Bien qu il existe des techniques pour palier à ce problème, nous n allons pas les traiter ici. Le but était seulement de montrer avec un exemple simple que les expressions lambda ne permettent pas de tout faire. Rappelons que les expressions lambda sont utilisées par Linq pour représenter les clauses d une requête. Mais certaines clauses peuvent être arbitrairement complexes. Pensons par exemple à la possibilité de réaliser une requête imbriquée dans une clause Where en Sql. Une simple expression lambda ne peut en ellemême représenter une clause réalisant une requête imbriquée, cela l obligerait à s appeler elle- 3 Le terme compilé est traduit de l Anglais «compiled» tel que mentionné dans *1+. L explication fournie est en revanche personnelle.

14 même durant sa définition. Les expressions arborescentes permettent de résoudre ce problème en constituant une super expression composée de nœuds selon une structure en arbre. La construction finale de l expression se fait en commençant par les feuilles de l arbre, en remontant ensuite. L ouvrage *1+ propose l explication la plus claire qui a pu être trouvée sur la cuisine interne des expressions arborescentes. Cette explication se base sur un exemple qui confronte une expression lambda avec une expression arborescente, le code présenté ci-dessous est tiré de cet exemple. Nous allons tenter de résumer cette explication afin de bien percevoir ce qu est une expression arborescente. Commençons donc par un code qui devrait permettre d afficher le type d une expression lambda et celui d une expression arborescente (certains extraits ont été traduits en dehors de quoi le code est identique à celui proposé dans l ouvrage) : static void exemple() Func<int, int> lambdainc = (x) => x + 1; Expression<Func<int, int>> exprinc; exprinc = (x) => x + 1; Console.WriteLine("avec expression lambda : 0", lambdainc.tostring()); Console.WriteLine("avec expression arborescente : 0", exprinc.tostring()); Bien que la déclaration soit écrite de manière différente, le résultat est préssenti comme devant être le même. Parlons maintenant du résultat non pas de ces deux expressions mais de l affichage dans la console. Le résultat produit par ce code prend cette forme : Figure 2 : types d'expressions Notre expression lambda est en fait une référence vers un type créé par le compilateur, le type «`2» prenant deux paramètres entiers. Notre expression arborescente quant à elle semble contenir la structure de l expression sous forme plus lisible. Rappelons-nous qu une expression lambda est en réalité une abréviation pour l écriture d un délégué. Le compilateur crée donc un objet délégué d un nouveau type, puisqu une expression lambda fait usage du typage anonyme. Le type créé pour notre expression arborescente n est pas un délégué, comme nous pouvons le voir. Pour découvrir comment est interprétée cette expression, [1] nous fournit le schéma page suivante ainsi que le code correspondant à ce schéma.

15 Figure 3 : schéma d'une expression arborescente Pour réaliser une structure similaire, voici le code proposé : static void equivalent() Expression<Func<int, int>> exprinc; ConstantExpression constante = Expression.Constant(1, typeof(int)); ParameterExpression parametre = Expression.Parameter(typeof(int), "x"); BinaryExpression addition = Expression.Add(parametre, constante); exprinc = Expression.Lambda<Func<int, int>>(addition, new ParameterExpression[] parametre ); Console.WriteLine("ex. arb. avec syntaxe equivalente :"); Console.WriteLine("0", exprinc.tostring()); Et ce code produit le résultat que voici : Figure 4 : type d'une expression arborescente Notons que les quelques lignes qui apparaissent entre la déclaration de l expression et l affichage en console, tout ce groupe représente l équivalent de ce qui avait écrit la première fois comme «exprinc = (x) => x + 1». Nous avons bien généré l arbre en partant des feuilles, nœud par nœud. Sans compliquer trop l explication, signalons juste que chaque nœud est matérialisé par un objet nœud de type générique, permettant d assurer la navigation au sein de l expression.

16 2.2.4 Extensions de méthode «Extension de méthode» est le terme utilisé pour ajouter une méthode à une classe donnée sans manipuler le code de cette classe. Cela reviendrait à créer une classe héritant de la classe de base en spécifiant la ou les méthodes que l on souhaite y ajouter. Plus qu une facilité syntaxique, l extension de méthode permet d éviter les pièges tendus par l héritage et n introduit pas de biais conceptuel dans la programmation. Une extension de méthode ne peut utiliser que les champs publics de la classe dont elle est l extension. Elle doit elle-même être déclarée comme publique et statique. Son premier paramètre doit être précédé du mot-clé this et le type de ce paramètre définit le type dont la méthode est une extension. Le code suivant (tiré de [11]) montre une extension de méthode ayant pour effet de représenter un nombre décimal sous forme de chaîne de caractères au format standard US : //Exemple fourni par Linq in Action public static string FormattedUS( this decimal d) return String.Format( formatus, "0:#;0.00", d); L utilisation des extensions de méthodes donnera peut-être l impression de faire double emploi avec les méthodes virtuelles mais il faut garder à l esprit qu une méthode virtuelle est résolue à l exécution alors qu une extension de méthode doit être résolue dès la compilation. Précisons enfin que le type étendu peut être générique, ce qui offre la possibilité d étendre un ensemble de types simultanément. Typiquement, les extensions de méthodes sont utilisées lors de l appel de clauses dans les requêtes comme les clauses Where ou Select. Le framework.net dans sa version 3 propose une interface générique IEnumerable<T> pour représenter toute donnée susceptible de faire l objet d une requête ou d une manipulation propre aux données. Des extensions de méthodes sont définies pour chaque clause avec cette interface (ou l un de ses descendants) comme type étendu Formalisme de requêtes Cette sous-section s inspire très fortement de *1+ et *11+. Les expressions de types requêtes ont été introduites avec la troisième version du framework.net et définissent la forme générale d une requête lorsqu elle est écrite en C# ou en Visual Basic Une requête apparaît ici au sens large puisque la syntaxe sera la même que ce soit une requête vers une base de données relationnelle, vers une liste d objets en mémoire ou encore vers un fichier XML. Une requête correctement formulée doit commencer par une clause From et se terminer par une clause Select ou une clause group. La clause From indique quels types d objets vont être interrogés et ceux-ci doivent implémenter l interface IEnumerable<T> représentant une collection de données générique susceptible de faire l objet d une requête. Chaque clause de l expression correspond à un ou plusieurs appels d extensions de méthodes pour l interface citée précédemment. Voici un exemple de requête typique : var query = from e in etudiants where e.moyenne >= 10 select e; Le compilateur interprétera l expression ci-dessus de la manière suivante : var query = etudiants.where(e => e.moyenne >= 10).Select(e => e);

17 A noter que etudiants n a pas été particularisé et pourrait être aussi bien une classe représentant une table de données relationnelle qu une liste ordonnée d objets en mémoire. Dans les deux cas, le code écrit reste correct. Les expressions de type requête sont traduites par le compilateur. La validité d une requête et la vérification des types sont établis lors de la phase de compilation du code. Les fautes de frappe et les erreurs syntaxiques seront donc détectées par le compilateur, ce qui représente un avantage certain par rapport aux accès Sql ou Xml qui ne révèleront leurs erreurs qu à l exécution. Ceci permet déjà d avoir une vue d ensemble de Linq au travers des enrichissements syntaxiques apportés par le framework version 3. Les expressions de type requête sont des interrogations génériques qui appellent une succession de méthodes, chacune utilisant la réponse de la précédente comme paramètre. Les méthodes d extensions simplifient l écriture de ces appels, les rendant plus lisibles et plus faciles à implémenter. Les méthodes anonymes permettent la transmission des paramètres d un appel à l autre. Les expressions lambda permettent de définir la logique de la plupart des opérations effectuées par ces méthodes. Les types anonymes permettent de gérer en mémoire les résultats de requêtes et l inférence sur le typage est ce qui permet au compilateur de faire le lien entre toutes ces fonctionnalités et de les valider à la compilation. Avant de rentrer dans les détails de comment Linq est implémenté, deux remarques sont encore à souligner. Premièrement, au vu des nouveautés syntaxiques du langage, Linq apparaît d ores et déjà comme une partie intégrante du langage et non comme un outil ORM 4 à greffer sur une architecture existante. Cela implique qu utiliser Linq ne nécessite que le fait de programmer avec une version trois (ou supérieure) du framework.net. L autre point à soulever est que Linq n est défini jusqu ici qu en termes d interface générique (IEnumerable<T> pour rappel) et de mécanismes de langage. Ceci implique deux choses : Linq est défini en plusieurs implémentations de base et il est possible d ajouter une implémentation de Linq pour s adapter à un besoin précis. Ceci termine notre tour d horizon des changements généraux d ordre purement syntaxique proposés avec la troisième version du framework.net. Nous avons introduit les principaux mécanismes qui constituent Linq ainsi que leurs interactions, ayant souligné également que Linq se compose de plusieurs implémentations. Nous allons de ce pas examiner ces différentes implémentations en détails. 4 ORM signifie Object Relational Mapper. Il s agit le plus souvent d une désignation pour un utilitaire assurant une certaine automatisation dans la réalisation du mapping objet relationnel.

18 Chapitre 3 : Implémentation Objets Nous avons vu jusqu ici quelle est la manière de formuler une requête syntaxiquement valide, requête au sens de Linq. Rien n a été spécifié en ce qui concerne la nature de la source de données, ce qui implique que tout ce qui a été vu jusqu ici sera toujours valable tant que nous parlons de Linq. Mais Linq en lui-même n est qu un tas de concepts mis bout à bout. Si nous faisons le point de ce qui a déjà été vu, nous avons un formalisme pour écrire des requêtes avec l explication générale de comment cette requête pourra être traduite vers une source de données, quelle qu elle soit. C est précisément cette opération de traduction qui va nécessiter de connaître cette source plus en détails. Pour répondre à cette attente, Linq est présenté avec une syntaxe unifiée, faisant abstraction (répétons-le une fois encore) de la nature du stockage des données. Et pourtant, ce que nous appelons Linq depuis le début est en réalité un ensemble d implémentations partageant une même syntaxe extérieure. Chaque implémentation est définie par un nom qui correspond au type de données qu elle cible. Ainsi nous parlerons de Linq to Sql, Linq to DataSet et ainsi de suite. Nous commencerons notre étude par l implémentation objet, Linq to Objects. Cette implémentation sera rapidement parcourue, examinant quelques aspects intéressants. Parmi ces aspects, nous nous intéresserons à certains opérateurs généraux (donc valables pour toutes les implémentations) et à l interface IEnumerable<T> que doit implémenter toute donnée désirant interagir avec Linq. Ce chapitre dans son ensemble est inspiré de [11] et de [1] pour la description des opérateurs. 3.1 Champ d application Linq to Objects permet d interagir avec toute collection qui implémente IEnumerable<T>. Les collections standards intégrées au framework implémentent toutes cette interface, ce qui permet de ne pas se poser la question dès lors qu on utilise une structure de base. Pour ce qui est des collections définies par l utilisateur (le programmeur), le plus simple est de créer une collection par héritage d une structure standard. Cela peut s avérer être une erreur conceptuelle dans certains cas, et l utilisateur devra réaliser lui-même l implémentation de cette interface. Ceci s applique à toutes les implémentations Linq. Regardons d un peu plus près cette fameuse interface. Elle est définie dans l espace de noms System.Collections.Generic et la documentation 5 [4] montre que la seule méthode qui est renseignée est GetEnumerator qui doit retourner un objet capable de parcourir les éléments de la collection un à un. La documentation officielle fait également état d un ensemble d extensions de méthode qui représentent en fait l ensemble des opérateurs disponibles. Implémenter IEnumerable<T> signifie posséder les extensions de méthode nécessaires à Linq pour assurer le bon déroulement de requêtes écrites avec la syntaxe vue précédemment. Nous allons maintenant nous intéresser à certains opérateurs, ne pouvant tous les détailler par manque de place (il y en a plus d une centaine en comptant toutes les surcharges!). 5 La référence exacte est :

19 3.2 Quelques opérateurs à la loupe Les opérateurs représentent ce qu il est possible de faire en utilisant Linq sur un ensemble de données. Nous pouvons aisément nous imaginer qu il est possible de réaliser une projection à la manière d un Select en Sql ou même un filtrage avec une clause Where puisque ces opérations sont définies explicitement dans la syntaxe. Certaines fonctionnalités légèrement plus subtiles se sont néanmoins glissées dans Linq et nous allons tâcher d en rassembler quelques unes. Nous parlerons ainsi de l opérateur de projection groupée, de l opérateur d inversion, de l opérateur de groupement, des quantificateurs et de l opérateur de conversion en énumérable Projection groupée L opérateur de projection groupée est appelé officiellement SelectMany. Son comportement est globalement similaire à celui de l opérateur Select, mais il a pour effet d aplatir le résultat obtenu. Ainsi, une requête demandant l ensemble des cours suivis par les étudiants de dernière année recevrait une réponse sous la forme d une collection de cours et non comme une collection de collections de cours. Lorsque seules les valeurs distinctes doivent être reprises, il suffit d appliquer au résultat l opérateur Distinct. Il est intéressant de noter que l aplatissement du résultat est disponible mais non imposé au programmeur. S il désire travailler sur les collections, un Select suffira. S il désire travailler sur les éléments eux-mêmes, un SelectMany constituera un raccourci appréciable Inversion et indexes Les opérateurs de tri classiques que sont OrderBy et ThenBy permettent de trier les éléments d un résultat pour peu que ceux-ci implémentent l interface IComparable<T>. Mais en certaines circonstances, il peut être intéressant d avoir les derniers éléments de la liste. Pour ce faire, Linq propose un opérateur d inversion appelé Reverse qui retourne l ordre des éléments au sein d une collection. Rien d extraordinaire jusqu ici mais il est nécessaire d introduire un autre petit concept, celui des opérateurs à index. Il faut savoir que plusieurs opérateurs acceptent un argument supplémentaire de type entier et qui permet de ne considérer le résultat qu après en avoir exclu un nombre d éléments correspondant à la valeur passée en argument. Avec cette information, l opérateur d inversion permet d inverser un résultat dont les x premières entrées ont été retirées ou d ignorer les x dernières entrées d un résultat. Bien que cela puisse faire l effet d un simple gadget, il est intéressant de noter cette combinaison d opérateurs qui permet de réaliser une sélection plus fine du résultat Groupement L opérateur de groupement, appelé GroupBy, réalise le groupement des résultats selon une clé spécifiée. Une clause de groupement rend facultative la clause de projection (de sélection) car le groupement renvoie le résultat sous forme d une collection de collections, chaque collection étant accessible par la valeur de sa clé associée. Le critère de groupement est défini par une expression lambda ce qui rend le groupement très lisible. Notons que le critère de groupement n est pas tenu de faire partie de la clause de projection, comme c est le cas en Sql. L opérateur de groupement possède plusieurs surcharges, permettant des réglages supplémentaires. Parmi ces surcharges, citons la possibilité de préciser un sélecteur d éléments ainsi qu un sélecteur de résultat. Un exemple d utilisation se trouve à la page suivante.

20 var r = etudiants.groupby( e => e.facultes, e => new e.nom, e.matricule, (key, elements) => new Cle = key, Nbr = elements.count() ); Le premier paramètre est le critère de groupement, le second est le sélecteur d éléments qui va jouer le rôle d opérateur de projection embarqué. C est ce paramètre qui va définir quelles valeurs seront gardées lors de l affichage du résultat. Le troisième paramètre est le sélecteur de résultat qui permet de réaliser une projection non plus sur les éléments mais sur les groupes, ce qui est particulièrement intéressant lorsqu on souhaite obtenir des informations d agrégation sur les résultats sans le détail de ceux-ci. Le résultat produit par le code ci-dessus fournira des informations sur nombre d étudiants inscrits dans chaque faculté. Un groupement similaire mais sans le sélecteur de résultat donnerait le nom et le matricule de chaque étudiant, ceux-ci étant groupés par faculté Quantificateurs Les quantificateurs sont bien pratiques lorsqu il s agit de faire des manipulations complexes sur les données. Les fameux «Pour tout» et «Il existe» sont d ailleurs une légère entrave en Sql puisque les quantificateurs universels n y sont pas définis [12]. Linq fournit trois opérateurs de quantifications Any, All et Contains. Le quantificateur Any retourne la valeur true si au moins un élément de la collection sur laquelle il est appelé répond favorablement à l expression lambda qui lui est passée en paramètre. Si aucune expression ne lui est passée, il répond simplement à la question «Y a-t-il un élément dans la collection?». Le quantificateur All permet de vérifier que l ensemble des éléments d une collection vérifient un prédicat ayant la forme d une expression lambda. En réalité cet opérateur tente de vérifier qu aucun élément de la collection ne vérifie pas le prédicat, ce qui signifie qu il retournera toujours true sur une collection vide. Le quantificateur Contains tente de vérifier si une collection contient un élément spécifique. En termes objets, n oublions pas que deux éléments seront jugés identiques si et seulement si leurs références pointent toutes deux vers le même objet. Il est néanmoins possible de fournir un comparateur personnalisé pour déterminer l égalité de deux objets sur base d autres critères que leurs simples références Conversion en énumérable Il s agit ici d un opérateur prenant en paramètre une séquence d objets et cet opérateur retournera des valeurs identiques mais sous forme d objets énumérables, c est-à-dire implémentant l interface IEnumerable<T>. Comment s y prend-il? Très simplement, en utilisant un énumérable générique dans lequel il encapsule les données de chaque élément. Cet énumérable générique est en fait une collection assez pauvre puisque son seul but va être de fournir accès aux extensions de méthodes qui caractérisent les énumérables. Toute autre information sera superflue puisque supposée déjà être présente dans la collection à convertir. Notons qu il existe d autres opérateurs de conversion tels que ToList, ToArray et ToDictionnary qui peuvent être utiles pour convertir un résultat dans un format plus classique. L opération de conversion en énumérable est fortement utilisé avec l implémentation Linq to DataSet, ceci sera développé dans la section consacrée à cette implémentation.

21 3.3 Exemple illustratif Considérons un graphe d objets représenté par une liste de listes. A titre d exemple, imaginons que les nœuds de ce graphe soient des villes et que chaque ville soit reliée par une route à une ou plusieurs autres villes. Pour corser un peu la situation, nous allons doter nos villes d informations supplémentaires, un nombre d habitants, un nom et une liste de toutes les communes qui dépendent de celle-ci. Il faut bien sûr que chaque ville ait à sa disposition la liste des villes auxquelles elle est connectée, cela constituera les branches de notre réseau. Le code comprenant les définitions nécessaires à cet exemple se trouve en annexe (Annexe 1 : Code de l exemple Linq to object). Commençons par écrire une requête adressée au réseau et permettant de retrouver toutes les villes comptant au plus habitants. Ceci s écrit comme suit : var petitesvilles = from v in reseauroutier where v.hab <= orderby v.hab select new Ville = v.nom ; foreach (var ville in petitesvilles.reverse()) Console.WriteLine(ville); Ce code, en plus d être intuitif, permet de réaliser aisément la récupération du résultat. Ceci n est cependant pas très dur à récupérer en utilisant une syntaxe classique. Imaginons maintenant vouloir connaître l ensemble des villes qui comprennent au moins deux communes et qui sont connectées à une ville de moins de habitants. Avec une écriture classique, cela implique de parcourir la liste des villes du réseau. Pour chacune de ces villes, il faudra récupérer l ensemble des communes et les dénombrer. Pour celles qui possèdent au moins deux communes, il faudra parcourir la liste des villes avec lesquelles une connexion existe. Si les villes à l autre bout de cette connexion ont un nombre d habitant inférieur ou égal à la borne souhaitée, nous devons ajouter la ville initiale à l ensemble qui sera le résultat. C est déjà relativement complexe à écrire en syntaxe classique, mais si nous désirons maintenant montrer le nom des villes à faible population qui figurent dans les connexions, c est encore pire. Il faudra créer des associations voire même recréer un graphe d objets et le retourner comme résultat. Ecrivons cela avec Linq : var requete = from v in reseauroutier from c in v.liaisons where v.communes.count() >= 2 && c.hab <= select new Ville = v.nom, Connexion = c.nom, Habitants=c.Hab; foreach (var v in requete) Console.WriteLine(v);

22 Ceci produit le résultat suivant qui correspond bien à ce que nous attendions : Figure 5 : exemple Linq to object Les deux clauses From représentent en réalité l équivalent d une jointure. Les relations sont accessibles de manière simple, il suffit d avoir un accès à la propriété correspondante. Ceci permet de justifier l emploi de Linq même dans un contexte déjà «tout objet». Linq représente un moyen à la fois simple et puissant d exprimer des requêtes. Nous avons vu en détails plusieurs opérateurs ainsi qu un exemple pratique mettant en scène l implémentation objet de Linq. Nous allons maintenant nous pencher sur les sources de données relationnelles.

23 Chapitre 4 : Implémentations relationnelles La problématique de la persistance des objets remonte probablement à la popularisation des premiers langages orientés objets [3]. Les applications utilisent des objets en mémoire pour décrire le monde et ceux-ci disparaissent dès la fin de l application. Pour les enregistrer, le recours à des bases de données relationnelles reste une option plus que répandue [3]. Or le monde objet et celui du relationnel ne s interfacent pas parfaitement. Tout ceci n est pas nouveau, bien sûr, mais pourtant de nouvelles solutions à ce problème continuent de voir le jour à un rythme régulier. Linq se présente comme l une de ces solutions, voulant offrir une transition plus souple entre ces deux mondes. Nous allons voir comment Linq a été pensé pour interagir avec les données relationnelles. Nous commencerons par présenter quelques concepts à la base de la correspondance objetrelationnel telle que réalisée par Linq. Nous détaillerons ensuite les différentes implémentations relationnelles de Linq, en précisant leur moyen d arriver à une correspondance entre objets et tables relationnelles. Nous tâcherons également de soulever les avantages et limitations de chaque implémentation. Après ces analyses, nous terminerons par un bilan global des possibilités offertes par Linq pour manipuler des bases de données. Ce chapitre est inspiré de *3+ pour l introduction. Chaque section ayant été le fruit de recherches particulières, les références y seront détaillées au cas par cas. 4.1 Entités en mémoire Cette section est tiré de [1] et [11]. Interroger une base de données suppose d avoir préalablement établi un canal de communication ainsi qu un langage commun. Linq ne permet pas d écrire des requêtes pour une base de données mais plutôt d écrire des requêtes qui seront soumises aux objets réalisant le mapping de la base de données. Il s agit d un mécanisme de cache où des objets représentent l état des données dans la base. Nous appellerons ces objets des entités et les définitions de leur classe seront appelées des classes entités (ceci correspond à la nomenclature utilisée dans l ouvrage *1+). Cette notion est centrale et doit toujours être gardée à l esprit : nous ne pourrons jamais parler directement à la base de données. Chaque implémentation proposée par Linq repose sur le concept des entités, bien que les solutions varient de l une à l autre, comme nous allons le voir. 4.2 Linq to Sql La première implémentation que nous allons étudier porte le nom officiel de «Linq to Sql» et nous pourrions intuitivement penser qu il s agit de l implémentation avec un grand «i» au regard des bases de données relationnelles. Nous verrons que ce n est pas le cas. Cette section contient énormément d informations tirées de *11+ pour les concepts théoriques, de *1+ et de *4+ pour combler les vides laissés par [11]. Nous allons voir comment cette implémentation réalise le mapping objet relationnel au niveau du code et quels sont les outils qui permettront de nous aider dans cette tâche. Nous verrons quelles classes sont impliquées dans le mapping et quel est leur rôle, avec un cas concret. Nous aborderons ensuite les possibilités de manipulation des données et les contraintes associées. Nous terminerons l étude de cette implémentation par un bref passage en revue des pièges à éviter lors de l usage de Linq to Sql.

24 4.2.1 Mapping Syntaxe au niveau du code Commençons par une petite précision. Les cibles de Linq to Sql doivent implémenter l interface IQueryable<T> qui est une descendante de IEnumerable<T>. L explication est simplement que certaines possibilités disparaissent avec l apparition des bases de données, comme par exemple la notion d ordre dans une table. Les opérateurs de sélection d éléments permettant de choisir un élément du résultat sur base d un index n ont plus de raison d être. Des notions de synchronisations entrent également en jeu, puisqu il va falloir surveiller que nos entités n aient pas fait l objet d une modification dans la base de données. Pour asseoir ce changement de comportement (qui pourrait entraîner des erreurs), c est une autre interface qui définit les extensions de méthodes. Cette précision faite, nous pouvons envisager la question du mapping. L assemblage System.Data.Linq permet d utiliser les classes entités dans le code. Ici, l esprit général des entités est de concevoir une classe entité comme la représentation d une table dans la base de données. Cette représentation doit être explicitement renseignée dans la définition d une classe, au moyen du mot clé «Table» suivi par l expression «(Name= «NomDeLaTable»)», le tout, entre crochets, placé juste avant l identificateur de la classe. Chaque propriété de la classe représentant un attribut de la table doit être précédée par le mot clé «Column» entre crochets également. Lorsque le nom de la propriété est différent de celui de l attribut, une expression «Name» similaire à celle de la table doit être utilisée. Voici l exemple d une classe entité (cet exemple s appuie sur *11+ et *1+) : [Table(Name="Clients")] public partial class Class1 [Column] private string IDClient; [Column(Name="Nom")]private string _champ2; Cette classe est une correspondance de la table Clients de la base de données, table qui possède dans ses attributs au moins un champ «IDClient» et un champ «Nom». Une classe entité n est pas tenue d effectuer le mapping de chaque attribut de la table. Elle peut également contenir des attributs ou propriétés qui lui sont propres et qui ne participent pas au mapping. Il s agit ici de considérations syntaxiques mais comment le mapping est-il réellement effectué? Nous n avons spécifié aucune information qui pourrait permettre d identifier la base de données, nous avons seulement fait «l autre moitié» du mapping. En effet, nous avons renseigné qu une classe Class1 est une classe entité et que certaines de ses propriétés sont en correspondance directe avec des attributs relationnels. Jetons maintenant un coup d œil sur l autre facette de ce mapping Principes et fonctionnement La correspondance est réalisée au moyen de fichiers spécifiques pouvant être de deux formats : le format Dbml (pour DataBase Markup Language) et le format Xml. Commençons par parler du format Dbml qui est considéré comme principal pour Linq to Sql. Le format Dbml est un langage à balises tout comme le Xml dont il est dérivé. Une définition de ce schéma est disponible avec Visual Studio 2008, cette définition servant de validateur intégré. Dans un fichier Dbml représentant un mapping valide, les premières lignes fournissent tout un tas de renseignements généraux comme la chaîne de connexion à la base de données et le nom de la classe utilisée comme DataContext. Nous reparlerons plus amplement du DataContext dans une section ultérieure, considérons pour l instant cette classe

25 comme gestionnaire des objets entités. Viennent ensuite les définitions des tables relationnelles et les classes entités qui leur correspondent. Les procédures stockées et les fonctions utilisateurs de la base de données sont également renseignées à cet endroit. Pour chaque table, les attributs et leurs propriétés Sql sont renseignés. En plus des propriétés purement relationnelles, des informations de synchronisation sont fournies, comme IsDbGenerated dans l exemple ci-dessous. Ceci touche en particulier à la synchronisation qui sera abordée lorsque nous aborderons les cas pratiques de mapping. Voici un extrait d un fichier Dbml 6 : <?xml version="1.0" encoding="utf-8"?> <Database Name="LinqDB" Class="MappingDataContext" xmlns=" <Connection Mode="AppSettings" ConnectionString="Data Source=.\SQLEXPRESS;AttachDbFilename= DataDirectory \LinqDB.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True" SettingsObjectName="LinqSelectTest.Properties.Settings" SettingsPropertyName="LinqDBConnectionString1" Provider="System.Data.SqlClient" /> <Table Name="dbo.Customers" Member="Customers"> <Type Name="Customers"> <Column Name="ID" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" /> <Column Name="Name" Type="System.String" DbType="VarChar(50) NOT NULL" CanBeNull="false" /> <Column Name="Address_city" Type="System.String" DbType="VarChar(50) NOT NULL" CanBeNull="false" /> <Column Name="Address_zip" Type="System.String" DbType="VarChar(8) NOT NULL" CanBeNull="false" /> <Column Name="Address_street" Type="System.String" DbType="VarChar(50)" CanBeNull="true" /> <Column Name="Address_number" Type="System.Int32" DbType="Int" CanBeNull="true" /> <Column Name=" " Type="System.String" DbType="VarChar(50)" CanBeNull="true" /> <Association Name="Customers_Orders" Member="Orders" OtherKey="Customer" Type="Orders" /> <Association Name="Customers_ForeignCustomers" Member="ForeignCustomers" OtherKey="ID" Type="ForeignCustomers" Cardinality="One" /> </Type> </Table> </Database> Lorsque le DataContext approprié est instancié, le fichier Dbml fournit toutes les informations nécessaires à la correspondance entre les mondes objet et relationnel. Le lien entre ces deux fichiers est très simple : le DataContext possède des références vers les classes entités, elles-mêmes validées par le Dbml du même nom que le DataContext 7. Il faut savoir que le format Dbml est le format le plus riche en termes d informations incluses dans le mapping mais il n est pas le seul disponible. Il a été prévu qu un fichier Xml puisse servir de source externe de mapping, le terme «externe» est le terme officiel utilisé par Microsoft (dans la documentation) et désigne le fait que en interne ce sera toujours un fichier Dbml qui sera manipulé même s il pourra être créé depuis une source en Xml. Les informations fournies par un tel fichier Xml sont sensiblement moins fines que celles d un fichier Dbml. En effet, les informations générales sur les tables et les entités sont présentes dans les deux 6 L alignement des balises laisse ici quelque peu à désirer, ceci étant du au manque de place. 7 nomdatacontext hérite de DataContexte et nom.dbml est le fichier de mapping.

26 cas, mais certaines informations concernant la synchronisation des entités en mémoire ne peuvent pas être exprimées. Nous n allons pas approfondir ces détails dans le cadre de cette étude, signalons simplement que ces deux formes de mappings sont équivalentes, l une étant moins expressive que l autre (des réglages supplémentaires seront à la charge du programmeur s il décide d utiliser cette méthode) Gestion par le DataContext A ce stade, nous sommes en droit de poser la question suivante «Quand et Comment seront instantiées ces classes entités?». L idée est que ces objets ne seront créés que lorsqu ils seront nécessaires afin de ne pas encombrer la mémoire et une classe en particulier sera responsable de leur gestion. Cette classe sera en quelque sorte le «chef d orchestre» du mapping, il s agit de la classe DataContext. Un objet de classe DataContext représente le lien entre la base de données et les classes entités qui lui sont assignées. Un DataContext contient une ou plusieurs classes entités et est responsable de la génération du code Sql qui sera envoyé à la base de données. C est toujours le DataContext qui va maintenir les entités, au besoin les créer et les mettre à jour. En pratique, la classe DataContext est le plus souvent dérivée et c est un de ses descendants qui est utilisé [1], la raison en deviendra apparente lorsque nous envisagerons notre cas pratique. Quand est-ce que les objets entités seront instanciés? Lorsque le DataContext reçoit une requête, s il n a pas les entités nécessaires à la fabrication de la réponse, il va soumettre la requête à la base de données en créant les entités correspondantes. Nous devons attirer l attention sur le terme «reçoit» qui est laissé expréssément flou. Linq to Sql utilise une méthode d exécution différée (deferred loading en Anglais) pour ses requêtes. Cela signifie que lorsqu une requête est soumise au DataContext, celui-ci ne va pas nécessairement la transmettre directement à la base de données 8. Par contre, une provision d entités sera créée pour pouvoir accélérer leur chargement le moment venu. Bien que cela puisse apparaître comme un mécanisme tordu, cela prend son sens dans un contexte où les accès à la base de données sont nombreux et éventuellement concurrentiels. Une politique d optimisation complexe est déployée par Linq mais nous en reparlerons plus tard. Nous avons vu jusqu ici le rôle d un DataContext vis-à-vis des entités, tant celles qui se trouvent en mémoire que celles qui séjournent dans les tables relationnelles. Nous verrons plus loin comment la théorie du mapping est mise en pratique et quel y est le rôle du DataContext. 8 Il s agit là d une interprétation de diverses sources contradictoires. *11+ précise que chaque appel au DataContexte entraîne une réaction vers la base de données, sans préciser sa nature. [4] reste très flou. [1] dit clairement que pour une lecture, l interaction n est pas initiée par le programmeur.

27 4.2.2 Opérations fondamentales Nous allons explorer dans cette sous-section les procédures dites CUD (Create Update Delete) et comment elles sont traduites vers les habituelles instructions Sql INSERT, UPDATE et DELETE. Nous examinerons en priorité les mécanismes sous-jacents et comment ceux-ci font pour surveiller les éventuels changements dans les entités. Chacune des opérations sera ensuite analysée pour avoir une idée globale de la gestion des entités vis-à-vis du support relationnel en arrière-plan. De nombreuses informations apparaissant ici sont directement tirées de [4], des sources non officielles [13] ont contribué à éclaircir les points obscurs. Pour pouvoir considérer des entités et leur évolution, il faut pouvoir agir sur ces entités et disposer d un système capable de gérer ces modifications. Nous allons commencer par nous intéresser à ce dernier. Pour Linq to Sql, ce système porte le nom de «change tracking service» que nous appellerons le service sentinelle bien que ceci ne constitue en aucun cas une appellation officielle. Cette sentinelle est chargée de conserver les états originaux des entités de manière à pouvoir détecter les changements. L autre fonction de cette sentinelle est de pouvoir recréer les modifications observées en termes d instructions Sql, pour éviter de systématiquement inclure les valeurs de tous les attributs d une entité [4]. Le service sentinelle a recours à un système de marquage pour identifier les entités modifiées. Les marques désignent l état courant de l entité, l état par défaut étant «non modifiée». Des états comme «à insérer», «à supprimer» ou «à mettre à jour» permettent de rapidement savoir quelle modification a été apportée à l entité. Le service sentinelle est accessible depuis le DataContext via l appel de la méthode GetChangeSet [1]. La sentinelle est active en permanence et collecte le moindre changement survenu sur une entité. Lorsque le DataContext reçoit l instruction d exécuter les modifications faites jusqu alors, le service sentinelle vérifie l état de toutes les entités en mémoire et créer le code Sql nécessaire pour obtenir les mêmes modifications dans la base de données. Les ajouts et suppressions d entités se font de manière relativement similaire, nous allons donc les examiner ensemble. Ajouter une entité se fait de la même manière qu un ajout de n importe quel type d objets, par un appel au constructeur. La suppression d une entité implique de l avoir préalablement isolée, autrement dit d avoir en main l objet entité en question. Pour l une ou l autre de ces opérations, il suffit désormais d appliquer les changements au DataContext en marquant l entité à modifier. Marquer une entité «à insérer» se fait en appelant InsertOnSubmit sur le DataContext en passant en paramètre une référence vers l entité à marquer. Pour réaliser la même chose lors d une suppression, il faut utiliser DeleteOnSubmit, toujours en passant la référence adéquate en paramètre. A noter qu une version a été développée pour chacune de ces méthodes de manière à opérer en une fois l opération sur une collection d entités. Ces versions groupées sont appelées InsertAllOnSubmit et DeleteAllOnSubmit respectivement. Ces variantes groupées ne sont là que dans le but simplifier l écriture, aucune forme d optimisation par groupement n a lieu 9. La mise à jour d une entité est légèrement différente. Elle nécessite d avoir isolé l entité et d avoir changé la valeur d au moins une de ses propriétés. Linq to Sql n autorise pas la modification de la propriété renseignée comme étant la clé primaire. Ceci pourrait être intéressant lorsqu on souhaite remplacer une entité par une autre en prenant en compte la participation à des relations entre entités. Une mise à jour de ce type se fait par insertion de la nouvelle valeur et remplacement de 9 Ceci a été vérifié en rebasculant le log d écriture Sql vers Console.out : y défile une longue suite de requêtes Sql indépendantes.

28 l ancienne valeur dans chaque relation à laquelle elle participe. Notons également que les mises à jour sont les seules opérations pouvant être invisibles au programmeur inattentif. Dans le cadre d une relation entre entités, s il l un des participants est supprimé l autre subira une mise à jour pour refléter que cette relation n existe plus [4] [11]. Cette mise à jour n aura éventuellement pas été spécifiée explicitement. De même, lorsqu une association est créée en passant à une entité une référence vers une autre entité, l entité reliée (mais non modifiée explicitement) sera mise à jour. Ajouter ou modifier une entité du DataContext n est en soi que la moitié du travail. Les entités en mémoire ne sont plus synchronisées par rapport à la base de données et les modifications désirées n y seront pas encore effectives [1]. Pour notifier le DataContext qu une mise à jour est souhaitée, il faut le faire explicitement par le biais de la méthode SubmitChanges. Cette opération va prendre en charge toutes les modifications apportées aux entités, qu il s agisse de créations, de mises à jour ou de suppressions. C est lors de l appel de cette méthode que le service sentinelle va répertorier toutes les modifications apportées aux entités. Des instructions Sql vont ensuite être générées pour amener la base de données correspondant aux entités en mémoire. Ceci a plusieurs implications en termes de performances et d ordonnancement des opérations. Premièrement, chaque appel de la méthode SubmitChanges peut potentiellement donner lieu à des opérations inattendues à cet instant précis [4]. En effet, la sentinelle enregistre toutes les modifications et il est tout à fait possible qu une autre partie du programme ait créé des modifications entre une insertion et sa soumission quelques lignes plus loin. Dans un contexte multithreads ou dans celui d une programmation par événements, l enchaînement exact de chaque instruction est au mieux dur à prévoir. Les mises à jour implicites sont également à ranger dans cette catégorie d opérations fantômes. Deuxième remarque à soulever, le service sentinelle passe en revue chaque entité en mémoire à chaque appel de cette fameuse méthode. La seule opération effectuée sur une entité non modifiée consiste à tester si son marquage est toujours égal à «non modifiée». Pour un ensemble conséquent d entités, ceci peut créer un délai non désiré dont il faut rester conscient. Il est, par exemple, conseillé d éviter d appeler SubmitChanges dans une boucle destinée à créer un ensemble d objets Cas pratiques Il nous reste maintenant à découvrir les techniques pratiques pour construire un mapping et son DataContext associé. Nous allons ensuite soumettre quelques requêtes et observer comment nous parviennent les résultats. Nous envisagerons d abord un cas très simple à vocation illustrative avant de considérer des scénarios plus complexes. Supposons que nous ayons une base de données Sql Server 2008 pleinement fonctionnelle à notre disposition et que notre application ne souhaite pas prendre en charge les accès concurrentiels pour l instant. Nous allons réaliser tout cela avec Visual Studio 2008, étape par étape. En ayant créé un nouveau projet C#, nous allons ouvrir l explorateur de serveurs pour y localiser notre base de données. Lorsque nous l avons trouvée, nous pouvons désormais voir les tables qu elle contient, ses procédures stockées, ses fonctions utilisateurs, les associations entre les tables et de nombreuses autres informations dont nous ne ferons pas usage dans ce simple petit test. Ajoutons une classe à notre projet dont le type sera «Linq to Sql class». Les classes Linq to Sql arborent l extension Dbml, aussi nous pouvons en conclure qu il s agira de notre fichier de mapping. Choisissons lui un nom de circonstance (par exemple «MonMapping») et validons notre choix afin de créer ce fameux fichier de mapping. Rappelons que la structure d un tel fichier, vue à la section

29 précédente, est assez complexe et semble assez rébarbative à établir. Aller vérifier chacune des nombreuses propriétés de chaque attribut d une table, pour toutes les tables impliquées dans le mapping, cela semble totalement rebutant. Et bien, réjouissons-nous, cela n a pas à être fait. En effet, à la création de notre classe à l extension Dbml, Visual Studio nous présente un éditeur graphique où nous pouvons, à notre convenance, créer des entités depuis la base de données ou de toutes pièces pour les ajouter dans le futur. Créer une classe entité depuis la base de données, cela signifie faire du «glisser-déplacer» depuis l explorateur de serveurs vers l espace d édition graphique. Toutes les métadonnées sont automatiquement extraites depuis les tables concernées, mettant directement à jour le fichier Dbml. Ajoutons deux tables à celui-ci. Si nous consultons le fichier Dbml, nous pouvons y trouver désormais la définition d une classe nommée MonMappingDataContext héritant de DataContext et des deux classes entités que nous avons créées par «glisser-déplacer». La génération des informations de mapping ainsi que celle de notre classe héritant de DataContext. Voici pourquoi nous avions dit plus haut qu en pratique c est une classe dérivée qui est utilisée. Cela nous permet également de définir plusieurs contextes et mappings différents si tel est notre bon vouloir. De retour à notre exemple, nous pouvons à présent écrire des requêtes pour nos nouvelles classes entités, le compilateur aura à sa disposition toutes les informations nécessaires pour juger de la validité syntaxique de cette requête. C est ce que nous allons faire. MonMappingDataContext db = new MonMappingDataContext(); var query = from c in db.demo_customer //clause where eventuelle select c.customer_name; Console.WriteLine("Voici la table demo_customer :"); foreach (var q in query) Console.WriteLine(q); En exécutant ce code sur le mapping considéré précédemment (nommé MonMapping), nous retrouvons notre DataContext ainsi que la structure des expressions de requêtes. Notons la simplicité d utilisation : le mapping a été créé de manière presqu entièrement automatique, une ligne pour instancier notre DataContext, deux lignes pour notre requête et l affaire est faite. Nous avons par ailleurs la sécurité de la validation par le compilateur, aucun code «unchecked» n est utilisé. Procédons maintenant à une insertion et à une suppression. Le code correspondant à ces opérations est le suivant : Console.WriteLine("Ajoutons un nouveau client avec Linq"); demo_customer dc = new demo_customer(); dc.customer_name = "nouveau client"; db.demo_customer.insertonsubmit(dc); db.submitchanges(); Console.ReadLine(); Console.WriteLine("Voici la nouvelle table demo_customer :"); foreach (var q2 in query)

30 Console.WriteLine(q2); Console.WriteLine("Supprimons le nouvel ajout"); db.demo_customer.deleteonsubmit(dc); db.submitchanges(); Console.ReadLine(); Console.WriteLine("Regardons a nouveau la table demo_customer :"); var query2 = from c in db.demo_customer select new c.customer_id, c.customer_name ; foreach (var q3 in query2) Console.WriteLine(q3); Console.ReadLine(); Et le résultat de l ensemble de ce code est le suivant : Figure 6 : requêtes Linq to Sql Tout cela paraît bien simple et automatisation rime souvent avec perte de contrôle sur les mécanismes sous-jacents. En effet, revenons à nos hypothèses de départ, à savoir que nous ayons accès à une base de données Sql Server 2008 pleinement opérationnelle et que nous ne nous préoccupions pas des accès concurrentiels. Dans la pratique, il est tout à fait possible que nous ayons affaire à une base de données dont la structure soit connue mais sans l avoir à disposition. De même, nous serions bien imprudents en affirmant qu un projet quelconque utilisera une base de données Sql Server Bon, et qu est-ce que cela change pour nous si nous n avons pas la base de données sous la main? Et bien, l extraction automatique des métadonnées se glisse hors de notre portée et nous devrons trouver un moyen d obtenir la structure de la base de données. Rappelons que le

31 mapping peut-être effectué par un fichier Dbml ou Xml, qui sont globalement des fichiers textes et donc, faciles à échanger via le réseau car de taille modeste. Visual Studio 2008 offre la possibilité d extraire facilement un fichier Dbml depuis une base de données, ne reste alors plus qu à le rendre disponible via un service web ou un procédé semblable. D accord, mais que se passera-t-il si notre base de données n est pas (ou n est plus) du type Sql Server 2008? La réponse va paraître brutale, cela ne marchera tout simplement pas, Linq to Sql est prévu pour être utilisé uniquement avec Sql Server. Attention, il est question ici de «Linq to Sql» et rappelons nous qu il ne s agit que d une implémentation Linq et non de «Linq vers relationnel» dans son ensemble. Plus qu un tour de passe-passe linguistique, il s agit de deux choses différentes. Linq to Sql peut être vu comme un raccourci simplifié pour les utilisateurs de Sql Server alors que les autres variantes de Linq offrent d autres possibilités pour relier le monde relationnel et celui des objets. Nous détaillerons ces autres possibilités dans les sections qui leur sont dédiées Erreurs et difficultés Pour terminer l analyse pratique de Linq to Sql, nous allons envisager deux cas plus complexes mais néanmoins tout à fait plausibles. Tout d abord le cas où nous n avons tout simplement pas de base de données, il arrive pour certains projets de devoir créer leur base de données «from scratch». Nous allons voir quelle aide Linq peut apporter dans ce contexte et quelles en sont les inconvénients. Nous allons ensuite examiner la gestion des accès concurrentiels et les diverses erreurs considérées comme typiques. Cette sous-section est tirée de [1], plus particulièrement du chapitre 5 : Managing Sql Data. Dans le cas où nous n avons pas encore de base de données, nous pouvons soit la créer de manière classique, soit utiliser Linq pour le faire. Rappelons-nous lors de notre premier test, nous avions à notre disposition une boîte à outil fournie par Visual Studio. Cette boîte à outil porte en réalité le nom de «Object Relational Designer» ou Concepteur Objet Relationnel pour rester dans la langue de Molière. Ce concepteur nous permet de définir de nouvelles entités, sans nous préoccuper des données relationnelles existantes (c est-à-dire que cette possibilité est disponible même si la génération des entités depuis une base de données a été utilisée). Ces entités ne correspondant à aucune table relationnelle, elles sont inutilisables telles quelles. Néanmoins une instance d un DataContext peut créer une base de données depuis son schéma de mapping en faisant appel à la fonction CreateDatabase définie pour la classe DataContext. L ouvrage [1] nous met en garde contre une telle pratique, précisant que ce n est à utiliser que lorsque les classes entités sont jugées plus importantes que la structure relationnelle. En effet, le passage d une base de données à un fichier Dbml n est pas parfaitement bidirectionnel et certaines opérations ne sont pas possibles comme par exemple la création de procédures stockées ou de triggers. Autrement dit, nous pouvons utiliser cette méthode lorsque la base de données est utiliser pour servir l application et non le contraire, auquel cas nous devrions créer notre base de données avec du code Sql. Cela reste très intéressant car nous pouvons désormais réaliser la persistance d objets sans devoir écrire la moindre ligne de code Sql et nous pouvons profiter de la validation des requêtes à la compilation, ce qui simplifie les tests et réduit le temps de développement. Les bases de données sont énormément utilisées dans le monde du web. Cet environnement à la particularité de pouvoir provoquer des accès concurrentiels n importe quand. Profitons de passage pour préciser ce que nous entendons par «accès concurrentiels». Nous allons parler ici d accès concurrentiels pour désigner les problématiques différentes que sont les opérations concourantes

32 sur des données (typiquement demande de lecture d une donnée en cours de modification ou à modifier), les transactions (avec mécanismes de roll-back si satisfaire la transaction s avère impossible) et la gestion des exceptions Sql [12]. Dans ces trois domaines, la presque totalité des problèmes pouvant survenir sont découverts à l exécution, ce qui est toujours gênant lorsqu on souhaite offrir un accès en ligne aux ressources. Linq manipule les objets entités en mémoire et donc crée un délai supplémentaire durant lequel des accès concurrentiels peuvent apparaître. Un objet entité contient plusieurs indicateurs permettant de savoir s il correspond ou non à son homologue en base de données et le DataContext peut donc détecter lorsqu un conflit survient. Il est possible d assigner une politique de gestion de conflits plus ou moins fine selon ce qui est désiré. Nous n allons pas trop nous étendre là-dessus, les heuristiques de résolution de tels conflits dépassent largement le cadre de ce travail. Nous nous contenterons de dire que les opérations concourantes ont été envisagées et que le DataContext est en mesure de réaliser une gestion de conflits assez performantes pour peu qu une politique adaptée lui soit fournie. Les informations de synchronisations jouent également un rôle important à ce niveau. En effet, lorsque le comportement est laissé par défaut (il s agit du IsDbGenerated), le DataContext ira régulièrement s informer auprès de la base de données pour s enquérir d éventuels changements survenus pour chaque attribut ayant ce comportement. Le comportement inverse est également possible. Lorsqu une entité doit modifier l une de ses propriétés, elle en avertit le DataContext et celui-ci va marquer l entité avec le statut «modifié» le temps de répercuter les changements dans la base de données. Cela nous laisse déjà entrevoir les possibilités de conflits engendrés par des opérations concourantes. Microsoft, par le biais de la bibliothèque en ligne MSDN [4], propose plusieurs politiques de gestion de conflits mais, comme dit plus haut, tout cela dépasse le cadre de notre étude. Les transactions sont utilisées systématiquement par les objets de type DataContext. Cela n a rien d étrange quand nous avons vu que le DataContext est l unique lien entre la base de données et l ensemble des entités qui lui sont associées. Lorsque le DataContext se voit soumettre une ou plusieurs requêtes, il effectue en priorité les changements sur les entités en mémoire et va, selon la disponibilité de la connexion à la base de données, soumettre à son tour les changements à la base de données. Chaque requête soumise au DataContext est encapsulée dans une transaction au sens relationnel du terme. Il est néanmoins possible pour le programmeur d élargir une transaction, en y ajoutant des modifications. La classe TransactionScope (disponible dans la bibliothèque System.Transactions) permet cette opération le plus naturellement qui soit [4]. Il suffit d instancier un nouvel objet TransactionScope sans paramètre et d y inclure l ensemble des opérations souhaitées, comme le montre le morceau de code suivant : using (TransactionScope ts = new TransactionScope()) mondatacontext.submitchanges(); //Soumission de l'ensemble des requêtes en attente //... code supplémentaire éventuel ts.complete(); Nous avons encore à aborder le problème des exceptions. Les auteurs de «Programming Linq» [1] nous présentent trois sources principales d exceptions, la création d un DataContext, les accès à une base données en lecture et ceux en écriture. Notons que Linq ne possède pas d exceptions qui lui

33 sont propres. La plupart des exceptions classiques peuvent être rencontrées en utilisant «Linq to Sql» néanmoins nous n allons détailler que celles qui sont typiques de son utilisation. Les erreurs susceptibles d apparaître lors de la création d un DataContext sont du type InvalidOperationException et indiquent un problème au niveau du mapping. De par leur nature, ces exceptions «sont considérées comme étant irrécupérables ( «unrecoverable» ) la plupart du temps» [1]. Ce genre d erreurs est «très peu probable si le mapping est généré automatiquement» [1]. Lors de l accès en lecture à une base de données, plusieurs types de problèmes peuvent survenir : l accès peut être impossible, refusé, la structure des tables peut être différente de ce qui était prévu et ainsi de suite avec la presque totalité des problèmes pouvant survenir lors de l accès à une base de données relationnelle. Le principal problème avec l accès en lecture est qu il est impossible de prévoir quand il aura lieu exactement. En effet, nous avions vu dans les précédentes sections que Linq to Sql ne permettait de parler directement qu au DataContext (c est-à-dire aux représentations en mémoire que sont les entités) et jamais à la base de données. Et pire encore, le DataContext va lui-même effectuer le travail en arrière-plan (groupement de requêtes et analyses pour maintenir la synchronisation principalement) responsable d avoir déclenché l exception sans que vous puissiez avoir directement connaissance de la nature de ces menues opérations ni du moment précis où elles auront lieu. En imaginant une application multi tiers, les causes d erreur sur les accès à la base de données peuvent se retrouvés en de nombreux points (nous parlons seulement ici des accès en lecture, rappelons-le). Nous pourrons toutefois nous consoler en constatant que la plupart des erreurs courantes auront été détectées dès la compilation et la syntaxe Sql, véritable nid à problèmes pour le développeur orienté objet, est l affaire du DataContext et non celle du programmeur désormais. Les accès en écriture ont lieu quant à eux à des moments relativement contrôlés. A ces instants, le DataContext répercute toutes les modifications apportées aux entités sur la base de données. Du fait de cette écriture décalée et d éventuelles opérations concourantes, nous devons envisager la possibilité que des opérations inattendues aient lieu à chaque écriture. Ceci veut dire qu une écriture est susceptible de déclencher n importe quel type d exception Sql [11][1][4]. Ceci rejoint grandement le problème des opérations concourantes et de la mise en place d une gestion de conflits. Nous devions cependant souligner le fait que d autres erreurs peuvent survenir lors de la phase d écriture. C est le cas des violations de contraintes d intégrité, des dépassements de délais lors de l attente d une réponse et ainsi de suite, la liste étant longue. Linq to Sql ne propose aucun remède miracle contre l apparition de ces exceptions et elles doivent être gérées comme dans le cadre d un accès relationnel classique.

34 4.2.5 Performances Les questions de performance sont toujours à garder à l œil lorsque mapping il y a. En effet, le mapping n est jamais qu une ou plusieurs couches insérées dans une pile parfois déjà conséquente. La performance n est pas toujours facile à cerner, en revanche. Nous pouvons d ores et déjà parler de performances exprimées en temps développeurs car nous avons vu ce qu il en était de la syntaxe et de la simplicité de mise en œuvre. Le travail est plus rapide et moins porteur d erreurs ([1] utilise les termes de «less error prone» pour désigner le développement avec Linq to Sql). Si le temps de mise en œuvre est réduit par rapport à une approche ADO.NET qu en est-il de la qualité? Les codes auto-générés sont souvent pointés du doigt dans ce domaine. Et les temps de réponses, seront-ils satisfaisant? Nous allons réaliser plusieurs tests afin de nous forger notre propre opinion Test d insertions Nous allons ici envisager un scénario très simple, à savoir une succession d insertions dans une table relationnelle vierge. Nous mettrons en compétition une version Linq to Sql avec une version ADO.NET. Les requêtes seront groupées ainsi que le ferait une application avec base de données locale, dans un but de réduction du nombre d accès disques. La situation est exprimée ci-dessous en pseudo code : DateTime star t = now ; //start pour le test 1 for(int i=1 ; i < nbrops ; ++i) requete.ajout(insertion unitaire); requete.execute() ; DateTime end = now ; //Ecart = end start Les codes utilisés lors de ce test sont disponibles en annexe (Annexe 2 : codes de tests de performances pour Linq to Sql). Après plusieurs exécutions de la version Linq pour un même nombre d opérations, un phénomène curieux apparaît. Cette version est plus lente à la première exécution du test, et les temps de réponses se stabilisent dès la deuxième exécution du test. C est assez inattendu et rien, à ce stade de notre étude, ne semble pouvoir justifier cela. [1] nous apprend que le DataContext rassemble toutes les informations nécessaires au mapping lors de sa première utilisation. Le mapping est gardé en mémoire jusqu à son remplacement par un autre mapping ou jusqu à la fermeture de Visual Studio. Le gain de temps observé varie entre quelques dixièmes à deux secondes, quel que soit le nombre d opérations demandées par la suite. Pour revenir à notre test, nous pouvons désormais comparer la version ADO.NET aux deux temps de réponse de la version Linq. De manière surprenante, la version Linq a été observée comme étant plus rapide pour ses deux temps de réponse. Ceci semble aller contre toute la logique du mapping et en réalité, c est là qu un examen plus approfondi du code permettra de dénicher l astuce. Pour ce premier test, la version ADO.NET a été construite de manière très naïve. La requête étant représenté par un string, celui-ci est modifié à chaque tour de boucle pour représenter une requête de plus en plus longue. La manipulation de ce string en mémoire va entraîner un nombre d opérations responsables de l accumulation de ce retard. Notons déjà ici une des forces de Linq to Sql qui est de réaliser l optimisation pour le programmeur alors que la version ADO.NET peut fonctionner en étant très mal programmée. En ne considérant que les temps d accès à la base de données, la version ADO.NET s est montrée plus rapide, ce qui était beaucoup plus prévisible. Le temps d exécution nécessaire varie presque du simple au double entre les deux approches dans ces conditions. Ces temps varient linéairement avec le nombre d opérations à effectuer. L ergonomie et la productivité du développeur

35 Linq se paient par une hausse conséquente des temps d accès (ceci est confirmé par [11] et [1]). Le graphique ci-dessous montre les résultats moyens observés durant les deux précédents tests. L axe des ordonnées représente les temps moyen d exécution exprimés en millisecondes, alors que les abscisses représentent le nombre d opérations d insertion successives effectuées durant le test. Les courbes suivies de la mention «(with Q)» désignent les résultats du premier test, où le temps d exécution comprend également le temps nécessaire à la construction de la requête. Pour les courbes qui ne sont pas suivies par cette mention, il s agit des résultats obtenus lors du second test où le temps d exécution considéré ne comprend que le temps nécessaire à la connexion directe à la base de données. Voici la situation exprimée en pseudo code : DateTime star t = now ; //start pour le test 1 for(int i=1 ; i < nbrops ; ++i) requete.ajout(insertion unitaire); DateTime start2 = now ; //start pour le test 2 requete.execute() ; DateTime end = now ; //Ecart = end start Figure 7 : test d'insertions (temps de réponse (ms) en ordonnées, nbr d'insertions en abscisse)

36 Test en situation concurrentielle Le test suivant porte sur un contexte où les connexions sont nombreuses et indépendantes. Pour simuler cette situation, nous allons simplement imposer au programme de ne considérer que des insertions simples directement transmises à la base de données. Comme précédemment, un grand nombre d insertions seront effectuées mais cette fois elles seront transmises directement à la base de données sans regroupement. Bien qu il ne s agisse pas d un scénario vraiment réaliste, cela suffira pour se faire une idée des performances relatives de Linq et d une connexion plus traditionnelle. Le graphique qui suit ce paragraphe montre les temps nécessaires (exprimés en millisecondes) à l envoi de toutes les requêtes une à une pour les deux méthodes, le nombre de requêtes de chaque lot étant repris en ordonnée. On voit clairement que la courbe intitulée «Linq sequence» croît exponentiellement avec l augmentation du nombre de requêtes à satisfaire. L explication principale en est que Linq doit manipuler des objets en mémoire comme nous l avons vu dans la section «Opérations fondamentales» de ce chapitre, dernier paragraphe. Chaque ajout créé un objet supplémentaire et cette modification a lieu en mémoire centrale, ce qui sera fait beaucoup plus rapidement que l envoi de la requête à la base de données. Chaque soumission entraîne l analyse du marquage de chaque objet, ce qui ralentit l ensemble du programme. La méthode ADO.NET, représentée par la courbe «ADO sequence», ne manipule pas d autres objets que les strings utilisés pour construire les requêtes, celles-ci étant ensuite transmises au gestionnaire de la base de données. Les temps d accès varient donc selon une progression linéaire. La troisième courbe présente sur le graphe représente les temps d accès correspondant pour une utilisation idéalisée de Linq. Utilisation idéalisée car l envoi des requêtes n est fait qu au dernier moment, économisant ainsi sur les temps d analyse de marquages par la sentinelle. L appel à la fonction SubmitChanges réalise l appel à la base de données et toutes les entités marquées comme étant «à insérer» vont générer une requête Sql correspondant à leur insertion. En n effectuant cette tâche qu une seule fois, on aperçoit que le gain de temps est conséquent 10. Dans la réalité pratique, on pourrait regrouper plusieurs requêtes par petits lots afin d économiser un peu sur les accès successifs à la base de données. Mais un appel unique est impensable, du fait que «la fin» est impossible à prévoir en pratique ainsi qu à cause des problèmes d accès concurrentiels aux données. Les possibilités d optimiser Linq relèvent principalement de la gestion des conflits, de la synchronisation et du design de l application. Les performances en situation réelles sont certainement moins bonnes que le cas idéal mais vraisemblablement plus proches de cette valeur que de celle de la version naïve. 10 Cette observation semble n apparaître nulle part, *4+ le laisse tout juste sous-entendre.

37 Figure 8 : tests en situation concurrentielle (temps de réponse (ms) en ordonnées, nbr d'insertions en abscisse) Conclusion Linq to Sql effectue la correspondance entre objets et tables relationnelles avec des fichiers spécifiques. Nous avons vu comment ces fichiers peuvent être automatiquement générés, délivrant le développeur de la tâche ardue qu est la réalisation d un mapping objet relationnel. Les mécanismes de gestion et de modifications des entités sont intuitifs et rapidement mis en œuvre, comme nous l avons fait avec un exemple concret. Plusieurs pièges restent tendus, guettant le développeur inattentif mais ceux-ci sont nettement moins nombreux que dans un contexte d accès aux données en Sql. La plupart du code est vérifié à la compilation et un système de gestion de conflits diminuera encore davantage les risques liés aux accès concurrentiels. En ce qui concerne la performance, Linq s est montré plus lent qu une approche ADO.NET mais tout en restant dans des limites acceptables. Le seul dommage semble être que Linq to Sql n est en réalité que Linq to Sql Server, ce qui limite fortement son champ d application Cette information est relativement dissimulée. C est par le réseau développez.com que j en ai eu connaissance *13+, ce n est apparu dans *1+ qu au 12 e chapitre!

38 4.3 Linq to DataSet Un DataSet est quelque chose de très proche de la notion des classes entités vues précédemment. Il s agit d une représentation en mémoire d une collection de données. Précisons qu un DataSet est une représentation générique puisque la collection de données est une représentation d une source de données que cette dernière soit d origine relationnelle ou non. Les DataSets font partie de la couche de données ADO.NET et n ont donc pas été introduits par Linq. La couche d accès aux données ADO.NET fait un grand usage des DataSets, notamment en lecture pour conserver des informations de structure liées aux données. Il est assez logique que Linq propose une implémentation destinée à interroger ces structures. Nous allons poursuivre notre étude avec l analyse cette implémentation nommée Linq to DataSet. Cette section est grandement inspirée de [1] et de [4]. Comme son nom l indique, cette implémentation a pour cibles des objets de type DataSet. Cette section ne sera pas découpée en sous-parties car Linq n introduit que peu de nouveautés en ce qui concerne les DataSets. L étude approfondie des mécanismes sous-jacents aux DataSets en général n entre pas dans le cadre de ce travail et nous les passerons sous silence. Pour pouvoir être utilisable par une implémentation Linq, il est nécessaire d implémenter l interface IEnumerable<T>. Sans nous étendre sur le sujet, signalons qu il y a moyen de créer des DataSets typés mais en toute généralité un DataSet doit être considéré comme non typé et n implémente donc pas la fameuse interface. Nous ne considèrerons ici que les DataSets non typés et nous tenterons d éclaircir comment les utiliser en tant que IEnumerable<T>. Etant un concept abstrait, les DataSets peuvent être construits depuis n importe quel type de base de données. Ils disposent en outre de mécanismes pour recréer la structure des tables relationnelles sous-jacentes. Un mapping? En effet, cela y ressemble fortement, mais celui-ci doit être explicitement spécifié «à la main» par le développeur. Pour interroger de telles structures, Linq a réalisé une implémentation spécifique appelée «Linq to DataSet». Ceci permet de bénéficier de toutes les améliorations apportées par Linq sur des structures pouvant s interfacer sur n importe quel type de base de données. Ceci n est en aucun cas le remède universel au vide laissé par Linq to Sql puisque ce ne sont que les DataSets qui sont interrogeables. Leur construction ainsi que le suivi des modifications vers la base de données sont encore à faire. Un DataSet représentant une cache de base de données est classiquement construit à partir d un DataAdapter (c est-à-dire en utilisant la couche ADO.NET). A noter qu il est possible d utiliser Linq pour remplir un DataSet sans passer par un DataAdapter, mais cela suppose d avoir préalablement récupéré les données et de les avoir sous forme IEnumerable<T>. Pour pouvoir utiliser Linq sur une table d un DataSet, il faut donc explicitement créer un mapping avec la fonction TableMappings.Add(string sourcetable, string DataSetTable) du DataSet. Pour que cette table soit énumérable, il faut utiliser l opérateur AsEnumerable qui sera, dans ce cas-ci, utilisé sur une DataTable. Voyons un exemple utilisant une base de données MySql (sa procédure de construction est détaillée dans l annexe 3 : utilisation d une base de données MySql avec Linq to DataSet).

39 using MySql.Data; using MySql.Data.MySqlClient; class Program static void Main(string[] args) MySqlConnection con = new MySqlConnection ("Database=MyLinqSql;Uid='root'"); con.open(); DataSet ds = new DataSet("MySqlDataSet"); string selectstring * FROM objects1"; MySqlDataAdapter da = new MySqlDataAdapter(selectString,con); da.tablemappings.add("objects1", "Table"); da.fill(ds); //interrogation du DataSet ds avec Linq to DataSet DataTable dt1 = ds.tables["table"]; var datasetquery = from o in dt1.asenumerable() select new ID = o.field<int>("id"), TEXT = o.field<string>("desc"); foreach(var res in datasetquery) Console.WriteLine(res); //Fermeture de la connexion con.close(); Console.WriteLine("Appuyez sur Enter pour terminer..."); Console.ReadLine(); Le résultat de ce code, pour la base de données considérée est le suivant : Figure 9 : Linq to DataSet pour interroger un DataSet construit avec MySql Revenons maintenant sur les particularités de ce code. Nous avons bien créé une connexion MySql que nous ouvrons et nous instancions un nouveau DataSet nommé MySqlDataSet. Nous créé un nouveau DataAdapter avec l instruction de sélectionner toutes les lignes de la table objects1. Un mapping est ensuite créé pour pouvoir retrouver dans le DataSet la table équivalente à objects1 sous le nom de Table. Le DataSet est rempli et nous définissons une nouvelle DataTable avec Table. Vient ensuite notre requête qui a toutes les apparences d une requête Linq qui devrait maintenant nous être familière. Néanmoins, la référence à la table utilise l opérateur AsEnumerable car une DataTable n implémente pas IEnumerable<T>, comme nous l avions dit plus haut. Mais nous voyons également

40 que les attributs de cette table doivent être accédés par la méthode Field<T> en précisant explicitement la nature de T, car le compilateur ne pourrait réaliser l inférence depuis un champ d une DataTable. Ceci n est simplement pas prévu. Peut-être cela changera-t-il dans le futur, mais pour l heure nous devons nous-mêmes fournir les informations qui sont en réalité des informations de mapping encore une fois. Pour en revenir à l opérateur AsEnumerable, il s agit d un opérateur réalisant la conversion à la volée. Il s applique à une séquence d éléments et va les encapsuler dans une nouvelle séquence d objets implémentant IEnumerable<T>. Cet opérateur peut être redéfini, offrant ainsi la possibilité de créer des variantes adaptées au contexte. En ce qui concerne les performances, la question est de mettre en balance ce que Linq apporte et les délais introduits. Le mapping est réalisé par le DataSet lui-même et des instructions explicites au niveau du code. Aucune logique de mapping automatique ne vient alourdir l usage classique d un DataSet. Les performances en termes de temps de réponses seront fonction du contexte et non du choix d avoir ou non utilisé Linq. Notons tout de même que l utilisation de telles structures n est pas toujours aisée et en particulier traduire une requête en langage naturel devrait être beaucoup plus simple en utilisant Linq. Avec Linq to DataSet, nous avons une solution portable vers tout type de base de données et même vers d autres systèmes de persistance car, rappelons-le, un DataSet représente simplement une collection de données. Cela permet d utiliser le confort lié aux requêtes de Linq, certes, mais Linq to DataSet demande pas mal de réglages de la part du développeur, notamment d assurer le suivi entre le DataSet et la base de données. Il s agit là d un inconvénient majeur puisque cela peut amener des problèmes liés à la synchronisation ainsi que toute la panoplie d erreurs classiques liées à l accès aux données en Sql. Ceci ne constitue pas alternative à Linq to Sql mais plutôt comme un complément pour répondre aux besoins des développeurs ayant choisi de manipuler des DataSets ou ayant à maintenir des applications qui en font toujours usage. [4] maintient que «les DataSets sont une composante importante de la couche ADO.NET», ce qui fait de Linq to DataSet un outil appréciable. 4.4 Linq to Entities Une autre implémentation ayant pour cible des données relationnelles s appelle Linq to Entities. Le terme Entities dans son nom fait référence à la technologie Entity Framework, qui est une évolution de la couche ADO.NET que nous appellerons par raccourci EF. EF est légèrement plus récent encore que Linq. Nous allons brièvement introduire les idées fondatrices de cette technologie ainsi que ses principaux concepts. Nous tenterons ensuite de mettre en lumière les forces et faiblesses de ce framework, tout en particularisant cela aux contributions de Linq to Entities. Cette section puise ses informations principalement de [5] pour EF et de [1] pour Linq to Entities Concepts fondateurs L idée au départ de l EF est celle-là même qui a amené Linq. Nous pourrions résumer cette idée de base en «une application orientée objet ne devrait pas dépendre des mécanismes de persistance». Nous n allons pas expliquer à nouveau le problème de correspondance entre l orienté objet et le relationnel mais nous allons plutôt ce problème dans le contexte de la deuxième édition du framework.net. A cette époque pas si lointaine d ailleurs, les accès relationnels se faisaient en utilisant les services de la couche ADO.NET, elle-même une évolution des premiers services ADO (ADO signifie ActiveX Data Object). Cette nouvelle couche apportait son lot de nouveautés, parmi lesquelles l interface IDbConnection, qui permettait de considérer une connexion générique à une

41 base de données. Chaque fournisseur de données (il faut comprendre par là tant MySql que Oracle ou Sql Server) implémentait cette interface au sein d une classe concrète nommée client (MySqlClient, OracleClient ). De même, la lecture des données se faisait en remplissant un DataSet pouvant lui-même garder une structure très proche des tables relationnelles de la source. Pour en revenir à l idée énoncée plus haut, une application de l époque dépendait de la nature de la source de données en ce qui concernait la construction du DataSet et l instanciation de la connexion. La dépendance envers la source en elle-même et non son type est localisée au niveau des requêtes Sql qui imposent de nommer les tables et attributs relationnels. Un changement dans la structure des tables ou dans le type de la base de données imposent de réécrire tout le code responsable de la connexion à la base de données et de la construction du DataSet. Selon les cas, il pouvait être nécessaire de réécrire également certaines requêtes, en particulier lorsque les dialectes Sql parlés par l ancienne et la nouvelle source ne coïncidaient pas. Reprenons l idée de départ mais transformons-la en une nouvelle formulation dont le sens global sera identique à celui de la première : «Une application orientée objet devrait pouvoir utiliser la logique conceptuelle des données en faisant abstraction de son mode de stockage». Avec la version 2 du framework, il n est pas possible d utiliser la logique telle qu elle serait définie dans un modèle conceptuel entitésrelations, nous sommes condamnés à utiliser les tables telles que définies dans la base de données. De même, il n est pas possible de vérifier entièrement la logique dès que celle-ci interagit un temps soit peu avec du code Sql. L Entity Framework a été créé pour résoudre ces problèmes et se présente comme une couche ajoutée par-dessus les mécanismes ADO.NET classiques. Manipuler des entités conceptuelles sans directement agir sur la base de données, nous pouvons en effet comprendre que ce concept est similaire à celui de Linq. Là où Linq propose une syntaxe unifiée pour les requêtes, EF propose un accès conceptuel aux données défini indépendamment de la base de données Fonctionnement Commençons par préciser quelques termes de vocabulaires et mettons-les en rapport avec la réalité concrète du moins aussi concrète que peut être la réalité des accès aux données. Sans entrer dans toutes les spécificités techniques, nous tenterons de mettre en lumière qui sont les principaux acteurs de cet Entity Framework et quel est leur rôle. Service objet est le terme officiel utiliser par Microsoft [5][1] pour décrire l action d EF. Les données relationnelles n ont pas changé, elles sont rendues disponibles en tant qu objets. C est ainsi que peut être perçu le concept de service objet. Il est important de comprendre qu il s agit bien d un service et donc d une couche supplémentaire posée sur la pile des mécanismes ADO.NET. Une entité au sens d EF est un concept décrit dans une modélisation entités-relations. Microsoft les décrit parfois sous le nom de data object, littéralement objet donnée. Il s agit donc de classes qui vont jouer un rôle similaire à celui des entités au sens de Linq. Les entités d EF regroupent des données pouvant se retrouver sur plusieurs tables relationnelles et en termes relationnels, ce qui approchent le plus de ces entités, ce sont les vues. Il est important de noter que les entités sont mappées aux données relationnelles mais cette correspondance n associe aucune ressource directement aux entités. Cela pourrait se résumer de cette manière : les entités sont les objets métiers qui décrivent la logique de l application et lorsqu on en vient à parler de la persistance, le mapping permet aux entités de savoir où aller regarder.

42 Une relation est un lien entre deux entités ou plus. Il s agit là des mêmes concepts que ceux présents dans le fameux schéma entités-relations. Une relation peut être de diverses multiplicités : un à un, un à plusieurs ou plusieurs à plusieurs. Une relation peut elle-même posséder des attributs et est donc représentée par une classe. Un objet contexte, ou context object en Anglais, est le terme pour désigner la classe en charge de la gestion du modèle. La classe ou plutôt un de ses objets. Ce rôle s apparente fort à celui du DataContext de Linq to Sql et cet objet contexte gère à la fois le mapping et les instanciations d entités et de relations. Un seul objet contexte peut exister pour un modèle donné. Il intercepte toutes les demandes, qu elles soient faites aux entités, aux relations ou au modèle lui-même. L objet contexte est le point d entrée de la couche des services objets (c est ainsi qu il est présenté dans la documentation officielle fournie par Microsoft [5]). Le modèle de données, appelé Entity Data Model ou EDM par Microsoft, regroupe les entités et leurs relations. C est en quelque sorte un schéma entités-relations mais les données peuvent y être spécifiées déjà finement, notamment au niveau des types. Ce modèle peut être créé depuis une base de données disposant d un schéma entités-relations. Il peut également être créé à la main ou depuis la structure de tables relationnelles d une base de données. Dans tous les cas, des modifications sont toujours possibles à postériori. Le fonctionnement général d EF est le suivant : l application utilise des concepts dont la forme correspond à la logique de l application. Cet assemblage d objets est manipulé directement en mémoire et aucune interférence due à la couche relationnelle n a lieu à ce niveau. Il n y a que les entités et relations ayant un rôle à jouer qui sont instanciées, les autres disparaissent dès leur rôle terminé. L objet contexte ne maintient que le minimum d objets nécessaires. Lorsque ceux-ci nécessitent un rafraîchissement ou lorsqu ils font l objet d une demande d écriture, l objet contexte va utiliser les informations de mapping à sa disposition pour créer les commandes Sql appropriées. Sql étant devenu standard (ou presque), la seule question délicate est de gérer l accès direct aux données. Là et seulement là, le mapping contient des informations qui seront dépendantes de la nature de la base de données. Ces informations sont utilisées pour créer des connexions et des commandes avec la couche ADO.NET classique, c est-à-dire telle qu elle permet déjà de le faire depuis la version 2 du framework.net. Un changement du mode de stockage des données impose de seulement changer quelques lignes au niveau du mapping. Les informations de structure pouvant être utilisée pour recréer des tables relationnelles en correspondance avec le mapping actuel. Voici le principe de l Entity Framework Mapping Le mapping est réalisé de manière distribuée, dans le sens où plusieurs fichiers y participent, chacun apportant des informations différentes. Sans entrer dans les détails de leur syntaxe, un premier fichier représente la structure des entités et relations, un deuxième fichier représente la structure des données au niveau de la source relationnelle et le troisième fichier fait la correspondance entre les deux [5]. Ceci se fait (presque) indépendamment de la nature de la base de données et la structure de cette dernière peut être récupérée ou recréée à l envie. A l envie signifie dans la limite où ce type de base de données est supporté par EF sans quoi ces étapes doivent être faites à la main. Ceci est d autant plus intéressant que le développeur n a pratiquement aucune ligne de code à écrire pour réaliser ce fameux mapping, un éditeur de modèle EDM graphique est fourni avec EF.

43 4.4.4 Rôle de Linq En plus de tous ces mécanismes, Linq propose une implémentation ayant pour cible l EF, nommée Linq to Entities. L EF disposant de son propre moteur de requêtes, Linq se présente comme une syntaxe unifiée, qui resterait valable que l on ait recours à l EF ou non. Tant les requêtes Linq que celles de l EF utilisent les services objets, aucune des deux alternatives n est réellement plus rapide que l autre 12 [1][5]. Précisons toutefois que les requêtes EF sont écrites dans un langage proche du Sql nommé Entity Sql, ce qui laisse apparaître du code non vérifiable à la compilation, ce que Linq permet justement d éviter. De plus, nous pouvons faire la même remarque que celle faite lorsque nous parlions de l implémentation objet : Linq propose un formalisme de requêtes nettement plus lisible et plus compact. La difficulté de la mise en œuvre d une application Linq to Entities tient davantage à la construction du modèle de données qu à la mise en place des requêtes. C est pourquoi nous ne ferons pas mention d exemple dans cette section, la syntaxe Linq restant inchangée. Signalons tout de même que certains opérateurs sont à manier avec prudence, en particulier les opérateurs d agrégation personnalisés qui peuvent ne pas être supportés, en toute généralité, par le gestionnaire de bases de données. 4.5 Db Linq Il s agit ici d une implémentation particulière, dans le sens où elle n émane pas directement de Microsoft mais d une équipe mixte, regroupant des développeurs de Microsoft et d autres contributeurs indépendants. Son nom est d ailleurs toujours un nom de code et non une désignation standard «Linq to something». Cette implémentation, résumée en une phrase, a pour but de faire comme Linq to Sql mais mieux que Linq to Sql. La plupart des informations la concernant sont disponibles sur [4] mais tout est rassemblé sur le site du projet en lui-même [14]. En effet, cette implémentation se base sur l API de Linq to Sql mais intègre d autres types de bases de données que Sql Server. Citons parmi eux MySql, Oracle et PostGreSql qui sont probablement les plus célèbres. Pas grand-chose à ajouter sur cette implémentation, si ce n est qu elle est toujours en développement. La dernière release est la version 0.20 datée du 16 avril 2010, ce qui en fait la plus récente à l heure d écrire ce paragraphe. Microsoft ne semble pas vouloir intégrer cette implémentation dans les librairies standards, pour une raison indéterminée. Même si tous les outils de génération de code disponibles pour Linq to Sql n ont pas d équivalents pour Db Linq, se contraindre à Sql Server semble peu judicieux. Nous reparlerons plus loin du projet Mono qui a choisi quant à lui la solution Db Linq [14][15]. 12 Il est d ailleurs possible d écrire des requêtes Entity Sql avec Linq en utilisant les objets ObjectQuery<Entity>.

44 Chapitre 5 : Implémentation Xml Le recours à des bases de données Xml s est fortement répandu ces dernières années et tout naturellement Linq propose une implémentation pour interagir avec ces structures. Xml est cependant une technologie difficile à interfacer avec les langages orientés objet, en particulier lorsque ceux-ci désirent créer du contenu Xml. L approche classique utilise DOM 13 qui oblige à créer l ensemble des éléments avant de les rassembler. Linq to Xml propose une nouvelle syntaxe pour créer du contenu Xml, la construction fonctionnelle. Elle permet de créer les éléments selon une structure hiérarchique beaucoup plus compacte. Cette syntaxe est encore plus évidente dès lors que nous utilisons Visual Basic 2008, car ce dernier a introduit dans sa dernière version les littéraux Xml. Avec cela nous pouvons écrire directement le code en Xml, comme dans l exemple cidessous (inspiré de [1]) où nous créons un étudiant : Dim exemplexml As XDocument = _ <?xml version="1.0" encoding="utf-16" standalone="yes"?> <etudiant matricule="023951"> <nom>schoonenbergh</nom> <faculte>ecole polytechnique</faculte> <annee>ma2</annee> <adresse> <rue>kleine Daalstraat</rue> <numero>79</numero> <cp>1930</cp> <localite>zaventem</localite> </adresse> </etudiant> Linq to Xml a été pensé pour manipuler du Xml tel que défini par le W3C 14, c'est-à-dire pour manipuler directement du contenu Xml sans passer par un intermédiaire. Cela permet d interagir avec de telles structures tout en restant dans un paradigme objet. La construction fonctionnelle est supportée par l assemblage System.Xml.Linq et peut être utilisée même sans recours direct à Linq. Plusieurs classes sont définies pour représenter les éléments structurels du langage Xml, citons parmi elles quelques exemples intéressants. La classe XObject tout d abord qui est la classe de base pour représenter n importe quel objet Xml. Cette classe propose des méthodes qui représentent toute la gestion structurelle de l arbre Xml qui sera créé en mémoire. Des méthodes telles que AddBeforeSelf ou AddAfterSelf permettent ainsi d ajouter un élément à un endroit précis de l arbre. Cette classe supporte également l annotation Xml. La classe XStreamingElement contient un arbre d objets IEnumerable<T> et peuvent donc faire l objet de requête. Les objets de cette classe réalisent l exécution différée des requêtes chargeant partiellement le résultat, ce qui permet de mieux doser la quantité d objets chargés en mémoire, bien utile dans une optique de performance. Parlons enfin de la classe XDocument représentant un document Xml. Les objets de cette classe n ont pas besoin de références à un fichier pour être instanciés. Ils sont créés selon le pattern Factory et peuvent être associés dans le futur à une référence (ou une URI) qui les reliera directement à du contenu existant, le cas échéant. 13 DOM signifie Document Object Model. Il s agit d un ensemble de règles définissant les premières structures Xml. 14 World Wide Web Consortium ; organisme de standardisation des technologies web.

45 Une particularité de l implémentation Xml est que les résultats restent valables même si la source de données est déconnectée. Ce qui veut dire que les entités présentes dans un résultat ne seront resynchronisées que si la demande explicite leur parvient. Il est également possible d imaginer l exécution d une requête sur un document Xml particulier, récupérer ensuite le résultat et ré exécuter la même requête sur un fichier différent (celui-ci devra vraisemblablement avoir une structure très similaire au premier). Une autre possibilité d utilisation de cette propriété est qu il est très facile d utiliser un résultat issu d une source de données relationnelle pour effectuer une requête sur une structure Xml. Les entités Linq to Sql par exemple se resynchronisent périodiquement mais ce n est pas le cas du Xml. Les deux implémentations étant indépendantes, il ne pose aucun problème d utiliser l une de ces sources de données pour supporter une requête sur l autre. Par exemple, nous pourrions extraire d un fichier Xml tous les étudiants inscrits dans chaque faculté et ensuite pour chacun de ces étudiants, faire une requête en base de données relationnelle pour obtenir ses informations personnelles.

46 Chapitre 6 : En pratique 6.1 Ressenti général Après ce vaste tour d horizon de Linq, il est temps de prendre un peu de recul et de faire le point sur ce que nous pouvons en retirer. Qu a apporté cette étude? Voila une question qu il est bon de se poser. La découverte de Linq s est faite depuis les bases, tout comme ce fut relaté dans ce rapport. Nous avons introduit un ensemble de mécanismes fondateurs avant de décortiquer les différentes implémentations proposées par Linq. L exploration de ces diverses implémentations et la mise en œuvre de cas concrets se sont avérés parfois surprenants, révélant des comportements inattendus (cf tests de performance pour Linq to Sql) ou au contraire des avantages conséquents (comme pour l exemple de l implémentation objet). La méthode appliquée tout au long de cette étude a été de partir des bases théoriques en allant progressivement vers des considérations de plus en plus en phase avec la réalité concrète. Bien qu il soit tentant d explorer encore et encore certaines options, nous nous sommes efforcés de nous en tenir au sujet initial qui ne concerne que Linq. Des ouvertures vers des technologies passionnantes comme l Entity Framework ont été tentées mais les essais et explications sont restés centrés sur Linq. La plus grande difficulté rencontrée durant cette étude concerne la disponibilité de la documentation. En effet, Linq était partie intégrante d une solution propriétaire, une très large majorité des informations techniques est concentrée sur le site officiel de Microsoft ou dans des livres édités par Microsoft Press. Certains sujets sont encore mal documentés du fait de leur jeunesse et de leurs rapides mutations. Un des problèmes rencontrés à ce sujet fut d avoir accès à des explications tronquées, certaines parties étant apparemment considérées comme triviales. Lorsque ce n est pas l avis du lecteur, c est rapidement problématique pour ce dernier. De même, certains sujets très récents comme l Entity Framework ne proposent que des informations fragmentaires et parfois contradictoires, le plus souvent à cause de changements survenus durant la version beta non répercutés dans la documentation. Heureusement la communauté qui soutient le développement.net est nombreuse et les accès en avant-première à certaines technologies encore en développement permettent à certains spécialistes de rédiger des explications complémentaires souvent utiles (il s agit des sources *13+ et *6+ principalement). Ce passage est également l occasion de remercier tous ces contributeurs pour leur travail et leur dévouement. Proposant généralement des informations dispersées sur des blogs ou des forums communautaires, ils sont parfois auteurs d une simple phrase permettant le déclic. Leurs interventions sont aussi l occasion d offrir un point de vue différent de l omniprésent Microsoft. Dans la documentation officielle, tout semble toujours simple et harmonieux. Plusieurs retours d expérience ont également permis d adopter une vision plus objective sur l ensemble des sujets abordés. 6.2 Points forts, points faibles La première remarque qui s impose après ce que nous avons vu, c est de se dire que Linq permet d écrire du code beaucoup plus simplement. Les requêtes y sont écrites dans un langage plus proche du langage naturel et les erreurs sont détectées à la compilation. Durant les différents tests réalisés préalablement à l écriture de ce rapport, le temps nécessaire à l écriture de requêtes Sql a été constaté comme étant entre deux et trois fois supérieur au temps requis pour produire des requêtes Linq équivalentes (est compris dans ces mesures le temps consacré à l écriture des requêtes et à leur débogage). En termes de productivité, Linq constitue déjà une avancée majeure. Au-delà de ce gain de performances humaines, Linq améliore la maintenabilité d un code car il est plus lisible d une part

47 et plus abstrait vis-à-vis des données d autre part. En termes de performances machines, seules certaines implémentations en pâtissent, en particulier Linq to Sql. Les autres implémentations ne rajoutent que peu de choses entre le code et la gestion du stockage des données, ceci n influence donc que légèrement sur les performances. Les possibilités d optimisation sont également plus visibles pour Linq qu en ce qui concerne la couche ADO.NET où une connaissance des subtilités est souvent nécessaire. Ceci n est nullement le fruit d une mesure cependant, simplement une impression personnelle partagée par divers interlocuteurs rencontrés sur des sites internet spécialisés. Bien qu il ne s agisse pas d une réelle information, cette tendance semble montrer que l utilisation de Linq continuera de se répandre tant qu il sera question de requêtes sur des données relationnelles. Les techniques d accès aux données relationnelles datant de la deuxième version du framework.net sont sans comparaison avec le confort offert par Linq. Mais si nous nous plaçons dans une optique de continuité, l arrivée de Linq ne signifie nullement l abandon de la couche ADO.NET. Certes manipuler la couche d accès aux données signifie utiliser un autre langage avec tous les désagréments que cela comporte, mais Linq est une alternative nouvelle. La plupart des développeurs chargés d écrire des requêtes ont probablement toujours une bonne connaissance du Sql et des bases de données en général. Linq est très plaisant du point de vue du débutant mais certaines personnes décrient son utilisation abusive, arguant du fait que son utilisation à outrance finira par provoquer l oubli des mécanismes subtils pour accéder aux données [13]. Ne plus être conscient de la cuisine interne réalisée par les outils de génération de code peut certes s avérer dangereux, mais est-ce vraiment ce à quoi nous risquons d arriver? Probablement pas, car les bases de données en elles-mêmes sont toujours la solution numéro un dans le monde de la persistance et ces bases de données se doivent d être gérées et maintenues par des experts. Des spécialistes du relationnels pour qui les requêtes ne sont qu une toute petite partie de ce que peut réaliser une base de données. Créer des procédures stockées, des déclencheurs (triggers) et ce genre de choses, cela aura toujours son lot d artisans œuvrant avec des lignes de commandes bien loin de Linq et de ses interfaces graphiques. Linq se présente comme le compagnon idéal du développeur d application qui souhaite ne pas être entravé par la présence des mécanismes de persistance. La couche ADO.NET restera de toute façon utilisée en arrière-plan pour réaliser les dialogues intimes avec les bases de données. Linq est donc probablement plus un complément qu un concurrent pour ADO.NET. Il est néanmoins dommage que des implémentations comme Db Linq ne soient pas plus soutenues par Microsoft, mais cela sera peut-être amené à changer. Si nous sortons du seul point de vue relationnel, Linq permet avant tout de manipuler des données sans se préoccuper de savoir d où elles viennent. C est à la fois une force et une faiblesse. La force est d augmenter l abstraction du code vis-à-vis du stockage, ce qui est vital nous ne le répèterons jamais assez. La faiblesse est qu il devient beaucoup plus facile de commettre des erreurs par ignorance. Ainsi une persistance assurée par plusieurs bases de données redondantes permettra des réponses rapides, mais un même code pourra s avérer problématique s il prend pour cible un unique fichier Xml de très grande taille. Il faut rester conscient qu utiliser Linq ne sera pas systématiquement une bonne chose et devra toujours être attentivement examiné. Linq dans son ensemble commence à atteindre la maturité nécessaire pour s attirer la confiance des développeurs, son utilisation va sans doute devenir généralisée dans le monde.net.

48 6.3 Quelles alternatives Comme nous l avions précédemment fait remarquer, le problème de la dépendance par rapport au stockage des données n est pas nouveau. Linq y apporte sa contribution et nous avons résumé les principales techniques qui étaient utilisées à l époque de la deuxième version de.net. Mais qu en est-il des autres langages?.net n a pas le monopole de l orienté objet et Linq est résolument lié au framework. Il est impensable qu un langage orienté objet tel que Java n ait pas développé de solutions de son crû pour tenter de créer davantage d abstraction vis-à-vis de la couche de persistance des données. Nous allons maintenant nous pencher sur différentes technologies et leurs points communs avec Linq Java Java reste une pointure dans le domaine des langages de programmation orientés objet. En perpétuelle concurrence avec son grand rival.net, leurs évolutions respectives se sont toujours plus ou moins suivies de près. Ainsi, les accès aux données relationnelles se faisaient via un pilote Odbc 15 en C# 2.0 et Java 5 faisait de même avec Jdbc, pour sa part. Voyons maintenant quelles sont les solutions actuellement proposées pour réaliser une persistance abstraite en Java JDO Les paragraphes consacrés à l étude de JDO sont presqu entièrement inspirés de *8+ et de la documentation qui s y trouve. JDO est l acronyme désignant Java Data Object. Il s agit d une librairie, plus exactement d une API, standard pour réaliser la persistance des objets. La première version de JDO est apparue en 2002 et la seconde version est disponible depuis Comme presque tout ce qui concerne Java, cette librairie est open source. La version 2.1 appelée aussi Apache JDO est toujours en cours de développement à l heure où ces lignes sont écrites. Cette librairie est décrite comme supportant tout type de stockage et représentant les données stockées à l aide de POJO (Plain Old Java Object), ce qui pourrait se traduire par de bons vieux objets Java. JDO se décline en plusieurs interfaces, comme le fait Linq, et ces implémentations permettent d utiliser différents stockages de données parmi lesquels des bases de données relationnelles, objet ou Xml, un système de fichiers ou même certains stockages plus exotiques comme les bases de données Big Table de Google 16. JDO présente la persistance du point de vue du développeur objet, de manière transparente. Pour décrire brièvement les classes qui entrent en jeu, nous avons un gestionnaire de persistance, des requêtes et des transactions. Le gestionnaire est responsable de la maintenance des instances de persistance qui ne sont en fait que l équivalent des entités en mémoire au sens de Linq. Le gestionnaire est également chargé d exécuter les requêtes et transactions qui lui sont passées. Le principe est, sur le fond, très similaire à Linq to Sql : nous avons un gestionnaire de contexte qui gère des entités persistantes. Pour interroger les sources de données, JDO a recours à un langage qui lui est propre, le langage JDOQL. Cet acronyme est l abréviation de Java Data Object (JDO) Query Language et n est pas directement lié à OQL comme nous pourrions l imaginer. Il est intéressant de noter que ce langage propose deux syntaxes alternatives, la syntaxe dite déclarative et celle dite du Single String. Pour ne pas trop nous perdre dans l analyse de toutes les possibilités syntaxiques, nous allons simplement examiner cela avec un exemple tiré du site officiel du projet Apache JDO [8], situé page suivante. 15 Il existe d autres pilotes plus anciens, odbc était le dernier en date lors de la release de C# Ceci est mentionné à l adresse suivante :

49 Declarative JDOQL : Query query = pm.newquery(mydomain.product.class,"price < limit"); query.declareparameters("double limit"); query.setordering("price ascending"); List results = (List)query.execute(150.00); Single-String JDOQL : Query query = pm.newquery("select FROM mydomain.product WHERE " + "price < limit PARAMETERS double limit ORDER BY price ASCENDING"); List results = (List)query.execute(150.00); Pour bien comprendre l exemple ci-dessus, précisons que l objet nommé pm désigne le gestionnaire de persistance qui est le point de passage obligé pour toute requête ou transaction effectuée sur ses données. Cette manière de procéder est différente de celle de Linq. JDO considère une requête comme un objet qui sera traité de manière centralisé alors que nous avons vu que Linq adresse ses requêtes directement sur les collections de données. Le recours au gestionnaire n avait lieu que lorsqu une opération générale était nécessaire, comme dans le cas du SubmitChanges que nous avions abordé dans la partie sur les implémentations relationnelles. En ce qui concerne le mapping, il est réalisé à la fois par des dénominations explicites dans le code et par un fichier Xml. Au niveau du code, les informations ajoutées servent à avertir les objets s ils doivent ou non s occuper de leur persistance ou de celle de leurs attributs. En ce qui concerne le fichier Xml, les informations spécifient quelle classe est la représentation de quelles données et où trouver ces dernières. Diverses autres informations participent au mapping mais nous ne les détaillerons pas ici. L important est de constater que le mapping se fait au niveau du code avec des indications qui permettent de savoir comment gérer les objets persistants et aussi avec un fichier de correspondance qui indique quel attribut correspond à quelle donnée enregistrée. La seule différence notable entre Linq et JDO en ce qui concerne le mapping, c est que Linq tente d encore faciliter la tâche du développeur avec l intégration d éditeurs graphiques Hibernate Une grande partie des informations relatives à Hibernate provient de [16]. Hibernate a été conçu à l origine pour simplifier la persistance d objets dans des bases de données relationnelles. Ses fonctionnalités se sont quelque peu élargies mais Hibernate reste un outil cantonné au domaine du relationnel. Son rôle est d offrir un mapping objet relationnel plus aisé que lorsqu il est réalisé à la main avec la technologie Jdbc. Hibernate gère les mécanismes de persistance, c est-à-dire les enregistrements et chargements depuis la base de données, mais il laisse le développeur écrire des requêtes dans le langage de son choix parmi lesquels le langage propre à Hibernate (HQL), le langage générique de l interface de persistance implémentée par Hibernate 17 (JPQL) ou directement en Sql. Là où Linq fait figure de canif suisse intégrant de multiples possibilités via un outil passe-partout, Hibernate est la boîte à outils du développeur désireux d avoir le choix des armes. A noter que Hibernate est souvent considéré comme une solution à n utiliser que lorsque la situation est adaptée [13] 18. Alors que Linq se veut être une solution flexible, avec abstraction du stockage, 17 Il s agit en réalité d une interface définie dans la librairie JPA, mais par abus de langage nous dirons que l interface implémentée est JPA. JPA signifie Java Persistence API. 18 Il s agit là d interventions non officielles mais néanmoins non(ou très peu) démenties par la communauté*13+

50 Hibernate est un choix lié au monde relationnel offrant un ensemble de fonctionnalités pas toujours aisées à maîtriser. Précisons tout de même qu Hibernate est bien plus ancien que Linq, puisque sa création remonte à Bien que les interfaces JPA aient été créées pour englober plusieurs utilitaires de persistance dont Hibernate, ce dernier reste davantage un ORM qu une solution intégrée au langage. De manière générale, le rôle des implémentations de JPA reste borné à effectuer une persistance plus simple lorsque les données sont stockées sous forme relationnelle NET Bien que Linq y soit récent et que, au contraire de Java, ce langage ne s enrichisse pas directement sur la base d une communauté de contributeurs,.net et C# en particulier proposent d autres alternatives pour réaliser la persistance des données sans passer par toute la panoplie des commandes ADO.NET. Les autres méthodes que nous allons aborder sont, de manière générale, destinées à un autre public que celui prévu pour Linq NHibernate Comme son nom l indique, il s agit là d une version d Hibernate adaptée au langage C# (le N est une abréviation courante en préfixe d une technologie pour signifier qu elle s applique à.net). Les informations relatives à NHibernate émanent de [17]. Le cœur d Hibernate a été porté vers.net et son utilisation a été quelque peu adaptée pour mieux répondre aux attentes des développeurs.net. Cet outil a été développé par la même équipe que celle en charge de la version Java. De par sa structure et son mode de fonctionnement, il s agit encore une fois d un ORM qui vient se greffer sur une architecture déjà existante, celle de l incontournable couche ADO.NET. NHibernate est présenté comme une solution mature, capable de réaliser la correspondance objet relationnel de manière transparente pour le développeur. NHibernate répond à une demande particulière : ne pas être limité par l ORM en étant sûr que, de toute façon, les données seront sauvées dans une base de données relationnelle. Il s agit là d une optique quelque peu hors des objectifs de Linq qui souhaite créer une abstraction avec le stockage tout en mettant davantage en avant la facilité de mise en œuvre. A noter que depuis peu, NHibernate propose un module complémentaire Linq to NHibernate permettant d utiliser la syntaxe Linq pour réaliser des requêtes avec NHibernate [18] Entity Framework Voici une figure connue, les informations à son sujet sont toujours majoritairement issues de [5]. L Entity Framework, que nous avions brièvement introduit dans la section Linq to Entities, est lui aussi en soi une alternative à Linq. Il serait mieux de parler de complémentarité entre ces deux outils que de concurrence, néanmoins il reste possible d utiliser l un sans l autre. L Entity Framework permet essentiellement deux choses : choisir la forme des entités à manipuler et automatiser toute la cuisine interne nécessaire pour pouvoir fournir des entités personnalisées de manière efficace. Comme nous l avions vu, cela ajoute également un niveau d abstraction vis-à-vis de la base de données, car le code manipulant les entités est bien séparé des manipulations relationnelles. Linq apporte quant à lui la puissance et la simplicité d utilisation de son langage de requêtes. L Entity Framework a donc pour vocation d aider à définir la «business logic» de l application sans entrave de la part du stockage des données, alors que Linq permet de récupérer des éléments précis plus aisément. Il est tout à fait envisageable de vouloir garder la main sur le langage de requêtes car, en effet, celles-ci seront traduites tôt ou tard en Sql. Dans cette optique-là, l utilisation de l Entity Framework se fera sans l aide de Linq. En résumé, si la difficulté se situe au niveau de l architecture du code ou de la jonction entre la logique métier et la couche de persistance des données, Entity

51 Framework est une solution envisageable. Le champ d application de Linq sera plutôt atteint si la difficulté réside dans la capacité à produire ou à vérifier des requêtes vers des données persistantes. Ces outils répondent à des besoins séparés et n entrent pas en concurrence directe Autres langages Nous avons vu un peu ce qui se faisait en Java comme en.net pour mettre en place une aide à la persistance. Ces deux langages sont probablement les porte-drapeaux du paradigme orienté objet et pourtant ils n en sont pas non plus les seuls représentants. Le PHP est très fort présent dans le domaine du développement web et ce domaine fait généralement un usage extensif des moyens de persistance. Nous allons maintenant parcourir des approches plus globales, permettant de nous faire une meilleure idée des types de persistance recherchées et pourquoi. Les paragraphes suivants sont issus de diverses sources, principalement [19],[20] et [21] Persistance personnalisée De nombreux ORM existent sur le marché et ce depuis maintenant quelques années. Les plus connus restent ceux liés à Java et.net. Pourquoi? La première chose qui devrait nous mettre la puce à l oreille est que ces langages sont fortement typés, à l inverse du PHP ou de Python. Il est impératif de connaître le type d une variable avant de pouvoir l utiliser. Or les types sont quelque peu différents lorsque nous passons du monde relationnel à celui des objets, ou vice versa. De même, les grandes applications orientées objet s appuient sur des architectures parfois titanesques et cela entraîne invariablement une complexification structurelle des données à stocker. Les langages comme PHP et Python ont quant à eux une réputation de légèreté et de facilité de mise en œuvre. Vu de cet angle là, la multiplication des utilitaires de persistance pour Java et.net s explique mieux. Leur supériorité numérique également. Nous avons vu le cas de Hibernate et de NHibernate dans les paragraphes précédents, précisons tout de même qu il en existe des dizaines d autres. Il existe malgré tout des ORM pour PHP (Doctrine en est le plus connu) et Python (avec l ORM SQLAlchemy). Ceux-ci sont souvent des versions d ORM utilisés en Java portées vers le langage cible. Des langages comme PHP et.net sont difficilement comparables lorsque le domaine d application est défini, il n est donc pas réellement question de concurrence entre Linq et ces différents outils. Une autre situation qui se généralise de plus en plus est d embarquer sa propre couche de persistance, offrant l abstraction désirée. C est particulièrement vrai pour des outils de conception «tout en un», tels des fournisseurs d ERP (TinyErp s appuie sur du code Python [24]) ou de gestionnaire de contenu CMS lorsqu ils sont développés en PHP ou Python. Les gestionnaires de contenu intègrent souvent la possibilité d insérer du code à plusieurs niveaux, que ce soit lors de la création d une page ou l écriture d un script dont l appel est géré par le CMS. Bien qu il s agisse essentiellement d outils spécialisés dans le développement web, notons que ces solutions intègrent chaque jour plus de fonctionnalités ce qui les approchent très fortement du statut d environnement de développement. Parmi ceux-ci, nous pouvons citer des exemples comme ez Publish [22] ou Drupal [23]. Ces outils de gestion de contenu permettent d insérer du code pratiquement n importe où et constituent en eux-mêmes des outils de développements (tous deux s appuient sur du PHP). Ils ont chacun à leur manière établis une couche de persistance tentant de faire abstraction de la nature de la source de données. Un ensemble de classes prennent en charge les différents types de bases de données et les interactions avec le stockage sont créées à la volée, selon le type de stockage détecté. L abstraction vis-à-vis du support de persistance est une idée similaire à celle de Linq mais les requêtes demeurent écrites en Sql ou en XQuery. Ceci n est pas très surprenant car les langages non

52 typés comme PHP n ont généralement pas recours à une phase de compilation. Dès lors, la vérification syntaxique n a plus de sens. Simplifier l écriture des requêtes pourrait être fait mais gardons en tête que la majorité des applications réalisées avec ces CMS et ERP sont depuis longtemps liées à des bases de données. Pour ces développeurs, il est envisageable que l écriture de requêtes soit un chapitre depuis longtemps maîtrisé, ou du moins avec lequel ils ont établis leurs habitudes Bases de données objets Les bases de données objets sont restées, depuis leur apparition, en marge des autres systèmes de persistance. Certains indices laissent croire qu elles font l objet d un regain d intérêt, spécialement pour des applications légères. Leur gros problème a toujours été de pouvoir justifier le changement de toute une couche de persistance pourtant déjà fonctionnelle [3]. Un tel changement implique une migration des données en plus d une réécriture conséquente des applications qui font usage de la persistance. Une base de données objet constitue un moyen de réaliser physiquement la persistance et non de fournir une aide au programmeur en soi. Bien sûr la syntaxe du langage Oql, permettant d interroger ces bases de données, est très proche des langages orientés objet. Mais elle n est pas réellement intégrée au langage comme l est Linq. Si nous en parlons ici c est pour faire un plus ample lien entre les deux. Plusieurs logiciels de gestion de bases de données orientées objet ont littéralement sauté sur l occasion pour se mettre dans la mouvance de Linq. Ainsi nous pouvons citer db4o qui utilise Linq comme langage de requêtes 19 mais aussi Eloquera, une base de données destinée au multimédia, ou encore Siaqodb 20 qui intègre même un éditeur de requêtes pour Linq. L écriture de requêtes avec Linq se fait déjà dans une optique orientée objet, que des bases de données objet tentent de s aligner dessus n est finalement pas surprenant. Est-ce que Linq contribuera à donner un second souffle aux bases de données orientées objet? L avenir nous le dira. 19 Information vue sur 20 Information vue sur

53 6.4 Evolutions de Linq Nous allons maintenant parler d avenir. De ce qui est en projets, en développement et de ce qui pourrait le devenir. Microsoft a montré sa volonté d avancer dans le domaine de la gestion des données persistantes mais bien des choses restent à faire Version 4 La quatrième version du framework.net est en phase de beta test au moment où sont rédigées ces lignes. Lors d une annonce faite le 28 octobre , l équipe en charge du développement de Linq précisait que Linq to Sql serait désormais considéré comme une moins prioritaire, tous les efforts étant dirigés vers Linq to Entities. Ceci en raison de sa capacité à s adapter à de plus nombreux types de bases de données relationnelles. Linq to Sql n a pas été abandonné pour autant, mais les changements annoncés ressemblent plus à un planning de résolutions de bogues qu à la mise en place d une évolution. Linq to Entities quant à lui semble avoir le vent en poupe, tout comme son compagnon l Entity Framework. Des améliorations concernant l ergonomie d utilisation et des possibilités étendues comme la création d une base de données depuis un modèle édité graphiquement sont actuellement déployées dans la version en test du framework et de Visual Studio Quelques changements précieux comme la capacité de «self tracking» des objets entités vont encore alléger la charge du développeur. En ce qui concerne strictement Linq, les améliorations concernent la flexibilité d utilisation en offrant davantage de réglages optionnels. Leur mise en pratique semble encore un peu floue et les informations obtenues sont parfois contradictoires, il est donc dur d être précis. Ce qui est sûr c est que Linq to Entities continuera son petit bonhomme de chemin. En ce qui concerne les autres implémentations de Linq il n y a pas grand-chose à signaler. Les changements apportés par la version 4 22 semblent surtout tenir de la correction Ce qui reste à améliorer Le passage par l Entity Framework résout en partie le problème posé par Linq to Sql et sa non portabilité vers d autres bases de données que Sql Server. Tant qu il y aura des options non proposées par Linq, son utilisation restera l objet d un compromis. La synchronisation des entités n est par exemple pas toujours évidente et les mappings auto-générés offrent toujours le risque que les mécanismes cachés soient mal compris. Ces fonctionnalités feront sans doute l objet d améliorations progressives mais pour l heure nous ne pouvons qu espérer. Il est bon de noter que Microsoft et l équipe ADO.NET en particulier essaient de se montrer comme étant à l écoute du développeur, précisant régulièrement que les retours de la communauté seront pris en compte. Malgré cela, plusieurs implémentations de Linq comme Linq to NHibernate citée précédemment ne sont pas suivies par Microsoft. Bien que cela puisse paraître normal puisqu ils n en sont pas les auteurs, cela laisse le risque qu une modification des spécifications de Linq vienne mettre hors jeu ces implémentations extérieures. Bien sûr ce risque existe pour de nombreuses technologies, mais l évolution de Linq semble encore hésitante, parlant tantôt d ajouter telle fonctionnalité, tantôt de laisser tomber telle autre, livrant les informations officielles au tout dernier moment. Ce qui nous amène à parler d une amélioration plus que souhaitable, celle concernant la documentation. En dehors de certains ouvrages, l ensemble de la documentation sur Linq se trouve en ligne, sur le site Consulter à ce sujet :

54 de la bibliothèque MSDN. Les livres deviennent rapidement dépassés, constituant rapidement des sources d informations obsolètes et parfois dangereuses. La documentation en ligne est dispersée et ne propose pas la même visibilité que celle de l API de Java. Cela amène rapidement à devoir récolter des informations morcelées et de tenter de les mettre soi-même en place. Le but de cette étude était d explorer et de tester, ce qui fait que les miettes d informations ne constituaient pas réellement un problème dans la mesure où des tests étaient faits de toute façon. Pour une application professionnelle en revanche, jouer à la devinette est à déconseiller. Une meilleure présentation de la documentation y constituerait une aide précieuse Linq et Mono Avant de faire le point sur ce tour d horizon de Linq, il nous reste un dernier point à traiter qui est celui du projet Mono. Le projet Mono consiste à porter les spécifications du framework.net vers les plateformes Linux. La version actuelle de Mono est la 2.6, sortie le 14 décembre L ensemble de cette section tire ses informations de [15] et de [14] en ce qui concerne Db Linq. Elle intègre, parmi d autres nouveautés, les fonctionnalités Linq to Sql avec quelques variantes. Il s agit en réalité de l implémentation Db Linq partageant une partie de l API de Linq to Sql. La plus importante différence est que la version Mono de Linq to Sql n est pas limitée à Sql Server mais permet de gérer des fournisseurs de données comme FireBird, MySql, PostGreSql, Ingres, Oracle et SqlLite [14]. [15] précise que «La totalité du code n est pas encore portée», il est par exemple signalé que le support de l assemblage System.Data.Linq n est pas total. Cet assemblage contient la définition des entités et l ensemble des extensions de méthode. Il est amusant de constater que Linq avec Mono est plus polyvalent que dans sa version Microsoft qui, pour une raison mystérieuse, ne semble pas vouloir soutenir activement l implémentation Db Linq. Notons que le projet Mono est développé en partenariat avec les équipes Microsoft et qu un tel échange devrait pourtant être possible. Affaire à suivre. Bien que n offrant qu une implémentation, Mono permet d utiliser Linq avec des bases de données relationnelles. Ceci donne une dimension supplémentaire à Linq, qui devient une solution beaucoup plus portable. L abstraction vis-à-vis du stockage des données est une chose, la réutilisabilité d un code en est une autre. Avec le support de Mono, Linq devient un choix viable dans un contexte multi plateformes, ce qui permet de concurrencer les solutions «à la Java».

55 Conclusion Nous avons vu quels étaient les mécanismes permettant au langage d implémenter les bases de Linq. Ces mécanismes sont pour la plupart des évolutions de ce qui était proposé dans le deuxième framework.net. Partis de ces bases théoriques, nous avons découvert le formalisme de requêtes proposé par Linq, formalisme proposant une syntaxe unifiée pour toutes les implémentations. Linq se décline en une série d implémentations, chacune destinée à des types de données particuliers. L implémentation objet a d abord été abordée, en détaillant les opérateurs jugés comme étant les plus intéressants. Un cas pratique a été envisagé, l implémentation objet de Linq y a montré son intérêt vis-à-vis de techniques plus classiques. Plusieurs implémentations relationnelles ont ensuite été abordées, avec une attention toute particulière pour Linq to Sql, implémentation vedette de Linq. Les concepts y ont été vus en détails avant d analyser les performances de cette implémentation confrontée à un accès classique aux données. D autres implémentations ont ensuite été examinées, mettant en avant l autre technologie phare de Microsoft, l Entity Framework. L exploration de Linq s est poursuivie avec l étude de l implémentation Xml et des nouveautés qu elles apportaient, en particulier dans la gestion de données directement en Xml. Avec un peu de recul, le point a été fait sur l expérience Linq ainsi que sur ses forces et faiblesses. L abstraction suppélmentaire du code visà-vis de la couche de persistance est un apport très positif. Les anciennes techniques d accès relationnels ne sont pas obsolètes, le besoin de gérer plus finement des bases de données sera toujours présent. Malgré tout, Linq constitue un danger pour le développeur non averti. Les tests ont montré qu une connaissance des mécanismes utilisés en interne s avère indispensable pour éviter les pièges qu une trop grande facilité pourrait masquer. Le manque de documentation claire et accessible est également à déplorer. L étude s est poursuivie par l examen des alternatives envisageables à Linq et leurs correspondances relatives. De nombreux concurrents existent mais très peu proposent une abstraction aussi forte que celle de Linq. Seul JDO en Java semble constituer une alternative sérieuse à Linq et.net. Pour finir ce tour d horizon, les possibles évolutions de Linq ont été discutées. Il est difficile de prévoir ce que l avenir nous réserve mais pour l heure Linq semble se stabiliser. Le projet Mono en est encore à ses débuts avec Linq mais la portabilité qu il offre au projet Linq tout entier laisse croire que son évolution à lui aussi se poursuivra. Linq, nouveau paradigme, annonciateur de la programmation orientée données? Un long chemin reste à accomplir, l avenir nous donnera la réponse.

56 Bibliographie 1. «Programming Microsoft Linq», Paolo Pialorsi et Marco Russo, éditions Microsoft Press, «C# et.net, version 2», Gérard Lebrun, éditions Eyrolles, «L orienté objet, troisième édition», Hugues Bersini, éditions Eyrolles, «Documentation en ligne du réseau de développeurs Microsoft», technical references on C# 3.0 and «Technical preview of Entity Framework», 6. «Tout sur WPF, Linq, C# et.net en général», Thomas Lebrun, 7. «Programming Entity Framework», Julie Lerman, O Reilly Media, janvier «The Apache JDO web page», hosted by Apache Software Foundation, 9. «db4o, an object oriented datastore», «Siaqodb first full Linq-supported object database», «Linq in Action», par Fabrice Marguerie, Steve Eichert et Jim Wooley, O Reilly Media, «Bases de données», Esteban Zimànyi, cours donné en MA1 de la faculté des sciences appliquées de l Université Libre de Bruxelles, «Forum des développeurs C#», forum de la communauté Developpez.com, «DbLinq 2007», site du projet Db Linq, «Mono 2.6 Release Notes», site du projet Mono, partie relative à la version 2.6, «Hibernate in Action», par Christian Bauer et Gavin King, O Reilly. 17. «NHibernate for.net», site hébergé par la communauté JBoss, «Linq to NHibernate page», «Doctrine ORM page», «ORM comparison and benchmark», ormeter.net/ 21. «Apache Cayenne : Orm comparison for Java», «ez Publish», site du projet open-source ez Publish, ez.no 23. «Drupal community plumbing», site de la communauté Drupal, drupal.org 24. «OpenERP», site de OpenERP anciennement tinyerp,

57 Annexe 1 : Code de l exemple Linq to object Contenu du fichier Ville.cs : using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace exlinq class Ville private string nom; private int nbrhab; public List<string> communes; public List<Ville> liaisons; public Ville(string n, int nbr) nom = n; nbrhab = nbr; communes = new List<string>(); liaisons = new List<Ville>(); public string Nom getreturn nom; setnom=value; public int Hab get return nbrhab; set if(value>0) nbrhab = value; public void AjouterCommune(string nom) communes.add(nom); public void RetirerCommune(string nom) communes.remove(nom); public void RelierA(Ville v) liaisons.add(v); public void EnleverLiaisonAvec(Ville v) liaisons.remove(v);

58 Contenu du fichier program.cs : using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; namespace exlinq class Program static void Main(string[] args) Villes(); Console.Read(); static void Villes() List<Ville> reseauroutier = InitialiseLeReseau(); var requete = from v in reseauroutier from c in v.liaisons where v.communes.count() >= 2 && c.hab <= select new Ville = v.nom, Connexion = c.nom, Habitants=c.Hab; foreach (var v in requete) Console.WriteLine(v); static List<Ville> InitialiseLeReseau() Ville v = new Ville("Charleroi", 45000); v.ajoutercommune("marcinelle"); v.ajoutercommune("courcelles"); v.ajoutercommune("marchienne au pont"); Ville v2 = new Ville("Zaventem", 8500); v2.ajoutercommune("nossegem"); v2.ajoutercommune("sint Stevens Woluwe"); Ville v3 = new Ville("Wavre", 18000); v3.ajoutercommune("limal"); Ville v4 = new Ville("Braine l'alleud", 22000); v4.ajoutercommune("ophain"); v4.ajoutercommune("witterzée"); Ville v5 = new Ville("Louvain",26000); Ville v6 = new Ville("Woluwe Saint Lambert", 20500); v6.ajoutercommune("paduwa"); v.reliera(v4); v4.reliera(v); v.reliera(v3); v3.reliera(v); v2.reliera(v5); v5.reliera(v2); v2.reliera(v4); v4.reliera(v2); v2.reliera(v6);

59 v6.reliera(v2); v3.reliera(v5); v5.reliera(v3); v4.reliera(v6); v6.reliera(v4); v5.reliera(v6); v6.reliera(v5); List<Ville> reseau = new List<Ville>(); reseau.add(v); reseau.add(v2); reseau.add(v3); reseau.add(v4); reseau.add(v5); reseau.add(v6); return reseau; Vu les valeurs données lors de l initialisation, on constate que «l ensemble des villes ayant au moins deux communes et étant connectées à au moins une ville de maximum habitants» se résume à Braine l Alleud, qui est la seule ville connectée à Zaventem (la seule de moins de habitants) à posséder au moins deux communes.

60 Annexe 2 : Code de tests de performance pour Linq to Sql Contenu de la classe ADOManager.cs : using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Common; using System.Data.SqlClient; namespace Linq_demo_console_3 public class ADOManager private SqlConnection db; private SqlDataReader rdr; public void Connect() Console.WriteLine(); db = new SqlConnection("Data Source=.\\SQLEXPRESS;AttachDbFilename=\"G:\\Documents and Settings\\Charles\\Mes documents\\visual Studio 2008\\Projects\\Linq_demo_console_3\\LinqSelectTest\\LinqDB.mdf\";Integrate d Security=True;Connect Timeout=30;User Instance=True"); rdr = null; try Console.WriteLine("ADO Initializing"); Console.WriteLine("Manual Connection to DataBase"); db.open(); Console.WriteLine("DataSource : "+db.datasource); Console.WriteLine("DataBase : " + db.database); catch(exception e) Console.WriteLine(e.Message); public void LaunchInsertTest(int charge) this.connect(); Console.WriteLine(); Console.WriteLine("*** ADO Test running ***"); //Compute Time interval required to construct query DateTime start = DateTime.Now; Console.WriteLine("Starting test at " + start.hour + ":" + start.minute + ":" + start.second + ":" + start.millisecond); string sql = "INSERT INTO Customers(Name,Address_city,Address_zip,Address_street,Address_number)"; string sql2; string totalquery = ""; for(int i=1;i<=charge; ++i) sql2 = " VALUES('cust"+i+"','city"+i+"','"+i+"','street"+i+"',"+i+"); "; totalquery += sql+sql2; //Compute Time interval required by actual query

61 DateTime qstart = DateTime.Now; Console.WriteLine("Starting query at " + qstart.hour + ":" + qstart.minute + ":" + qstart.second + ":" + qstart.millisecond); SqlCommand com = new SqlCommand(totalQuery, db); com.executenonquery(); DateTime end = DateTime.Now; Console.WriteLine("End of test at " + end.hour + ":" + end.minute + ":" + end.second + ":" + end.millisecond); Console.WriteLine("Query duration : "+(end-qstart).tostring()); Console.WriteLine("Test Duration : " + (end - start).tostring()); this.deconnect(); public void SingleQuery(int i) string sql = "INSERT INTO Customers(Name,Address_city,Address_zip,Address_street,Address_number)"; sql += " VALUES('cust" + i + "','city" + i + "','" + i + "','street" + i + "'," + i + "); "; SqlCommand com = new SqlCommand(sql, db); com.executenonquery(); public void Deconnect() if (db!= null) db.close();

62 Contenu de la classe LinqBenchmarking.cs : using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Linq_demo_console_3 public class Linq_benchmarking private CustomerDataContext db; public Linq_benchmarking() db = new CustomerDataContext(); public void LaunchInsertTest(int charge) Console.WriteLine("*** LINQ Test running ***"); //Compute Time interval required to construct query DateTime dt = System.DateTime.Now; Console.WriteLine("Starting test at "+dt.hour+":"+dt.minute+":"+dt.second+":"+dt.millisecond); for (int loop = 1; loop <= charge; ++loop) Customers c = new Customers(); c.id =loop; c.name="customer"+loop.tostring(); c.address_city="city"+loop.tostring(); c.address_number=loop; c.address_street="street"+loop.tostring(); c.address_zip=loop.tostring(); db.customers.insertonsubmit(c); //db.log = Console.Out; //Compute Time Interval required by actual query DateTime qstart = System.DateTime.Now; Console.WriteLine("Starting query at " + qstart.hour + ":" + qstart.minute + ":" + qstart.second + ":" + qstart.millisecond); db.submitchanges(); //db.log = null; DateTime dt2 = DateTime.Now; Console.WriteLine("End of test at " + dt2.hour + ":" + dt2.minute + ":" + dt2.second + ":" + dt2.millisecond); Console.WriteLine("Query duration : " + this.timebetween(qstart,dt2)); Console.WriteLine("Test Duration : "+this.timebetween(dt,dt2)); public void AllCustomers() var cust = from c in db.customers select c.name; foreach (string cst in cust) Console.WriteLine(cst);

63 public void CleanDB() var cust = from c in db.customers select c; foreach (Customers cst in cust) db.customers.deleteonsubmit(cst); db.submitchanges(); public string TimeBetween(DateTime start, DateTime end) string time = ""; time += (end - start).tostring(); return time; public void SingleQuery(int n) Customers c = new Customers(); c.id = n; c.name = "customer" + n.tostring(); c.address_city = "city" + n.tostring(); c.address_number = n; c.address_street = "street" + n.tostring(); c.address_zip = n.tostring(); db.customers.insertonsubmit(c); //db.submitchanges(); public void Submit() db.submitchanges();

64 Contenu de Customer.dbml : #pragma warning disable 1591 // // <auto-generated> // Ce code a été généré par un outil. // Version du runtime : // // Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si // le code est régénéré. // </auto-generated> // namespace Linq_demo_console_3 using System.Data.Linq; using System.Data.Linq.Mapping; using System.Data; using System.Collections.Generic; using System.Reflection; using System.Linq; using System.Linq.Expressions; using System.ComponentModel; using System; [System.Data.Linq.Mapping.DatabaseAttribute(Name="LinqDB")] public partial class CustomerDataContext : System.Data.Linq.DataContext private static System.Data.Linq.Mapping.MappingSource mappingsource = new AttributeMappingSource(); #region Extensibility Method Definitions partial void OnCreated(); partial void InsertCustomers(Customers instance); partial void UpdateCustomers(Customers instance); partial void DeleteCustomers(Customers instance); #endregion public CustomerDataContext() : base(global::linq_demo_console_3.properties.settings.default.linqdbco nnectionstring, mappingsource) OnCreated(); public CustomerDataContext(string connection) : base(connection, mappingsource) OnCreated(); public CustomerDataContext(System.Data.IDbConnection connection) : base(connection, mappingsource)

65 OnCreated(); public CustomerDataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingsource) : base(connection, mappingsource) OnCreated(); public CustomerDataContext(System.Data.IDbConnection connection, System.Data.Linq.Mapping.MappingSource mappingsource) : base(connection, mappingsource) OnCreated(); public System.Data.Linq.Table<Customers> Customers get return this.gettable<customers>(); [Table(Name="dbo.Customers")] public partial class Customers : INotifyPropertyChanging, INotifyPropertyChanged private static PropertyChangingEventArgs emptychangingeventargs = new PropertyChangingEventArgs(String.Empty); private int _ID; private string _Name; private string _Address_city; private string _Address_zip; private string _Address_street; private System.Nullable<int> _Address_number; private string _ ; #region Extensibility Method Definitions partial void OnLoaded(); partial void OnValidate(System.Data.Linq.ChangeAction action); partial void OnCreated(); partial void OnIDChanging(int value); partial void OnIDChanged(); partial void OnNameChanging(string value); partial void OnNameChanged(); partial void OnAddress_cityChanging(string value); partial void OnAddress_cityChanged(); partial void OnAddress_zipChanging(string value); partial void OnAddress_zipChanged();

66 partial void OnAddress_streetChanging(string value); partial void OnAddress_streetChanged(); partial void OnAddress_numberChanging(System.Nullable<int> value); partial void OnAddress_numberChanged(); partial void On Changing(string value); partial void On Changed(); #endregion public Customers() OnCreated(); [Column(Storage="_ID", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)] public int ID get return this._id; set if ((this._id!= value)) this.onidchanging(value); this.sendpropertychanging(); this._id = value; this.sendpropertychanged("id"); this.onidchanged(); [Column(Storage="_Name", DbType="VarChar(50) NOT NULL", CanBeNull=false)] public string Name get return this._name; set if ((this._name!= value)) this.onnamechanging(value); this.sendpropertychanging(); this._name = value; this.sendpropertychanged("name"); this.onnamechanged(); [Column(Storage="_Address_city", DbType="VarChar(50) NOT NULL", CanBeNull=false)] public string Address_city get

67 set return this._address_city; if ((this._address_city!= value)) this.onaddress_citychanging(value); this.sendpropertychanging(); this._address_city = value; this.sendpropertychanged("address_city"); this.onaddress_citychanged(); [Column(Storage="_Address_zip", DbType="VarChar(8) NOT NULL", CanBeNull=false)] public string Address_zip get return this._address_zip; set if ((this._address_zip!= value)) this.onaddress_zipchanging(value); this.sendpropertychanging(); this._address_zip = value; this.sendpropertychanged("address_zip"); this.onaddress_zipchanged(); [Column(Storage="_Address_street", DbType="VarChar(50)")] public string Address_street get return this._address_street; set if ((this._address_street!= value)) this.onaddress_streetchanging(value); this.sendpropertychanging(); this._address_street = value; this.sendpropertychanged("address_street"); this.onaddress_streetchanged(); [Column(Storage="_Address_number", DbType="Int")] public System.Nullable<int> Address_number get

68 set return this._address_number; if ((this._address_number!= value)) this.onaddress_numberchanging(value); this.sendpropertychanging(); this._address_number = value; this.sendpropertychanged("address_number"); this.onaddress_numberchanged(); [Column(Storage="_ ", DbType="VarChar(50)")] public string get return this._ ; set if ((this._ != value)) this.on changing(value); this.sendpropertychanging(); this._ = value; this.sendpropertychanged(" "); this.on changed(); public event PropertyChangingEventHandler PropertyChanging; public event PropertyChangedEventHandler PropertyChanged; protected virtual void SendPropertyChanging() if ((this.propertychanging!= null)) this.propertychanging(this, emptychangingeventargs); protected virtual void SendPropertyChanged(String propertyname) if ((this.propertychanged!= null)) this.propertychanged(this, new PropertyChangedEventArgs(propertyName)); #pragma warning restore 1591

69 Contenu du fichier program.cs : using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using MySql.Data; using MySql.Data.MySqlClient; namespace LinqToDataSet class Program static void Main(string[] args) MySqlConnection con = new MySqlConnection("Database=MyLinqSql;Uid='root';Pwd='C1$oon'"); string cmdstring = "show tables"; MySqlCommand cmd = new MySqlCommand(cmdString, con); con.open(); MySqlDataReader dr = cmd.executereader(); Console.WriteLine("Tables présentes dans la Db :"); while (dr.read()) Console.WriteLine(dr.GetValue(0)); //Fermeture du reader pour eviter conflit avec DataAdapter dr.close(); DataSet ds = new DataSet("MySqlDataSet"); string selectstring * FROM objects1"; MySqlDataAdapter da = new MySqlDataAdapter(selectString,con); da.tablemappings.add("objects1", "Table"); da.fill(ds); //interrogation du DataSet ds avec Linq to DataSet DataTable dt1 = ds.tables["table"]; var datasetquery = from o in dt1.asenumerable() select new ID = o.field<int>("id"), TEXT = o.field<string>("desc"); Console.WriteLine("Requête adressée au DataSet construit depuis une Db MySql"); foreach(var res in datasetquery) Console.WriteLine(res); //Fermeture de la connexion con.close(); Console.WriteLine("Appuyez sur Enter pour terminer..."); Console.ReadLine();

70 Annexe 3 : Utilisation d une base de données MySQL avec Linq to DataSet Phase 1 : Création de la base de données avec MySQL Téléchargement de MySQL Community Server (disponible à cette adresse : ). Après installation et première configuration, lancement de l utilitaire MySQL en ligne de commande. Les commandes entrées sont, dans l ordre : Create Database MyLinqSql \g \u MyLinqSql Create Table objects1 ( `Id` int not null, `Desc` varchar(20) default, primary key(id) ); Create Table objects2 ( `Id` int not null, `Code` int not null, `ShortDesc` varchar(20) default, primary key (Id), foreign key (Code) references objects1(id) ); Insert into objects1(`id`,`desc`) values (1, description 1 ); Insert into objects1(`id`,`desc`) values (2, description 2 ); insert into objects1(`id`,`desc`) values (3, description 3 ); Insert into objects2 values (1,1, obj2 pointe vers 1 ); Insert into objects2 values (2,1, obj2.2 ); Insert into objects2 values (3,2, obj2.3 ); Insert into objects2 values (4,1, obj2.4 ); Insert into objects2 values (5,2, obj2.5 ); Ce qui doit donner comme contenu pour objects1 (Select * from objects1 ;) : Et pour objects2 :

Types d applications pour la persistance. Outils de développement. Base de données préexistante? 3 modèles. Variantes avec passerelles

Types d applications pour la persistance. Outils de développement. Base de données préexistante? 3 modèles. Variantes avec passerelles Types d applications pour la persistance Université de Nice Sophia-Antipolis Version 0.9 28/8/07 Richard Grin Toutes les applications n ont pas une complexité qui nécessite une architecture n- tiers Ce

Plus en détail

Pour signifier qu'une classe fille hérite d'une classe mère, on utilise le mot clé extends class fille extends mère

Pour signifier qu'une classe fille hérite d'une classe mère, on utilise le mot clé extends class fille extends mère L'héritage et le polymorphisme en Java Pour signifier qu'une classe fille hérite d'une classe mère, on utilise le mot clé extends class fille extends mère En java, toutes les classes sont dérivée de la

Plus en détail

Quelques patterns pour la persistance des objets avec DAO DAO. Principe de base. Utilité des DTOs. Le modèle de conception DTO (Data Transfer Object)

Quelques patterns pour la persistance des objets avec DAO DAO. Principe de base. Utilité des DTOs. Le modèle de conception DTO (Data Transfer Object) Quelques patterns pour la persistance des objets avec DAO Ce cours présente des modèles de conception utilisés pour effectuer la persistance des objets Université de Nice Sophia-Antipolis Version 1.4 30/8/07

Plus en détail

Évaluation et implémentation des langages

Évaluation et implémentation des langages Évaluation et implémentation des langages Les langages de programmation et le processus de programmation Critères de conception et d évaluation des langages de programmation Les fondations de l implémentation

Plus en détail

SQL Server Installation Center et SQL Server Management Studio

SQL Server Installation Center et SQL Server Management Studio SQL Server Installation Center et SQL Server Management Studio Version 1.0 Grégory CASANOVA 2 SQL Server Installation Center et SQL Server Management Studio [03/07/09] Sommaire 1 Installation de SQL Server

Plus en détail

Premiers Pas en Programmation Objet : les Classes et les Objets

Premiers Pas en Programmation Objet : les Classes et les Objets Chapitre 2 Premiers Pas en Programmation Objet : les Classes et les Objets Dans la première partie de ce cours, nous avons appris à manipuler des objets de type simple : entiers, doubles, caractères, booléens.

Plus en détail

Créer et partager des fichiers

Créer et partager des fichiers Créer et partager des fichiers Le rôle Services de fichiers... 246 Les autorisations de fichiers NTFS... 255 Recherche de comptes d utilisateurs et d ordinateurs dans Active Directory... 262 Délégation

Plus en détail

Chapitre I Notions de base et outils de travail

Chapitre I Notions de base et outils de travail Chapitre I Notions de base et outils de travail Objectifs Connaître les principes fondateurs et l historique du langage Java S informer des principales caractéristiques du langage Java Connaître l environnement

Plus en détail

Introduction aux concepts d ez Publish

Introduction aux concepts d ez Publish Introduction aux concepts d ez Publish Tutoriel rédigé par Bergfrid Skaara. Traduit de l Anglais par Benjamin Lemoine Mercredi 30 Janvier 2008 Sommaire Concepts d ez Publish... 3 Système de Gestion de

Plus en détail

Chapitre VIII. Les bases de données. Orientées Objet. Motivation

Chapitre VIII. Les bases de données. Orientées Objet. Motivation Chapitre VIII Motivation Le modèle relationnel connaît un très grand succès et s avère très adéquat pour les applications traditionnelles des bases de données (gestion) Les bases de données Orientées Objet

Plus en détail

De quoi avez-vous besoin pour ce manuel?

De quoi avez-vous besoin pour ce manuel? Introduction Le commerce électronique est devenu l un des grands sujets de préoccupation des chefs d entreprise du monde entier. Ces derniers répètent à l envie que leur priorité absolue est de relever

Plus en détail

Table des matières PRESENTATION DU LANGAGE DS2 ET DE SES APPLICATIONS. Introduction

Table des matières PRESENTATION DU LANGAGE DS2 ET DE SES APPLICATIONS. Introduction PRESENTATION DU LANGAGE DS2 ET DE SES APPLICATIONS Depuis SAS 9.2 TS2M3, SAS propose un nouveau langage de programmation permettant de créer et gérer des tables SAS : le DS2 («Data Step 2»). Ces nouveautés

Plus en détail

Programmer en JAVA. par Tama ([email protected]( [email protected])

Programmer en JAVA. par Tama (tama@via.ecp.fr( tama@via.ecp.fr) Programmer en JAVA par Tama ([email protected]( [email protected]) Plan 1. Présentation de Java 2. Les bases du langage 3. Concepts avancés 4. Documentation 5. Index des mots-clés 6. Les erreurs fréquentes

Plus en détail

Compte Rendu d intégration d application

Compte Rendu d intégration d application ISMA 3EME ANNEE Compte Rendu d intégration d application Compte Rendu Final Maxime ESCOURBIAC Jean-Christophe SEPTIER 19/12/2011 Table des matières Table des matières... 1 Introduction... 3 1. Le SGBD:...

Plus en détail

Devenez un véritable développeur web en 3 mois!

Devenez un véritable développeur web en 3 mois! Devenez un véritable développeur web en 3 mois! L objectif de la 3W Academy est de former des petits groupes d élèves au développement de sites web dynamiques ainsi qu à la création d applications web

Plus en détail

Arithmétique binaire. Chapitre. 5.1 Notions. 5.1.1 Bit. 5.1.2 Mot

Arithmétique binaire. Chapitre. 5.1 Notions. 5.1.1 Bit. 5.1.2 Mot Chapitre 5 Arithmétique binaire L es codes sont manipulés au quotidien sans qu on s en rende compte, et leur compréhension est quasi instinctive. Le seul fait de lire fait appel au codage alphabétique,

Plus en détail

4. Utilisation d un SGBD : le langage SQL. 5. Normalisation

4. Utilisation d un SGBD : le langage SQL. 5. Normalisation Base de données S. Lèbre [email protected] Université de Strasbourg, département d informatique. Présentation du module Contenu général Notion de bases de données Fondements / Conception Utilisation :

Plus en détail

TP1 : Initiation à Java et Eclipse

TP1 : Initiation à Java et Eclipse TP1 : Initiation à Java et Eclipse 1 TP1 : Initiation à Java et Eclipse Systèmes d Exploitation Avancés I. Objectifs du TP Ce TP est une introduction au langage Java. Il vous permettra de comprendre les

Plus en détail

Sélection d un moteur de recherche pour intranet : Les sept points à prendre en compte

Sélection d un moteur de recherche pour intranet : Les sept points à prendre en compte Sélection d un moteur de recherche pour intranet : Les sept points à prendre en compte 1Les bases : vos objectifs 2 Sélection d un moteur de recherche pour intranet : Les sept points à prendre en compte

Plus en détail

Créer le schéma relationnel d une base de données ACCESS

Créer le schéma relationnel d une base de données ACCESS Utilisation du SGBD ACCESS Polycopié réalisé par Chihab Hanachi et Jean-Marc Thévenin Créer le schéma relationnel d une base de données ACCESS GENERALITES SUR ACCESS... 1 A PROPOS DE L UTILISATION D ACCESS...

Plus en détail

LES OUTILS D ALIMENTATION DU REFERENTIEL DE DB-MAIN

LES OUTILS D ALIMENTATION DU REFERENTIEL DE DB-MAIN LES OUTILS D ALIMENTATION DU REFERENTIEL DE DB-MAIN Les contenues de ce document sont la propriété exclusive de la société REVER. Ils ne sont transmis qu à titre d information et ne peuvent en aucun cas

Plus en détail

GOL502 Industries de services

GOL502 Industries de services GOL502 Industries de services Conception d un service Partie IIb Version 2013 Introduction Conception d un service partie IIb Nous verrons dans ce chapitre Modélisation d un service; Langage de modélisation

Plus en détail

TP 1. Prise en main du langage Python

TP 1. Prise en main du langage Python TP. Prise en main du langage Python Cette année nous travaillerons avec le langage Python version 3. ; nous utiliserons l environnement de développement IDLE. Étape 0. Dans votre espace personnel, créer

Plus en détail

Cours 1 : Introduction. Langages objets. but du module. contrôle des connaissances. Pourquoi Java? présentation du module. Présentation de Java

Cours 1 : Introduction. Langages objets. but du module. contrôle des connaissances. Pourquoi Java? présentation du module. Présentation de Java Langages objets Introduction M2 Pro CCI, Informatique Emmanuel Waller, LRI, Orsay présentation du module logistique 12 blocs de 4h + 1 bloc 2h = 50h 1h15 cours, 45mn exercices table, 2h TD machine page

Plus en détail

Bien architecturer une application REST

Bien architecturer une application REST Olivier Gutknecht Bien architecturer une application REST Avec la contribution de Jean Zundel Ce livre traite exactement du sujet suivant : comment faire pour que les services web et les programmes qui

Plus en détail

Cours 1 : La compilation

Cours 1 : La compilation /38 Interprétation des programmes Cours 1 : La compilation Yann Régis-Gianas [email protected] PPS - Université Denis Diderot Paris 7 2/38 Qu est-ce que la compilation? Vous avez tous déjà

Plus en détail

Présentation du module Base de données spatio-temporelles

Présentation du module Base de données spatio-temporelles Présentation du module Base de données spatio-temporelles S. Lèbre [email protected] Université de Strasbourg, département d informatique. Partie 1 : Notion de bases de données (12,5h ) Enjeux et principes

Plus en détail

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP COURS PROGRAMMATION INITIATION AU LANGAGE C SUR MICROCONTROLEUR PIC page 1 / 7 INITIATION AU LANGAGE C SUR PIC DE MICROSHIP I. Historique du langage C 1972 : naissance du C dans les laboratoires BELL par

Plus en détail

Chapitre VI- La validation de la composition.

Chapitre VI- La validation de la composition. Chapitre VI- La validation de la composition. Objectifs du chapitre : Expliquer les conséquences de l utilisation de règles de typage souples dans SEP. Présenter le mécanisme de validation des connexions

Plus en détail

Sommaire. 2 LINQ to Objects

Sommaire. 2 LINQ to Objects LINQ To Object 2 LINQ to Objects Sommaire 1 LINQ to Object... 3 1.1 Introduction par l exemple.... 3 1.2 Evaluation de requête différée... 6 1.3 Les objets «Enumerable» et «Queryable»... 7 1.4 Les mots-clés

Plus en détail

Générer du code à partir d une description de haut niveau

Générer du code à partir d une description de haut niveau Cedric Dumoulin Générer du code à partir d une description de haut niveau Ce projet vise à fournir un environnement de développement permettant de modéliser des UI Android à un haut niveau d abstraction,

Plus en détail

Cours en ligne Développement Java pour le web

Cours en ligne Développement Java pour le web Cours en ligne Développement Java pour le web We TrainFrance info@wetrainfrance Programme général du cours Développement Java pour le web Module 1 - Programmation J2ee A) Bases de programmation Java Unité

Plus en détail

Introduction à la B.I. Avec SQL Server 2008

Introduction à la B.I. Avec SQL Server 2008 Introduction à la B.I. Avec SQL Server 2008 Version 1.0 VALENTIN Pauline 2 Introduction à la B.I. avec SQL Server 2008 Sommaire 1 Présentation de la B.I. et SQL Server 2008... 3 1.1 Présentation rapide

Plus en détail

Whitepaper. Méthodologie de création de rapports personnalisés SQL Server Reporting Services

Whitepaper. Méthodologie de création de rapports personnalisés SQL Server Reporting Services Ce Whitepaper décrit la méthodologie de développement d un rapport personnalisé au format SQL Server Reporting Service (SSRS) appliqué à System Center Operations Manager (SCOM) Whitepaper Méthodologie

Plus en détail

LMI 2. Programmation Orientée Objet POO - Cours 9. Said Jabbour. [email protected] www.cril.univ-artois.fr/~jabbour

LMI 2. Programmation Orientée Objet POO - Cours 9. Said Jabbour. jabbour@cril.univ-artois.fr www.cril.univ-artois.fr/~jabbour LMI 2 Programmation Orientée Objet POO - Cours 9 Said Jabbour [email protected] www.cril.univ-artois.fr/~jabbour CRIL UMR CNRS 8188 Faculté des Sciences - Univ. Artois Février 2011 Les collections

Plus en détail

INF 1250 INTRODUCTION AUX BASES DE DONNÉES. Guide d étude

INF 1250 INTRODUCTION AUX BASES DE DONNÉES. Guide d étude INF 1250 INTRODUCTION AUX BASES DE DONNÉES Guide d étude Sous la direction de Olga Mariño Télé-université Montréal (Québec) 2011 INF 1250 Introduction aux bases de données 2 INTRODUCTION Le Guide d étude

Plus en détail

Visual Paradigm Contraintes inter-associations

Visual Paradigm Contraintes inter-associations Visual Paradigm Contraintes inter-associations Travail de Bachelor d'informaticien de gestion Partie C Présentation de Visual Paradigm 1 Présentation de Visual Paradigm For UML L objet du travail de Bachelor

Plus en détail

IV- Comment fonctionne un ordinateur?

IV- Comment fonctionne un ordinateur? 1 IV- Comment fonctionne un ordinateur? L ordinateur est une alliance du hardware (le matériel) et du software (les logiciels). Jusqu à présent, nous avons surtout vu l aspect «matériel», avec les interactions

Plus en détail

Projet 2. Gestion des services enseignants CENTRE D ENSEIGNEMENT ET DE RECHERCHE EN INFORMATIQUE. G r o u p e :

Projet 2. Gestion des services enseignants CENTRE D ENSEIGNEMENT ET DE RECHERCHE EN INFORMATIQUE. G r o u p e : CENTRE D ENSEIGNEMENT ET DE RECHERCHE EN INFORMATIQUE Projet 2 Gestion des services enseignants G r o u p e : B E L G H I T Y a s m i n e S A N C H E Z - D U B R O N T Y u r i f e r M O N T A Z E R S i

Plus en détail

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

INTRODUCTION A JAVA. Fichier en langage machine Exécutable INTRODUCTION A JAVA JAVA est un langage orienté-objet pur. Il ressemble beaucoup à C++ au niveau de la syntaxe. En revanche, ces deux langages sont très différents dans leur structure (organisation du

Plus en détail

Cours Bases de données

Cours Bases de données Informations sur le cours Cours Bases de données 9 (10) séances de 3h Polycopié (Cours + TD/TP) 3 année (MISI) Antoine Cornuéjols www.lri.fr/~antoine [email protected] Transparents Disponibles

Plus en détail

Le langage SQL Rappels

Le langage SQL Rappels Le langage SQL Rappels Description du thème : Présentation des principales notions nécessaires pour réaliser des requêtes SQL Mots-clés : Niveau : Bases de données relationnelles, Open Office, champs,

Plus en détail

Introduction aux SGBDR

Introduction aux SGBDR 1 Introduction aux SGBDR Pour optimiser une base Oracle, il est important d avoir une idée de la manière dont elle fonctionne. La connaissance des éléments sous-jacents à son fonctionnement permet de mieux

Plus en détail

1. LA GESTION DES BASES DE DONNEES RELATIONNELLES

1. LA GESTION DES BASES DE DONNEES RELATIONNELLES Dossier G11 - Interroger une base de données La base de données Facturation contient tout un ensemble d'informations concernant la facturation de la SAFPB (société anonyme de fabrication de produits de

Plus en détail

Les structures. Chapitre 3

Les structures. Chapitre 3 Chapitre 3 Les structures Nous continuons notre étude des structures de données qui sont prédéfinies dans la plupart des langages informatiques. La structure de tableau permet de regrouper un certain nombre

Plus en détail

Information utiles. [email protected]. webpage : Google+ : http://www.ibisc.univ-evry.fr/ digiusto/

Information utiles. cinzia.digiusto@gmail.com. webpage : Google+ : http://www.ibisc.univ-evry.fr/ digiusto/ Systèmes de gestion de bases de données Introduction Université d Evry Val d Essonne, IBISC utiles email : [email protected] webpage : http://www.ibisc.univ-evry.fr/ digiusto/ Google+ : https://plus.google.com/u/0/b/103572780965897723237/

Plus en détail

Formation Webase 5. Formation Webase 5. Ses secrets, de l architecture MVC à l application Web. Adrien Grand <[email protected]> Centrale Réseaux

Formation Webase 5. Formation Webase 5. Ses secrets, de l architecture MVC à l application Web. Adrien Grand <jpountz@via.ecp.fr> Centrale Réseaux Formation Webase 5 Ses secrets, de l architecture MVC à l application Web Adrien Grand Centrale Réseaux Sommaire 1 Obtenir des informations sur Webase 5 2 Composants de Webase 5 Un

Plus en détail

Plan du cours. Historique du langage http://www.oracle.com/technetwork/java/index.html. Nouveautés de Java 7

Plan du cours. Historique du langage http://www.oracle.com/technetwork/java/index.html. Nouveautés de Java 7 Université Lumière Lyon 2 Faculté de Sciences Economiques et Gestion KHARKIV National University of Economic Introduction au Langage Java Master Informatique 1 ère année Julien Velcin http://mediamining.univ-lyon2.fr/velcin

Plus en détail

Programme «Analyste Programmeur» Diplôme d état : «Développeur Informatique» Homologué au niveau III (Bac+2) (JO N 176 du 1 août 2003) (34 semaines)

Programme «Analyste Programmeur» Diplôme d état : «Développeur Informatique» Homologué au niveau III (Bac+2) (JO N 176 du 1 août 2003) (34 semaines) Programme «Analyste Programmeur» Diplôme d état : «Développeur Informatique» Homologué au niveau III (Bac+2) (JO N 176 du 1 août 2003) (34 semaines) Module 1 : Programmer une application informatique Durée

Plus en détail

THEME PROJET D ELABORATION D UNE BASE DE DONNEES SOUS LE SERVEUR MYSQL

THEME PROJET D ELABORATION D UNE BASE DE DONNEES SOUS LE SERVEUR MYSQL . THEME PROJET D ELABORATION D UNE BASE DE DONNEES SOUS LE SERVEUR MYSQL Mr MEZRED MOHAMED Ingénieur météorologue INTRODUCTION Il existe de nombreuses manières de construire une base de données. En effet,

Plus en détail

BIRT (Business Intelligence and Reporting Tools)

BIRT (Business Intelligence and Reporting Tools) BIRT (Business Intelligence and Reporting Tools) Introduction Cette publication a pour objectif de présenter l outil de reporting BIRT, dans le cadre de l unité de valeur «Data Warehouse et Outils Décisionnels»

Plus en détail

Info0101 Intro. à l'algorithmique et à la programmation. Cours 3. Le langage Java

Info0101 Intro. à l'algorithmique et à la programmation. Cours 3. Le langage Java Info0101 Intro. à l'algorithmique et à la programmation Cours 3 Le langage Java Pierre Delisle, Cyril Rabat et Christophe Jaillet Université de Reims Champagne-Ardenne Département de Mathématiques et Informatique

Plus en détail

Langage et Concepts de Programmation Objet. 1 Attributs et Méthodes d instance ou de classe. Travaux Dirigés no2

Langage et Concepts de Programmation Objet. 1 Attributs et Méthodes d instance ou de classe. Travaux Dirigés no2 Langage et Concepts de Programmation Objet Travaux Dirigés no2 Pôle Informatique École Nationale Supérieure des Mines de St-Etienne Vous trouverez plus de détails sur les concepts abordés lors de ce TD

Plus en détail

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile Dans ce TP, vous apprendrez à définir le type abstrait Pile, à le programmer en Java à l aide d une interface

Plus en détail

1 Introduction et installation

1 Introduction et installation TP d introduction aux bases de données 1 TP d introduction aux bases de données Le but de ce TP est d apprendre à manipuler des bases de données. Dans le cadre du programme d informatique pour tous, on

Plus en détail

SQL Server 2012 et SQL Server 2014

SQL Server 2012 et SQL Server 2014 SQL Server 2012 et SQL Server 2014 Principales fonctions SQL Server 2012 est le système de gestion de base de données de Microsoft. Il intègre un moteur relationnel, un outil d extraction et de transformation

Plus en détail

La Clé informatique. Formation Excel XP Aide-mémoire

La Clé informatique. Formation Excel XP Aide-mémoire La Clé informatique Formation Excel XP Aide-mémoire Septembre 2005 Table des matières Qu est-ce que le logiciel Microsoft Excel?... 3 Classeur... 4 Cellule... 5 Barre d outil dans Excel...6 Fonctions habituelles

Plus en détail

Techniques d interaction dans la visualisation de l information Séminaire DIVA

Techniques d interaction dans la visualisation de l information Séminaire DIVA Techniques d interaction dans la visualisation de l information Séminaire DIVA Zingg Luca, [email protected] 13 février 2007 Résumé Le but de cet article est d avoir une vision globale des techniques

Plus en détail

Java et les bases de données: JDBC: Java DataBase Connectivity SQLJ: Embedded SQL in Java. Michel Bonjour http://cuiwww.unige.

Java et les bases de données: JDBC: Java DataBase Connectivity SQLJ: Embedded SQL in Java. Michel Bonjour http://cuiwww.unige. : JDBC: Java DataBase Connectivity SQLJ: Embedded SQL in Java Michel Bonjour http://cuiwww.unige.ch/~bonjour Plan JDBC: API bas niveau pour l accès aux BD (SQL) - Introduction - JDBC et : Java, ODBC, SQL

Plus en détail

Éléments de programmation et introduction à Java

Éléments de programmation et introduction à Java Éléments de programmation et introduction à Java Jean-Baptiste Vioix ([email protected]) IUT de Dijon-Auxerre - LE2I http://jb.vioix.free.fr 1-20 Les différents langages informatiques

Plus en détail

Traduction des Langages : Le Compilateur Micro Java

Traduction des Langages : Le Compilateur Micro Java BARABZAN Jean-René OUAHAB Karim TUCITO David 2A IMA Traduction des Langages : Le Compilateur Micro Java µ Page 1 Introduction Le but de ce projet est d écrire en JAVA un compilateur Micro-Java générant

Plus en détail

A QUOI SERVENT LES BASES DE DONNÉES?

A QUOI SERVENT LES BASES DE DONNÉES? BASE DE DONNÉES OBJET Virginie Sans [email protected] A QUOI SERVENT LES BASES DE DONNÉES? Stockage des informations : sur un support informatique pendant une longue période de taille importante accès

Plus en détail

COMMENT REDIGER UN RAPPORT TECHNIQUE?

COMMENT REDIGER UN RAPPORT TECHNIQUE? COMMENT REDIGER UN RAPPORT TECHNIQUE? Christiaens Sébastien Université de Liège Département PROMETHEE Institut de Mécanique et de Génie Civil, Bât. B52 Chemin des Chevreuils, 1 B-4000 Liège, Belgique Janvier

Plus en détail

La persistance des données dans les applications : DAO, JPA, Hibernate... COMPIL 2010 [email protected] 1

La persistance des données dans les applications : DAO, JPA, Hibernate... COMPIL 2010 francois.jannin@inp-toulouse.fr 1 La persistance des données dans les applications : DAO, JPA, Hibernate... COMPIL 2010 [email protected] 1 Plan 1. Généralités sur la persistance des données dans les applications 2. La connection

Plus en détail

Java Licence Professionnelle CISII, 2009-10

Java Licence Professionnelle CISII, 2009-10 Java Licence Professionnelle CISII, 2009-10 Cours 4 : Programmation structurée (c) http://www.loria.fr/~tabbone/cours.html 1 Principe - Les méthodes sont structurées en blocs par les structures de la programmation

Plus en détail

Notions fondamentales du langage C# Version 1.0

Notions fondamentales du langage C# Version 1.0 Notions fondamentales du langage C# Version 1.0 Z 2 [Notions fondamentales du langage Csharp] [Date : 25/03/09] Sommaire 1 Tout ce qu il faut savoir pour bien commencer... 3 1.1 Qu est ce qu un langage

Plus en détail

Manuel d utilisation 26 juin 2011. 1 Tâche à effectuer : écrire un algorithme 2

Manuel d utilisation 26 juin 2011. 1 Tâche à effectuer : écrire un algorithme 2 éducalgo Manuel d utilisation 26 juin 2011 Table des matières 1 Tâche à effectuer : écrire un algorithme 2 2 Comment écrire un algorithme? 3 2.1 Avec quoi écrit-on? Avec les boutons d écriture........

Plus en détail

Paginer les données côté serveur, mettre en cache côté client

Paginer les données côté serveur, mettre en cache côté client Paginer les données côté serveur, mettre en cache côté client Vous voulez sélectionner des lignes dans une table, mais celle-ci comporte trop de lignes pour qu il soit réaliste de les ramener en une seule

Plus en détail

Faculté des sciences de gestion et sciences économiques BASE DE DONNEES

Faculté des sciences de gestion et sciences économiques BASE DE DONNEES BASE DE DONNEES La plupart des entreprises possèdent des bases de données informatiques contenant des informations essentielles à leur fonctionnement. Ces informations concernent ses clients, ses produits,

Plus en détail

INTERSYSTEMS CACHÉ COMME ALTERNATIVE AUX BASES DE DONNÉES RÉSIDENTES EN MÉMOIRE

INTERSYSTEMS CACHÉ COMME ALTERNATIVE AUX BASES DE DONNÉES RÉSIDENTES EN MÉMOIRE I N T E RS Y S T E M S INTERSYSTEMS CACHÉ COMME ALTERNATIVE AUX BASES DE DONNÉES RÉSIDENTES EN MÉMOIRE David Kaaret InterSystems Corporation INTERSySTEMS CAChé CoMME ALTERNATIvE AUx BASES de données RéSIdENTES

Plus en détail

BASES DE DONNÉES. CNAM Centre associé de Clermont-Ferrand Cycle A Année 1997-98. J. Darmont I. INTRODUCTION II. LES SYSTÈMES HIÉRARCHIQUES

BASES DE DONNÉES. CNAM Centre associé de Clermont-Ferrand Cycle A Année 1997-98. J. Darmont I. INTRODUCTION II. LES SYSTÈMES HIÉRARCHIQUES BASES DE DONNÉES CNAM Centre associé de Clermont-Ferrand Cycle A Année 1997-98 J. Darmont I. INTRODUCTION II. LES SYSTÈMES HIÉRARCHIQUES III. LES SYSTÈMES RÉSEAU IV. LES SYSTÈMES RELATIONNELS V. LE LANGAGE

Plus en détail

Le modèle de données

Le modèle de données Le modèle de données Introduction : Une fois que l étude des besoins est complétée, deux points importants sont à retenir : Les données du système étudié Les traitements effectués par le système documentaire.

Plus en détail

La gestion des exceptions

La gestion des exceptions La gestion des exceptions Même lorsqu un programme est au point, certaines circonstances exceptionnelles peuvent compromettre la poursuite de son exécution ; il peut s agir par exemple de données incorrectes

Plus en détail

24/11/2011. Cours EJB/J2EE Copyright Michel Buffa. Plan du cours. EJB : les fondamentaux. Enterprise Java Bean. Enterprise Java Bean.

24/11/2011. Cours EJB/J2EE Copyright Michel Buffa. Plan du cours. EJB : les fondamentaux. Enterprise Java Bean. Enterprise Java Bean. Plan du cours 2 Introduction générale : fondamentaux : les fondamentaux Michel Buffa ([email protected]), UNSA 2002, modifié par Richard Grin (version 1.1, 21/11/11), avec emprunts aux supports de Maxime

Plus en détail

Introduction à Microsoft InfoPath 2010

Introduction à Microsoft InfoPath 2010 Introduction à Microsoft InfoPath 2010 Couplé à Microsoft SharePoint Designer 2010, InfoPath 2010 simplifie la création de solutions de bout en bout sur SharePoint Server 2010, qui contiennent des formulaires

Plus en détail

Chapitre 1 Qu est-ce qu une expression régulière?

Chapitre 1 Qu est-ce qu une expression régulière? Chapitre 1 Qu est-ce qu une expression régulière? Les ordinateurs n ont pas du tout la même conception des textes que nous : pour nous, un texte est un ensemble d idées couchées sur papier. Nous nous en

Plus en détail

PG208, Projet n 3 : Serveur HTTP évolué

PG208, Projet n 3 : Serveur HTTP évolué PG208, Projet n 3 : Serveur HTTP évolué Bertrand LE GAL, Serge BOUTER et Clément VUCHENER Filière électronique 2 eme année - Année universitaire 2011-2012 1 Introduction 1.1 Objectif du projet L objectif

Plus en détail

Groupe Eyrolles, 2004 ISBN : 2-212-11504-0

Groupe Eyrolles, 2004 ISBN : 2-212-11504-0 Groupe Eyrolles, 2004 ISBN : 2-212-11504-0 Table des matières Avant-propos................................................ 1 Quel est l objectif de cet ouvrage?............................. 4 La structure

Plus en détail

Mise en œuvre des serveurs d application

Mise en œuvre des serveurs d application Nancy-Université Mise en œuvre des serveurs d application UE 203d Master 1 IST-IE Printemps 2008 Master 1 IST-IE : Mise en œuvre des serveurs d application 1/54 Ces transparents, ainsi que les énoncés

Plus en détail

Création et Gestion des tables

Création et Gestion des tables Création et Gestion des tables Version 1.0 Z Grégory CASANOVA 2 Sommaire 1 Introduction... 3 2 Pré-requis... 4 3 Les tables... 5 3.1 Les types de données... 5 3.1.1 Les types de données Sql Server... 5

Plus en détail

Préparation à l examen EFA en Macro

Préparation à l examen EFA en Macro Préparation à l examen EFA en Macro Exercice sur les macros en Word / Excel Les questions suivantes doivent constituer un bref rafraîchissement et vous aider à situer le niveau de vos connaissances : Question

Plus en détail

clef primaire ; clef étrangère ; projection ; restriction ; jointure ; SQL ; SELECT ; FROM ; WHERE

clef primaire ; clef étrangère ; projection ; restriction ; jointure ; SQL ; SELECT ; FROM ; WHERE Cas Neptune hôtel Base de données et langage SQL Propriété Intitulé long Formation concernée Matière Notions Transversalité Présentation Description Neptune Hôtel. L interrogation d une base de données

Plus en détail

Jade. Projet Intelligence Artificielle «Devine à quoi je pense»

Jade. Projet Intelligence Artificielle «Devine à quoi je pense» Jade Projet Intelligence Artificielle «Devine à quoi je pense» Réalisé par Djénéba Djikiné, Alexandre Bernard et Julien Lafont EPSI CSII2-2011 TABLE DES MATIÈRES 1. Analyse du besoin a. Cahier des charges

Plus en détail

basée sur le cours de Bertrand Legal, maître de conférences à l ENSEIRB www.enseirb.fr/~legal Olivier Augereau Formation UML

basée sur le cours de Bertrand Legal, maître de conférences à l ENSEIRB www.enseirb.fr/~legal Olivier Augereau Formation UML basée sur le cours de Bertrand Legal, maître de conférences à l ENSEIRB www.enseirb.fr/~legal Olivier Augereau Formation UML http://olivier-augereau.com Sommaire Introduction I) Les bases II) Les diagrammes

Plus en détail

Présentation du langage et premières fonctions

Présentation du langage et premières fonctions 1 Présentation de l interface logicielle Si les langages de haut niveau sont nombreux, nous allons travaillé cette année avec le langage Python, un langage de programmation très en vue sur internet en

Plus en détail

Utilisation d objets : String et ArrayList

Utilisation d objets : String et ArrayList Chapitre 6 Utilisation d objets : String et ArrayList Dans ce chapitre, nous allons aborder l utilisation d objets de deux classes prédéfinies de Java d usage très courant. La première, nous l utilisons

Plus en détail

RÉALISATION D UN SITE DE RENCONTRE

RÉALISATION D UN SITE DE RENCONTRE RÉALISATION D UN SITE DE RENCONTRE Par Mathieu COUPE, Charlène DOUDOU et Stéphanie RANDRIANARIMANA Sous la coordination des professeurs d ISN du lycée Aristide Briand : Jérôme CANTALOUBE, Laurent BERNARD

Plus en détail

Business Intelligence

Business Intelligence avec Excel, Power BI et Office 365 Téléchargement www.editions-eni.fr.fr Jean-Pierre GIRARDOT Table des matières 1 Avant-propos A. À qui s adresse ce livre?..................................................

Plus en détail

Le logiciel pour le courtier d assurances

Le logiciel pour le courtier d assurances Le logiciel pour le courtier d assurances Introduction - Présentation 2 Intégration totale 3 Paperless Office 3 Traitement Unifié de l information 4 Outils commerciaux 5 Communication 6 Intégration AS/2

Plus en détail

Langage SQL : créer et interroger une base

Langage SQL : créer et interroger une base Langage SQL : créer et interroger une base Dans ce chapitre, nous revenons sur les principales requêtes de création de table et d accès aux données. Nous verrons aussi quelques fonctions d agrégation (MAX,

Plus en détail

MODIFICATIONS DES PRINCIPES DIRECTEURS CONCERNANT LA RÉDACTION DES DÉFINITIONS RELATIVES AU CLASSEMENT

MODIFICATIONS DES PRINCIPES DIRECTEURS CONCERNANT LA RÉDACTION DES DÉFINITIONS RELATIVES AU CLASSEMENT ANNEXE VI MODIFICATIONS DES PRINCIPES DIRECTEURS CONCERNANT LA RÉDACTION DES DÉFINITIONS RELATIVES AU CLASSEMENT RECOMMANDATIONS GÉNÉRALES Les utilisateurs s attendent à trouver dans les définitions des

Plus en détail

Initiation à Excel. Frédéric Gava (MCF) [email protected]

Initiation à Excel. Frédéric Gava (MCF) gava@univ-paris12.fr Initiation à Excel Frédéric Gava (MCF) [email protected] LACL, bâtiment P2 du CMC, bureau 221 Université de Paris XII Val-de-Marne 61 avenue du Général de Gaulle 94010 Créteil cedex Plan de cette année

Plus en détail

Nom de l application

Nom de l application Ministère de l Enseignement Supérieur et de la Recherche Scientifique Direction Générale des Etudes Technologiques Institut Supérieur des Etudes Technologiques de Gafsa Département Technologies de l Informatique

Plus en détail

Base de données relationnelle et requêtes SQL

Base de données relationnelle et requêtes SQL Base de données relationnelle et requêtes SQL 1e partie Anne-Marie Cubat Une question pour commencer : que voyez-vous? Cela reste flou Les plans de «Prison Break»? Non, cherchons ailleurs! Et de plus près,

Plus en détail

Les bases de données Page 1 / 8

Les bases de données Page 1 / 8 Les bases de données Page 1 / 8 Sommaire 1 Définitions... 1 2 Historique... 2 2.1 L'organisation en fichier... 2 2.2 L'apparition des SGBD... 2 2.3 Les SGBD relationnels... 3 2.4 Les bases de données objet...

Plus en détail

Chapitre 2. Classes et objets

Chapitre 2. Classes et objets Chapitre 2: Classes et Objets 1/10 Chapitre 2 Classes et objets Chapitre 2: Classes et Objets 2/10 Approche Orientée Objet Idée de base de A.O.O. repose sur l'observation de la façon dont nous procédons

Plus en détail

Bases de données Cours 1 : Généralités sur les bases de données

Bases de données Cours 1 : Généralités sur les bases de données Cours 1 : Généralités sur les bases de données POLYTECH Université d Aix-Marseille [email protected] http://odile.papini.perso.esil.univmed.fr/sources/bd.html Plan du cours 1 1 Qu est ce qu une

Plus en détail

Prénom : Matricule : Sigle et titre du cours Groupe Trimestre INF1101 Algorithmes et structures de données Tous H2004. Loc Jeudi 29/4/2004

Prénom : Matricule : Sigle et titre du cours Groupe Trimestre INF1101 Algorithmes et structures de données Tous H2004. Loc Jeudi 29/4/2004 Questionnaire d'examen final INF1101 Sigle du cours Nom : Signature : Prénom : Matricule : Sigle et titre du cours Groupe Trimestre INF1101 Algorithmes et structures de données Tous H2004 Professeur(s)

Plus en détail