Utilisation de LINQ avec la base MySQL
Aviez-vous pensé d’utiliser LINQ avec une autre base de données que SQL Server ? Dans le Framework.NET vous ne disposez malheureusement pas en natif d’outils qui vous permettent d’utiliser LINQ avec une base de données comme par exemple MySQL. Vous pouvez cependant vous tourner vers les providers commerciaux ou utiliser une solution alternative telle que DBLinq qui aujourd’hui gère MySQL, Oracle et PostgreSql en s’appuyant sur LinqToSql. Si telle est votre problématique, ce tutoriel a pour but de vous donner des bases nécessaires pour bien démarrer avec LINQ et MySQL. Dans le cadre de notre article nous allons réaliser une application C# qui n’a pas une réelle utilité à part la démonstration de l’utilisation de LINQ avec la base de données MySQL (version 5.1.30). Afin de simplifier la démarche nous allons créer une application de type console (sans le code GUI) qui permet de nous concentrer sur un cas concret d’utilisation.
Prerequis
Dans le cadre de notre application les outils suivants sont nécessaires :
- Le serveur MySQL : http://dev.mysql.com/downloads/mysql/5.1.htm.
- La bibliothèque DbLinq v.0.18 : http://code.google.com/p/dblinq2007/.
- Visual Studio 2008 Express : http://www.microsoft.com/Express/.
Une fois les prérequis téléchargés et installés, nous pouvons passer au développement de l’application.
Base de données
La base de données utilisée dans ce tutoriel s’appelle « gestcomm ». Elle est composée de 4 tables suivantes :
- ARTICLE
- COMMANDE
- LIGNES
- TIERS
Les scripts suivants vous faciliteront la création des tables et du jeu d’essai pour notre petite application :
ARTICLE
USE gestcomm;
CREATE TABLE `article` (
`ART_ID` int(11) NOT NULL DEFAULT '0',
`ART_LIBELLE` varchar(20) DEFAULT NULL,
`ART_PRIXBASEHT` decimal(10,0) DEFAULT NULL,
PRIMARY KEY (`ART_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
insert into `gestcomm`.`article`(`ART_ID`,`ART_LIBELLE`,`ART_PRIXBASEHT`) values (1,'IPOD',149);
insert into `gestcomm`.`article`(`ART_ID`,`ART_LIBELLE`,`ART_PRIXBASEHT`) values (2,'XBOX360',234);
insert into `gestcomm`.`article`(`ART_ID`,`ART_LIBELLE`,`ART_PRIXBASEHT`) values (3,'PSP3',399);
insert into `gestcomm`.`article`(`ART_ID`,`ART_LIBELLE`,`ART_PRIXBASEHT`) values (4,'PSP',150);
insert into `gestcomm`.`article`(`ART_ID`,`ART_LIBELLE`,`ART_PRIXBASEHT`) values (5,'WII',200);
COMMANDE
USE gestcomm;
CREATE TABLE `commande` (
`CDE_ID` int(11) NOT NULL DEFAULT '0',
`CDE_NUM` varchar(10) DEFAULT NULL,
`CDE_DATE` date DEFAULT NULL,
`TRS_ID` int(11) DEFAULT NULL,
PRIMARY KEY (`CDE_ID`),
KEY `TRS_ID` (`TRS_ID`),
CONSTRAINT `commande_ibfk_1` FOREIGN KEY (`TRS_ID`) REFERENCES `tiers` (`TRS_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
insert into `gestcomm`.`commande`(`CDE_ID`,`CDE_NUM`,`CDE_DATE`,`TRS_ID`) values (1,'CDE 1','2009-01-02 00:00:00',1);
insert into `gestcomm`.`commande`(`CDE_ID`,`CDE_NUM`,`CDE_DATE`,`TRS_ID`) values (2,'CDE 2','2009-01-08 00:00:00',1);
insert into `gestcomm`.`commande`(`CDE_ID`,`CDE_NUM`,`CDE_DATE`,`TRS_ID`) values (3,'CDE 3','2009-01-13 00:00:00',1);
insert into `gestcomm`.`commande`(`CDE_ID`,`CDE_NUM`,`CDE_DATE`,`TRS_ID`) values (4,'CDE 4','2009-01-06 00:00:00',2);
insert into `gestcomm`.`commande`(`CDE_ID`,`CDE_NUM`,`CDE_DATE`,`TRS_ID`) values (5,'CDE 5','2009-01-21 00:00:00',2);
insert into `gestcomm`.`commande`(`CDE_ID`,`CDE_NUM`,`CDE_DATE`,`TRS_ID`) values (6,'CDE 6','2009-02-04 00:00:00',3);
LIGNES
USE gestcomm;
CREATE TABLE `lignes` (
`LGN_ID` int(11) NOT NULL DEFAULT '0',
`LGN_QTE` int(11) DEFAULT NULL,
`LGN_TOTALHT` decimal(10,0) DEFAULT NULL,
`CDE_ID` int(11) DEFAULT NULL,
`ART_ID` int(11) DEFAULT NULL,
PRIMARY KEY (`LGN_ID`),
KEY `CDE` (`CDE_ID`),
KEY `ART` (`ART_ID`),
CONSTRAINT `ART` FOREIGN KEY (`ART_ID`) REFERENCES `article` (`ART_ID`),
CONSTRAINT `CDE` FOREIGN KEY (`CDE_ID`) REFERENCES `commande` (`CDE_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
insert into `gestcomm`.`lignes`(`LGN_ID`,`LGN_QTE`,`LGN_TOTALHT`,`CDE_ID`,`ART_ID`) values (1,2,468,1,2);
insert into `gestcomm`.`lignes`(`LGN_ID`,`LGN_QTE`,`LGN_TOTALHT`,`CDE_ID`,`ART_ID`) values (2,10,3990,1,3);
insert into `gestcomm`.`lignes`(`LGN_ID`,`LGN_QTE`,`LGN_TOTALHT`,`CDE_ID`,`ART_ID`) values (3,5,745,2,1);
insert into `gestcomm`.`lignes`(`LGN_ID`,`LGN_QTE`,`LGN_TOTALHT`,`CDE_ID`,`ART_ID`) values (4,2,798,3,3);
insert into `gestcomm`.`lignes`(`LGN_ID`,`LGN_QTE`,`LGN_TOTALHT`,`CDE_ID`,`ART_ID`) values (5,15,2250,3,4);
insert into `gestcomm`.`lignes`(`LGN_ID`,`LGN_QTE`,`LGN_TOTALHT`,`CDE_ID`,`ART_ID`) values (6,1,200,3,5);
insert into `gestcomm`.`lignes`(`LGN_ID`,`LGN_QTE`,`LGN_TOTALHT`,`CDE_ID`,`ART_ID`) values (7,1,200,4,5);
insert into `gestcomm`.`lignes`(`LGN_ID`,`LGN_QTE`,`LGN_TOTALHT`,`CDE_ID`,`ART_ID`) values (8,10,2340,5,2);
insert into `gestcomm`.`lignes`(`LGN_ID`,`LGN_QTE`,`LGN_TOTALHT`,`CDE_ID`,`ART_ID`) values (9,6,894,6,1);
insert into `gestcomm`.`lignes`(`LGN_ID`,`LGN_QTE`,`LGN_TOTALHT`,`CDE_ID`,`ART_ID`) values (10,10,1500,6,5);
TIERS
USE gestcomm;
CREATE TABLE `tiers` (
`TRS_ID` int(11) NOT NULL DEFAULT '0',
`TRS_NOM` varchar(30) DEFAULT NULL,
PRIMARY KEY (`TRS_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
insert into `gestcomm`.`tiers`(`TRS_ID`,`TRS_NOM`) values (1,'JASKULA');
insert into `gestcomm`.`tiers`(`TRS_ID`,`TRS_NOM`) values (2,'NODEVO');
insert into `gestcomm`.`tiers`(`TRS_ID`,`TRS_NOM`) values (3,'DUPONT');
Procédure stockée
A titre d’exemple nous utiliserons aussi une procédure stockée qui a pour but de nous renvoyer une commande pour un ID tiers passé en paramètre. En voici le code :
CREATE PROCEDURE gestcomm.`CommandesPourTier`(idTiers int)
BEGIN
SELECT * FROM commande WHERE TRS_ID = idTiers;
END;
Modèle métier
Avant de nous lancer dans le développement de notre application, nous allons créer notre modèle métier que nous pouvons illustrer de manière suivante :
Comme vous pouvez le constater le modèle est très simple à comprendre. Un tiers (client) peut passer une ou plusieurs commandes, en revanche une commande est passée par un tiers. Une commande est constituée d’une ou plusieurs lignes et une ligne représente un article. C’est une version très simplifiée d’un système de prise de commandes.
Génération des classes C#
Une fois notre base de données est créée, nous devons générer nos classes C#. Il n’y a malheureusement pas de support graphique pour les modèles, à l’instar de LinqToSql. Le DataContext doit être donc généré via une adaptation de SQLMetal appelé DBMetal, comme aux premières heures de LINQ. DBMetal est un projet permettant de générer du code source en s’appuyant sur des schémas de bases de données. Vous trouverez le générateur DBMetal.exe dans l’archive zip de la bibliothèque DbLinq que vous avez téléchargé.
Nous allons donc générer pour le besoin de notre application le DataContext appelé GestComm, il sera contenu dans le fichier du même nom avec l’extension .cs (pour C#). Le DataContext nous pouvons résumer en tant qu’ « unité de travail ». Il est responsable de récupérer plusieurs objets à l’aide d’une ou plusieurs requêtes, d’apporter des changements aux objets (si l’utilisateur les a modifié) et de persister les changements dans la base de données. Afin de générer notre fichier nous devons taper la commande suivante dans la console Windows :
bin\DbMetal.exe -provider=MySql -database:GestComm -server:localhost -user:LinqUser -password:linq2 -namespace:GestComm -code:GestComm.cs -sprocs
Quelques explications concernant la ligne de commande :
- Provider : indique à DbMetal à quelle base de données on désire se connecter. Les autres choix possibles sont Oracle et PostgreSQL
- Database : le nom de la base de données d’après laquelle nous souhaitons générer nos classes C#.
- Server : le serveur MySQL où se trouve la base de données.
- User : L’utilisateur avec lequel DbMetal peut se connecter pour générer nos classes.
- Password : Le mot de passe de l’utilisateur.
- Namespace : Indique l’espace de nom dans lequel seront générées nos classes.
- Code : Le nom du fichier dans lequel le générateur sauvegardera les classes.
- Sprocs : indique à DbMetal d’extraire également les procédures stockées.
Remarque : Afin que la génération réussisse, faites bien attention que l’utilisateur « LinqUser » ait les droits en sélection à la table système mysql.proc qui est nécessaire pour la génération du code source.
A la fin de la génération vous devriez avoir un message similaire à celui-ci :
Ce fichier contient le mapping entre la base de données MySQL et le code source. Une fois le fichier est généré nous pouvons le joindre à notre application.
En regardant le fichier de plus près, vous comprendrez vite grâce aux attributs quel élément de la base de données est mappé dans le fichier. Nous pouvons prendre à titre d’exemple la table ARTICLE qui dans le fichier GestComm.cs est représentée par une classe C# de cette manière :
[Table(Name = "GestComm.article")]
public partial class Article : INotifyPropertyChanged
{
Analogiquement nous trouverons aussi tous les éléments de la base de données comme les tables, les colonnes et les procedures stockées.
Passer à l’action
Une fois toutes ces étapes accomplies nous pouvons passer à l’écriture de notre application. Tout d’abord il faut commencer par ajouter les bonnes références :
Vous pouvez facilement les invoquer afin de les exécuter. Dans notre exemple nous avons créé une procédure stockée « CommandePourTiers(idTiers int) » qui prend en paramètre l’identifiant d’un tiers et retourne toutes ses commandes. Le résultat retourné est du type DataSet. L’extrait du code ci-dessous illustre son utilisation :
System.Data.DataSet result = db.CommandesPourTier(1);
Insertions
Il est également très simple d’insérer de données. Dans l’exemple ci-dessous nous allons insérer un tiers dans la base MySQL. Voici le code qui permet de le réaliser :
db.Tiers.InsertOnSubmit(new Tiers { TRSID = 4, TRSNoM = "Martin" });
db.SubmitChanges();
Suppressions
De même nous pouvons aussi facilement supprimer le dernier tiers ajouté dans l’exemple ci-dessus. Voici l’extrait du code qui permet de réaliser cette opération :
db.Tiers.DeleteOnSubmit(db.Tiers.Last());
db.SubmitChanges();
Ajouter un commentaire