Kader Yildirim
LINQ à 360 degré, Partie 3
Cet article présente les principales fonctionnalités apportées par LINQ to DataSet
Par Kader Yildirim publié le 01/07/2007 à 20:47, lu 3656 fois, 6 pages
 4 | LINQ et les DataSets non typés
Si nous transformons le code précédent (sans tirer parti des DataRelations, que nous verrons dans un second temps) pour utiliser les possibilités offertes par LINQ to DataSet nous obtenons :

static void DoJobNewWay1(DataSet ds)

        {

            var CommandesPassees = from client in ds.Tables["Client"].AsEnumerable()

                                   join cmd in ds.Tables["Commande"].AsEnumerable()

                                   on (int)client["ID"] equals (int)cmd["ClientID"]

                                   select new

                                   {

                                       CommandeID = (int)cmd["ID"],

                                       Client = (string)client["Nom"],

                                       Tel = DBNull.Value == client["Tel"] ? null : (string)client["Tel"],

                                       Quantite = (int)cmd["Quantite"]

                                   };

 

            foreach (var c in CommandesPassees)

                Console.WriteLine(c.CommandeID + " : " + c.Client + " : " + c.Tel + " : " + c.Quantite);

        }

La notation est déjà plus proche de nos habitudes SQL. Nous pouvons relever plusieurs points dans ce code :
  • Nous n'avons plus besoin de la classe Resultat grâce à l'utilisation des classes anonymes de .Net 3.0 et +
  • Nous pouvons enfin faire des jointures sur les DataSet simplement. Je vous invite à jeter un oeil à un code générique de gestion des jointures sur le site suivant et vous verrez combien LINQ est précieux sur ce point.
  • L'appel à l'extension methodAsEnumerable pour convertir une DataTable en une structure énumérable
  • Sur la clause ON de la jointure l'égalité ne se fait pas avec l'opérateur == mais avec le mot clé equals. En effet comme == est spécifique à C# et que LINQ est multi-langage, il a fallu créer un mot clé indépendant des langages de programmation
  • Enfin la gestion des valeurs null ne peut pas se faire simplement en faisant un cast du champ concerné en string?. Le code suivant est refusé par le compilateur :

    Tel = (string?)client["Tel"]

    En effet la conversion ne peut pas se faire vers de types nullables, il faut donc les gérer à la main comme suit :

    Tel = DBNull.Value == client["Tel"] ? null : (string)client["Tel"]

Aussi le fait de passer directement par les DataRow pour récupérer les valeurs de champs nécessite un cast lors de la requête. Cet inconvénient peut être résolu en utilisant la méthode Field qui permet de récupérer le contenu d'un champ de manière typé :

static void DoJobNewWay2(DataSet ds)

        {

            var CommandesPassees = from client in ds.Tables["Client"].AsEnumerable()

                                   join cmd in ds.Tables["Commande"].AsEnumerable()

                                   on client.Field<int>("ID") equals cmd.Field<int>("ClientID")

                                   select new

                                   {

                                       CommandeID = cmd.Field<int>("ID"),

                                       Client = client.Field<string>("Nom"),

                                       Tel = client.Field<string>("Tel"),

                                       Quantite = cmd.Field<int>("Quantite")

                                   };

 

            foreach (var c in CommandesPassees)

                Console.WriteLine(c.CommandeID + " : " + c.Client + " : " + c.Tel + " : " + c.Quantite);

        }

Vous noterez au passage que la méthode Field gère aussi le cas des valeurs null. En effet elle retourne null si la valeur est null au lieu de DBNull, ce qui permet de faire abstraction de ce type qui n'existe que parce qu'au lancement de .Net les types nullables (int? i par exemple) n'existaient pas à ce moment là.

Si on jette un oeil au code de la méthode Field qui se trouve dans System.Data.Entity.dll avec Reflector vous verrez :
 
/content/94bd08a5-6ce2-43ac-8921-fd2a8432ba04/GestionDesNULLs1.PNG
 
Et si on regarde de plus près sur la fonction InternalField on peut voir comment sont gérées les valeurs null :
 
/content/94bd08a5-6ce2-43ac-8921-fd2a8432ba04/GestionDesNULLs2.PNG
 
Comme dans notre DataSet il existe des DataRelation entre les DataTables il est possible de les utiliser avec LINQ, ce qui simplifie encore le code et évite des jointures inutiles. Le code devient alors :

static void DoJobNewWay3(DataSet ds)

        {

            var CommandesPassees = from client in ds.Tables["Client"].AsEnumerable()

                                   from cmd in client.GetChildRows("CommandeClient").AsEnumerable()

                                   select new

                                   {

                                       CommandeID = cmd.Field<int>("ID"),

                                       Client = client.Field<string>("Nom"),

                                       Tel = client.IsNull("Tel") ? "-inconnu-" : client.Field<string>("Tel"),

                                       Quantite = cmd.Field<int>("Quantite")

                                   };

 

            foreach (var c in CommandesPassees)

                Console.WriteLine(c.CommandeID + " : " + c.Client + " : " + c.Tel + " : " + c.Quantite);

        }

Vous noterez au passage que dans ce dernier cas de figure on utilise la méthode IsNull du DataRow pour formater le résultat.
 
» Démarrer une discussion
 
Discussion démarée par Matthieu Mezil le 02/07/2007 à 16:38, 2 commentaire(s).