Développons en Java avec Eclipse 0.80.1 | |
Copyright (C) 2003-2008 Jean-Michel DOUDOUX | (date de publication : 26/12/2008) |
|
Dali est un plug-in proposant de fournir des outils pour faciliter le mapping objet/relationnel.
Dali est un sous projet du projet WTP dont le but est de faciliter la mise en oeuvre de l'API JPA (Java Persistence API) définie par la JSR 220.
La page officiel du projet est l'url : http://www.eclipse.org/dali.
Les versions utilisées dans cette section sont :
Eclipse |
3.2.1 |
WTP |
1.5.1 |
Dali |
0.5 |
MySQL |
4.1 |
API JPA |
Implémentation de référence (toplink-essentials.jar) fournie avec GlassFish |
La version utilisée du plug-in dans cette section est en cours développement mais elle propose déjà des fonctionnalités intéressantes.
Il faut ouvrir la perspective Java Perspective : sélectionnez l'option « Fenêtre / ouverture la perspective » du menu principal.
Sélectionnez « Java Persistence » et cliquez sur le bouton « OK » pour ouvrir la perspective.
Créez un nouveau projet de type Java associé à un JRE 1.5 minimum.
Il faut ajouter le support de l'API Java Persistence au projet.
Sélectionnez le projet dans l'explorateur de projet et utiliser l'option Java Persistence / Add Java Persistence » : une boîte de dialogue perme de saisir les informations requises.
Cliquez sur le lien « Add connections »
Saisissez les informations concernant la base de données et sa connexion.
Cliquez sur le bouton « Tester la connexion »
Si la base de données n'est pas trouvée, un message est affiché :
Si la base de données est trouvée, un message d'information est affiché
Cliquez sur le bouton « OK » puis sur le bouton « Terminer »
Cliquez sur le bouton « Configure the project build path »
Cliquez sur l'onglet « Bibliothèques », puis sur le bouton « Ajouter des fichiers jar externes »
Sélectionnez le fichier toplink-essentials.jar, puis cliquez sur le bouton « Ouvrir » et sur le bouton « OK ».
Sélectionnez le schéma de la base de données (dans le cas de MySQL, c'est la base de données elle-même)
Saisissez le nom de la classe du Provider de Persistence : oracle.toplink.essentials.PersistenceProvider et le nom de l'unité de persistence puis cliquez sur le bouton « Terminer ».
Le fichier persistence.xml est créé dans le répertoire META-INF
Ce fichier xml est le fichier de configuration de l'API JPA.
La connexion à la base de données est affichée dans la vue « Explorateur de base de données ».
Créez une nouvelle entité de type « Java Persistence / Entity »
Cliquez sur le bouton « Suivant »
Saisissez le nom du package et le nom de la classe puis cliquez sur le bouton « Terminer ».
La classe est générée et son contenu est ouvert dans un éditeur.
La classe est marquée avec l'annotation @Entity : elle est en erreur car aucun champ de la classe n'est marqué avec l'annotation @Id qui est obligatoire.
La vue « Persistence Outline » affiche la nouvelle entity créée.
La vue « Persistence properties » affiche les propriétés de cet élément.
Cette vue indique que l'entité est mappée sur le table Personne.
Il faut ajouter les champs dans l'entité :
La vue « Persistence outline » affiche les champs ajoutés
Il faut réaliser le mapping entre les champs de l'entité et les champs de la table
Dans la vue « Persistence outline », sélectionnez le champ id.
Modifiez le champ « Map As » en sélectionnant le type « Id » : le code de la classe est modifié pour ajouter l'annotation @Id sur le champ.
L'icône du champ est aussi modifié dans la vue « Persistence outline » pour indiquer que ce champ est la clé.
Sélectionnez le type « Basic » pour les deux autres champs. Comme le nom des champs correspond exactement dans la table et dans la classe, le mapping est automatique.
L'entité ainsi modifiée est la suivante
L'éditeur affiche les erreurs de mapping si certaines sont détectées.
Il faut rajouter dans le classpath de l'application la bibliothèque du pilote JDBC (dans cet exemple c'est la base de données MySQL qui est utilisée : le fichier mysql-connector-java-3.1.10-bin.jar est donc ajouté au classpath du projet).
Il faut enrichir le fichier persistence.xml avec les propriétés de connexion à la base de données.
Exemple : |
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="1.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="test_dali">
<provider>
oracle.toplink.essentials.PersistenceProvider
</provider>
<class>com.jmdoudoux.test.dali.Personne</class>
<properties>
<property name="toplink.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="toplink.jdbc.url" value="jdbc:mysql://localhost/test" />
<property name="toplink.jdbc.user" value="root" />
<property name="toplink.jdbc.password" value="" />
<property name="toplink.logging.level" value="INFO" />
</properties>
</persistence-unit>
</persistence> |
Il faut enfin écrire le code qui va utiliser l'API JPA et les différentes entités de mapping générées.
Exemple : obtenir la personne dont l'identifiant vaut 1
Exemple : |
package com.jmdoudoux.test.dali;
import javax.persistence.Persistence;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityManager;
public class TestDali {
public static void main(String[]argv) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("test_dali");
EntityManager em = emf.createEntityManager();
Personne personne = em.find(Personne.class, 1l);
System.out.println("Personne.nom="+personne.getNom());
em.close();
emf.close();
}
} |
Résultat d'exécution : |
[TopLink Info]: 2006.11.06
06:01:18.134--ServerSession(25378506)--TopLink, version:
Oracle TopLink Essentials - 2006.4 (Build 060412)
[TopLink Info]: 2006.11.06
06:01:19.757--ServerSession(25378506)--file:/C:/Documents%20and%20Settings
/jumbo/workspace/TestDali/bin-test_dali
login successful
Personne.nom=nom1
[TopLink Info]: 2006.11.06
06:01:20.117--ServerSession(25378506)--file:/C:/Documents%20and%20Settings
/jumbo/workspace/TestDali/bin-test_dali
logout successful |
Avant de pouvoir utiliser les fonctionnalités du plug-in, il est nécessaire d'être connecté à la base de données afin de pouvoir contrôles les informations de mapping.
Il est possible de le faire dans les propriétés du projet.
Sélectionnez “Java Persistence” et cliquez sur le bouton “Reconnect”.
Il est aussi possible d'utiliser la vue « Explorateur de base de données ».
Sélectionnez la connexion et cliquez sur l'option "Reconnecter" du menu contextuel
Une boîte de dialogue permet de saisir le login et le mot de passe de connexion.
Si la connexion échoue alors un message d'erreur affiche la pile d'appel des exceptions
Si la connexion réussie, la base de données est affichée avec une petite icône verte et il est possible de parcourir l'arborescence des éléments qui la compose.
Le plug-in propose une fonctionnalité pour générer automatiquement les entités à par des tables d'une base de données connectées.
Sélectionnez le projet et utilisez l'option Java « Java Persistence/Generate entities »
Saisissez le nom du package, sélectionnez les tables concernées et cliquez sur le bouton « Terminer ».
Si une classe correspondant à une entité existante, alors un message de confirmation est affiché :
Les différentes classes des entités sont générées.
Dali propose un éditeur dédié à la modification du fichier persistence.xml. C'est l'éditeur par défaut de ce fichier. Il propose deux onglets : Conception et Source
La modification du fichier est facilitée par l'éditeur qui intègre le schéma du document XML.
Dans l'explorateur de packages, il faut sélectionner le fichier persistence.xml et utiliser l'option « Persistence / Synchronize classes » du menu contextuel.
Chaque nouvelle entité définie dans les sources est automatiquement ajoutée dans un tag <class> du fichier persistence.xml.
Le travail de synchronisation est effectué en tache de fond.
Il est possible de transformer une classe existante en Entity.
Exemple :
Sélectionnez la classe (ne sélectionnez pas le fichier .java mais la classe directement) dans l'explorateur de packages et utiliser l'option « Persistence / Make Java Persistence Entity ».
La clause import nécessaire et l'annotation « Entity » sont ajoutées :
Dans l'éditeur de code, sélectionnez la classe puis affichez la vue « Persistence Properties »
Dans la liste déroulante « Map As » sélectionnez « Entity »
La boîte de dialogue s'enrichie avec les propriétés relative au type Entity.
Dans la liste déroulante Table, sélectionnez la table infopersonne
Le code de l'entité est modifié
L'exemple de cette section va utiliser les tables ci dessous
La table « personne » contient les données suivantes :
La table « infopersonne » contient les données suivantes :
Il faut mettre en place l'association en modifiant la classe Personne
Exemple : |
package com.jmdoudoux.test.dali;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Basic;
import javax.persistence.Table;
@Entity
@Table(name="personne")
public class Personne {
@Id
private Long idPersonne;
@Basic
private String nomPersonne;
@Basic
private String prenomPersonne;
private InfoPersonne idInfoPersonne;
} |
Dans l'éditeur de code, sélectionnez le champ idInfoPersonne
Dans la vue « Persistence Properties », l'onglet « Join columns » permet de modifier les options de la jointure
Cochez la case « Override Default »
Sélectionnez la ligne dans la liste et cliquez sur le bouton « Edit » pour ouvrir la boîte de dialogue « Edit Join Column »
Dans la liste déroulante Name, sélectionnez le champ idInfoPersonne
Cliquez sur le bouton « OK » pour modifier le code de l'entité
Exemple : |
@OneToOne
@JoinColumn(name="idInfoPersonne", referencedColumnName = "idInfoPersonne")
private InfoPersonne idInfoPersonne; |
Sources complets de l'exemple :
Le fichier Persistence.xml : |
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="test_dali">
<provider>
oracle.toplink.essentials.PersistenceProvider
</provider>
<class>com.jmdoudoux.test.dali.InfoPersonne</class>
<class>com.jmdoudoux.test.dali.Personne</class>
<properties>
<property name="toplink.jdbc.driver"
value="com.mysql.jdbc.Driver" />
<property name="toplink.jdbc.url"
value="jdbc:mysql://localhost/test" />
<property name="toplink.jdbc.user" value="root" />
<property name="toplink.jdbc.password" value="" />
<property name="toplink.logging.level" value="INFO" />
</properties>
</persistence-unit>
</persistence> |
Le fichier InfoPersonne.java : |
package com.jmdoudoux.test.dali;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Basic;
@Entity
@Table(name="infopersonne")
public class InfoPersonne {
@Id
@Column(name="idInfoPersonne")
private long idInfoPersonne;
@Basic
private String commentaires;
public String getCommentaires() {
return commentaires;
}
public void setCommentaires(String commentaires) {
this.commentaires = commentaires;
}
public long getIdInfoPersonne() {
return idInfoPersonne;
}
public void setIdInfoPersonne(long idInfoPersonne) {
this.idInfoPersonne = idInfoPersonne;
}
} |
Le fichier Personne.java |
package com.jmdoudoux.test.dali;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Basic;
import javax.persistence.Table;
import javax.persistence.OneToOne;
import javax.persistence.JoinColumn;
@Entity
@Table(name="personne")
public class Personne {
@Id
private Long idPersonne;
@Basic
private String nomPersonne;
@Basic
private String prenomPersonne;
@OneToOne
@JoinColumn(name="idInfoPersonne", referencedColumnName = "idInfoPersonne")
private InfoPersonne idInfoPersonne;
public Long getId() {
return idPersonne;
}
public void setId(Long id) {
this.idPersonne = id;
}
public String getNom() {
return nomPersonne;
}
public void setNom(String nom) {
this.nomPersonne = nom;
}
public String getPrenom() {
return prenomPersonne;
}
public void setPrenom(String prenom) {
this.prenomPersonne = prenom;
}
public InfoPersonne getIdInfoPersonne() {
return idInfoPersonne;
}
public void setIdInfoPersonne(InfoPersonne idInfoPersonne) {
this.idInfoPersonne = idInfoPersonne;
}
} |
Le fichier TestDali.java |
package com.jmdoudoux.test.dali;
import javax.persistence.Persistence;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityManager;
public class TestDali {
public static void main(String[]argv) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("test_dali");
EntityManager em = emf.createEntityManager();
Personne personne = em.find(Personne.class, 1l);
System.out.println("Personne.nom="+personne.getNom());
System.out.println("commentaires = "
+personne.getIdInfoPersonne().getCommentaires());
em.close();
emf.close();
}
} |
Résultat d'exécution : |
[TopLink Info]: 2006.11.09
07:06:29.267--ServerSession(31999426)--TopLink, version:
Oracle TopLink Essentials - 2006.4 (Build 060412)
[TopLink Info]: 2006.11.09
07:06:30.679--ServerSession(31999426)--file:/C:/Documents%20and%20Settings
/jumbo/workspace/TestDali/bin-test_dali
login successful
Personne.nom=nom1
commentaires = commentaires de test
[TopLink Info]: 2006.11.09 07:06:31.009--ServerSession(31999426)--file:/C:
/Documents%20and%20Settings
/jumbo/workspace/TestDali/bin-test_dali
logout successful |
L'exemple fonctionne correctement car la clé étrangère existe. Il est nécessaire de gérer le cas si la clé n'existe pas.
Exemple : demander les informations de la personne ayant pour id 2 |
...
Personne personne = em.find(Personne.class, 2l);
... |
Résultat : |
[TopLink Info]: 2006.11.10
05:17:15.523--ServerSession(31999426)--TopLink, version:
Oracle TopLink Essentials - 2006.4 (Build 060412)
[TopLink Info]: 2006.11.10
05:17:16.895--ServerSession(31999426)--file:/C:/Documents%20and%20Settings
/jumbo/workspace/TestDali/bin-test_dali
login successful
Personne.nom=nom2
Exception in thread "main" java.lang.NullPointerException
at com.jmdoudoux.test.dali.TestDali.main(TestDali.java:16) |
Il suffit de tester si la clé étrangère est différente de null.
Exemple : |
Personne personne = em.find(Personne.class, 2l);
System.out.println("Personne.nom=" + personne.getNom());
if (personne.getIdInfoPersonne() != null) {
System.out.println("commentaires = "
+ personne.getIdInfoPersonne().getCommentaires());
} |
|