Dans ce deuxième volet sur Apache Torque, on va s’intéresser aux modifications du modèle de données.
Introduction
Dans le premier article, on a vu comment configurer et utiliser Apache Torque pour générer les entités et tables associées. Dans ce deuxième volet, on va d’abord améliorer la configuration du générateur d’entités puis s’intéresser aux modifications du modèle de données.
Configuration du générateur d’entités
Par défaut, les entités sont créées dans le dossier target/ du projet. C’est bien joli mais nos classes sont définies dans le dossier src/main/. Alors comment modifier le comportement par défaut? Simplement, en ajoutant plusieurs options dans le pom.xml (en gras ci-dessous).
1 <plugin>
2 <groupId>org.apache.torque</groupId>
3 <artifactId>torque-maven-plugin</artifactId>
4 <version>4.0</version>
5 <executions>
6 <execution>
7 <id>generate-sources</id>
8 <phase>generate-sources</phase>
9 <goals>
10 <goal>generate</goal>
11 </goals>
12 <configuration>
13 <packaging>classpath</packaging>
14 <configPackage>org.apache.torque.templates.om</configPackage>
15 <sourceDir>src/main/schema</sourceDir>
16 <defaultOutputDir>src/main/java/</defaultOutputDir>
17 <options>
18 <torque.om.retainSchemaNamesInJavaName>true</torque.om.retainSchemaNamesInJavaName>
19 <torque.om.package>ch.gobothegeek.model</torque.om.package>
20 <torque.database>mysql</torque.database>
21 <torque.om.package.peerPackageSuffix>.peer</torque.om.package.peerPackageSuffix>
22 <torque.om.package.dbObjectPackageSuffix>.dbo</torque.om.package.dbObjectPackageSuffix>
23 <torque.om.package.mapPackageSuffix>.map</torque.om.package.mapPackageSuffix>
24 <torque.om.package.managerPackageSuffix>.mgr</torque.om.package.managerPackageSuffix>
25 <torque.om.package.beanPackageSuffix>.bean</torque.om.package.beanPackageSuffix>
26 <torque.om.package.baseDbObjectPackageSuffix>.base.dbo</torque.om.package.baseDbObjectPackageSuffix>
27 <torque.om.package.basePeerPackageSuffix>.base.peer</torque.om.package.basePeerPackageSuffix>
28 <torque.om.package.baseManagerPackageSuffix>.base.mgr</torque.om.package.baseManagerPackageSuffix>
29 <torque.om.package.baseBeanPackageSuffix>.base.bean</torque.om.package.baseBeanPackageSuffix>
30 </options>
31 </configuration>
32 </execution>
33 <execution>
34 <id>generate-sql</id>
35 <phase>generate-sources</phase>
36 <goals>
37 <goal>generate</goal>
38 </goals>
39 <configuration>
40 <packaging>classpath</packaging>
41 <configPackage>org.apache.torque.templates.sql</configPackage>
42 <sourceDir>src/main/schema</sourceDir>
43 <defaultOutputDir>src/main/schema</defaultOutputDir>
44 <defaultOutputDirUsage>none</defaultOutputDirUsage>
45 <options>
46 <torque.database>mysql</torque.database>
47 </options>
48 </configuration>
49 </execution>
50 </executions>
51 <dependencies>
52 <dependency>
53 <groupId>org.apache.torque</groupId>
54 <artifactId>torque-templates</artifactId>
55 <version>4.0</version>
56 </dependency>
57 </dependencies>
58 </plugin>
C’est plutôt bien, on retrouve les entités dans dans le package ch.gobothegeek.model. Cependant, je ne trouve pas cela tout à fait satisfaisant, j’aurais bien aimé pouvoir séparer les différentes entités selon un regroupement personnalisé. A priori, la documentation n’indique aucune autre possibilité de configuration.
Modification du modèle de données
Dans la vraie vie, on est souvent (quotidiennement?) amené à modifier des tables existantes (ajout d’une colonne, changement de type de colonne). Or, par défaut, Torque génère le fichier de requêtes SQL suivant
C’est bien joli, ça fonctionne toujours mais en production il est difficile de virer des tables sans planter l’application. Dans le pom.xml, avec les autres options Torque, on peut ajouter cette ligne afin que les requêtes de drop ne soient pas ajoutées.
1<torque.sql.generate.drops>false</torque.sql.generate.drops>
Malheureusement c’est tout ce qu’on peut faire. Impossible d’obtenir des requêtes ALTER pour les tables existantes.
Inverser la génération
Comme on l’a vu, les options de générations du SQL et des entités sont finalement vite limitantes dans un contexte de maintenance d’une application utilisée en production. L’autre approche est d’utiliser la base de données pour générer les entités. Il devrait être plus facile de modifier les entités pour qu’elles collent au schéma. Voyons voir comment cela fonctionne.
Modification du pom.xml
Dans le pom, il faut ajouter ceci:
1<execution>
2 <id>generate-schema-from-jdbc</id>
3 <phase>generate-test-sources</phase>
4 <goals>
5 <goal>generate</goal>
6 </goals>
7 <configuration>
8 <packaging>classpath</packaging>
9 <configPackage>org.apache.torque.templates.jdbc2schema</configPackage>
10 <defaultOutputDir>src/main/schema</defaultOutputDir>
11 <defaultOutputDirUsage>none</defaultOutputDirUsage>
12 <options>
13 <torque.jdbc2schema.driver>org.mariadb.jdbc.Driver</torque.jdbc2schema.driver>
14 <torque.jdbc2schema.url>jdbc:mysql://localhost:3306/monProjet</torque.jdbc2schema.url>
15 <torque.jdbc2schema.user>xxx</torque.jdbc2schema.user>
16 <torque.jdbc2schema.password>xxx</torque.jdbc2schema.password>
17 <torque.jdbc2schema.schema>monProjet</torque.jdbc2schema.schema>
18 </options>
19 </configuration>
20 </execution>
Générer le descripteur de schéma avec Maven
Avec la commande “mvn generate-test-sources”, Torque va se connecter à la base, interroger le schéma, créer le fichier de description de schéma “schema.xml” (penser à faire une copie de celui existant, il va être écrasé sans avertissement). A ce stade, on pense pouvoir lancer la génération des entités (spoiler: ça va planter).
Contenu du fichier de description obtenu
1<database name="default">
2 <table name="book">
3 <column name="book_id" type="INTEGER" primaryKey="true"/>
4 <column size="255" name="title" type="VARCHAR" required="true"/>
5 <column size="24" name="isbn" type="VARCHAR" required="true"/>
6 <column name="publisher_id" type="INTEGER" required="true"/>
7 <column name="author_id" type="INTEGER" required="true"/>
8 </table>
9</database>
On constate très vite que ce n’est pas la peine de lancer la génération des entités:
- Le nom de la base n’est pas le bon (“default” alors qu’on se serait attendu à “monProjet”).
- Il manque le paramètre defaultIdMethod sur le tag “database”.
- Les descriptions de base et de colonnes ne sont pas repris (pas grave mais pénible).
- Les namespaces XML sont également absents.
Une fois le fichier de description remis normalisés, on peut générer les entités avec Maven “mvn generate-sources”. On obtient alors les classes nécessaires à la persistance en base. Par contre, encore une fois, toutes les entités seront déposées dans le même package et ce n’est pas génial. Sur un exemple ou une application avec peu d’entités, ça passe. Sur une application métier complexe avec de très nombreuses tables, il faut absolument organiser les entités. Je crois que j’ai trouvé une solution, j’en parlerai dans le troisième article sur Torque.
Conclusion
Dans le premier article, on a vu comment générer des entités et des tables à partir d’un fichier de description XML. Dans cet article, on a le contraire, c’est à dire générer le descripteur à partir du schéma puis générer les entités. A l’usage, même si le descripteur obtenu doit être légèrement modifié manuellement, cette solution est plus souple puisqu’elle évite de générer les requêtes “ALTER” et modifier le descripteur.