Kader Yildirim
LINQ à 360 degré, Partie 4
Cet article présente les principales fonctionnalités apportées par LINQ to SQL
Par Kader Yildirim publié le 01/08/2007 à 19:29, lu 3924 fois, 7 pages
 5 | Utilisation de LINQ to SQL
Commençons par une utilisation simple qui consiste à afficher le nom de la ville et la rue de la table Adresse :

EntrepriseDataContext edc = new EntrepriseDataContext();

            foreach (Adresse a in edc.Adresses)

                Console.WriteLine(a.Ville + " " + a.Rue);

Dans ce cas tout se passe bien :
 
/content/99963165-48f8-4ea2-8ee1-cf36f376b8c7/ResultatAdresse.PNG
 
Par contre si nous essayons d'afficher le nom et le code contenu dans la table Programme l'exception suivante est générée :
 
/content/99963165-48f8-4ea2-8ee1-cf36f376b8c7/Programme.PNG
 
Ceci est dû au fait que cette table, même si elle a une contrainte d'unicité, ne contient pas de clé primaire. En effet LINQ to SQL a besoin de tables ayant une clé primaire pour gérer l'identité des entités. Dans le monde .Net l'identité d'un objet est sa référence alors que dans le contexte d'une base de données l'identification des tables est basée sur les clés primaires. LINQ to SQL, via le DataContext, maintient le lien entre les deux mondes grâce à une table de correspondances interne.

Si nous ajoutons une clé primaire à cette table alors on obtient bien le résultat attendu :
 
/content/99963165-48f8-4ea2-8ee1-cf36f376b8c7/Programme2.PNG
 
Il en va de même pour la table PersonnelSite. Tant que celle-ci n'a pas de clé primaire toute utilisation directe ou indirecte (via la table Personnel par exemple) génère une exception.

Bien entendu il est possible d'utiliser toutes les facilités fournit par LINQ to SQL et que nous avons déjà eu l'occasion de voir dans les articles précédents. Par exemple :

var q = from p in edc.Projets

                    where p.TypeProjet.Code == "DSI"

                    select p;

 

            foreach (var p in q)

                Console.WriteLine(p.Nom + " " + p.CodeTypeProjet);

La requête générée est visible au niveau de Visual Studio 2008 (je vous laisse apprécier la qualité de cette requête ...) :
 
/content/99963165-48f8-4ea2-8ee1-cf36f376b8c7/Requete.PNG
 
La mise à jour des données est intuitive :

var q = from p in edc.Projets

                    where p.TypeProjet.Code == "DSI"

                    select p;

 

            foreach (var p in q)

                p.Nom = "New " + p.Nom;

            edc.SubmitChanges();

L'appel à la fonction SubmitChanges se charge de détecter les mises à jour et de faire les update nécessaires en base de données. Ce travail est assez compliqué car il faut tout d'abord ordonner les tables en fonction des relations entre elles et suivant l'opération à effectuer (insertion, suppression...) le tout encadré par une transaction qui annule l'opération en cas d'erreurs - heureusement que LINQ to SQL s'en charge pour nous.
Partons du code suivant :

var q = from p in edc.Projets

                   where p.TypeProjet.Code == "DSI"

                   select p;

 

           foreach (var p in q)

               Console.WriteLine(p.Nom + " " + p.CodeTypeProjet);

 

           foreach (var p in q)

               Console.WriteLine(p.Nom + " " + p.CodeTypeProjet);

La variable q ne contient pas le résultat de la requête mais une description de celle-ci et n'est exécutée qu'au moment de l'utilisation réelle. Vous pouvez vérifier ceci en mettant des points d'arrêts dans le code et en utilisant SQL Profiler. En effet q est de type System.Linq.IQueryable dont l'exécution n'est déclenchée que lors de l'appel à GetEnumerator - c'est ce que fait le foreach - : c'est le chargement différé.
Ce mode de fonctionnement pose un problème si on parcourt N fois le résultat car dans ce cas N requêtes sont lancées :
 
/content/99963165-48f8-4ea2-8ee1-cf36f376b8c7/Profiler.PNG
 
Pour éviter ceci il faut convertir q en liste ou en tableau. Par exemple :

var a = q.ToArray();

Le principe du chargement différé est aussi utilisé pour récupérer des données d'une table liée. Par exemple :

var q = from p in edc.Projets

                    where p.CodeTypeProjet == "DSI"

                    select p;

 

            foreach (var p in q)

                Console.WriteLine(p.Nom + " " + p.TypeProjet.Code);

Dans le cas ci-dessus les données de TypeProjet sont chargées lors du premier appel dans Console.WriteLine alors que la liste des projets est chargée lors du premier appel dans la boucle foreach comme on peut le constater dans SQL Profiler :
 
/content/99963165-48f8-4ea2-8ee1-cf36f376b8c7/Liens.PNG
 
Si on souhaite remplacer le chargement différé par un chargement immédiat il est possible d'utiliser la classe DataShape :

DataShape ds = new DataShape();

            ds.LoadWith<Projet>(p => p.TypeProjet);

            edc.Shape = ds;

 

            var q = from p in edc.Projets

                    where p.CodeTypeProjet == "DSI"

                    select p;

 

            foreach (var p in q)

                Console.WriteLine(p.Nom + " " + p.TypeProjet.Code);

Dans ce cas une seule requête est générée :
 
/content/99963165-48f8-4ea2-8ee1-cf36f376b8c7/MonoRequete.PNG
 
 
» Démarrer une discussion
 
Discussion démarée par Mitsuru Furuta le 08/08/2007 à 21:18, 1 commentaire(s).
Discussion démarée par ButhodS le 24/06/2008 à 10:55, 1 commentaire(s).
Discussion démarée par Matthieu Mezil le 08/08/2007 à 16:56, 1 commentaire(s).
Discussion démarée par Matthieu Mezil le 07/08/2007 à 17:37, 1 commentaire(s).
Discussion démarée par Matthieu Mezil le 06/08/2007 à 12:32, 2 commentaire(s).
Discussion démarée par steftanguy le 13/12/2007 à 23:00, 4 commentaire(s).