Magazine

NHModeler : DSL de génération de code à base d'Oslo / langage M, rien ne se perd, rien ne se crée, tout se transforme en info

Publié le 07 octobre 2009 par Olivier Duval

Flex et Bison

Je me souviens dans ma jeunesse (il y a très peu de temps donc), dans la boite où j'ai commencé mon activité pro, on développait des services de messageries roses télématiques à 1,23 Frs /mn (voire le double en trichant un peu), vous savez l'Internet français, qu'on appelait Minitel sur le réseau X25 de Transpac (CA du minitel en 2007 : 100 millions €, à peine imaginable)

Le moteur Opsion que nous utilisions générait du C, et il fallait donc écrire du C pour nos services. A l'époque, point de bases de données, mais des fichiers indexés au format C-ISAM. A chaque entité, il fallait écrire la génération de l'index, tout un tas de petites choses et surtout des fonctions de recherche sur la structure de données (à l'octet près...) (par catégorie, par nom, ...) en utilisant l'API C-ISAM, ce qui était assez fastidieux, et surtout courageux.

Comme on était de vrais geeks devant un écran noir à fonte verte, avec du vi, il nous fallait trouver un moyen pour automatiser toute cette phase de code plus ou moins toujours la même. J'avais alors créé une petite grammaire (qu'on appellerait DSL maintenant) à base de create table, afin de générer les fichiers C ad-hoc pour chaque table contenant les champs et index souhaités. Pour développer ce genre de programme, un compilateur en gros, nous utilisions le couple Lex & Yacc pour interpréter notre pseudo-langage (les create table avec les champs typés, et les index) afin de générer le code C pour utiliser l'API C-ISAM.

Mais pourquoi tu nous racontes ta p'tite vie de geek Olive ? tout simplement que lorsque vous utilisez NHibernate, la phase mapping, création des classes peut être très rapidement rébarbative. NHModeler se propose de résoudre tout ça, pour nous, informaticiens feignants : à partir d'une grammaire à base d'entités (le modèle), de générer une multitudes de fichiers : le modèle (les class C# de nos entités), les .hbm (le mapping), le fichier SQL de création des tables, fichiers qu'on aura plus qu'à intégrer à notre projet. Cette génération s'apparente à du MDA (Model Driven Architecture), avec ses inconvénients et ses avantages.

NHModeler

NHModeler a besoin du SDK Oslo. Également, afin de lancer la compilation de votre DSL, il manque 2 assembly dans les binaires fournis : log4net et les Iesi.Collections, les 2 pourront être pris de vos binaires NHibernate.

Comme toujours, on souhaite représenter la relation suivante :

NHModeler : DSL de génération de code à base d'Oslo / langage M, rien ne se perd, rien ne se crée, tout se transforme en info

une relation many-to-many dans le langage NHibernate.

On déclare cette relation dans le langage NHModeler, contenu d'un fichier nommé respassoc.nhm :

NHModel 
{
Entity Responsable
{
Nom: string(30)
Prenom: string(30)
Assocs->Responsables: Assoc *
} IN Responsables
 
Entity Assoc
{
Libelle: string(30)
Description: string
Responsables<-Assocs: Responsable *
} IN Assocs
}

note : si l'on ne souhaite pas de modifications en cascade entre les 2 entités, il suffit d'ajouter le mot clé weak derrière les relations :

Assocs->Responsables: Assoc * weak
Responsables<-Assocs: Responsable * weak

il reste à exécuter la génération de code, de notre fichier respassoc.nhm qui contient notre description précédente, pour le dialect SQL Server 2005 :

NHModeller.Console -a:Model  -d:MsSql2005 -ddl:dbscript.sql -out:"c:\temp\mymodel" respassoc.nhm

on obtient l'ensemble utile à NHibernate, les classes, hbm et le script SQL de création de tables

NHModeler

dans le script de création nous avons bien entendu les 3 tables qui représentent notre relation : Responsables, Assocs et la table de jointure Assoc_Responsable

CREATE TABLE Responsables (
Id INT IDENTITY NOT NULL,
Nom NVARCHAR(30) NOT NULL,
Prenom NVARCHAR(30) NOT NULL,
PRIMARY KEY (Id)
);
 
CREATE TABLE Assoc_Responsable (
Responsable_Id INT NOT NULL,
Assoc_Id INT NOT NULL,
PRIMARY KEY (Assoc_Id, Responsable_Id)
);
 
CREATE TABLE Assocs (
Id INT IDENTITY NOT NULL,
Libelle NVARCHAR(30) NOT NULL,
Description NVARCHAR(255) NOT NULL,
PRIMARY KEY (Id)
);
ALTER TABLE Assoc_Responsable ADD constraint FKFF76651DD5384AF6 FOREIGN KEY (Assoc_Id) REFERENCES Assocs;
ALTER TABLE Assoc_Responsable ADD constraint FKFF76651D9647BEE3 FOREIGN KEY (Responsable_Id) REFERENCES Responsables;

et les *.hbm.xml :

<?xml version='1.0' ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Model" namespace="Model">
<class name="Responsable" table="Responsables">
<id name="Id" column="Id" access="field.camelcase-underscore">
<generator class="native" />
</id>
<property name="Nom" column="Nom" type="String" not-null="true" length="30" />
<property name="Prenom" column="Prenom" type="String" not-null="true" length="30" />
<set table="Assoc_Responsable" access="field.camelcase-underscore" name="Assocs" cascade="none">
<key column="Responsable_Id" />
<many-to-many class="Assoc" outer-join="true" column="Assoc_Id" />
</set>
</class>
</hibernate-mapping>
 
<?xml version='1.0' ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Model" namespace="Model">
<class name="Assoc" table="Assocs">
<id name="Id" column="Id" access="field.camelcase-underscore">
<generator class="native" />
</id>
<property name="Libelle" column="Libelle" type="String" not-null="true" length="30" />
<property name="Description" column="Description" type="String" not-null="true" />
<set table="Assoc_Responsable" access="field.camelcase-underscore" name="Responsables" cascade="none">
<key column="Assoc_Id" />
<many-to-many class="Responsable" outer-join="true" column="Responsable_Id" />
</set>
</class>
</hibernate-mapping>

La documentation est riche avec des exemples, le langage est assez complet et semble répondre aux principales fonctionnalités de NHibernate, ce projet vaut la peine de s'y arrêter, au moins pour se rappeller de bons souvenirs

Petit défaut : pas de sources disponibles.


Retour à La Une de Logo Paperblog

A propos de l’auteur


Olivier Duval 4 partages Voir son profil
Voir son blog

l'auteur n'a pas encore renseigné son compte l'auteur n'a pas encore renseigné son compte

Dossier Paperblog