Java Persistence API (la suite) Quelques liens : La page JPA chez Sun http://java.sun.com/javaee/technologies/persistence.jsp Javadoc de l’API JPA 1.0 (JEE 5) http://java.sun.com/javaee/5/docs/api/javax/persistence/package-summary.html Javadoc de l’API JPA 2.0 (JEE 6) http://java.sun.com/javaee/6/docs/api/javax/persistence/package-summary.html Le tutorial JPA 1.0 (JEE 5) http://java.sun.com/javaee/5/docs/tutorial/doc/bnbpy.html Le tutorial JPA 2.0 (JEE 6) http://java.sun.com/javaee/6/docs/tutorial/doc/bnbpy.html La page de Wikipedia http://en.wikipedia.org/wiki/Java Persistence API De très bons exemples http://schuchert.wikispaces.com/EJB+3+and+Java+Persistence+API http://www.java2s.com/Tutorial/Java/0355 JPA/Catalog0355 JPA.htm Un petit manuel de référence http://jszyzx.scu.edu.cn/resin-doc/amber/index.xtp Une documentation sur JPQL http://download.oracle.com/docs/cd/E13189 01/kodo/docs40/full/html/ejb3 overview query.html 1 Rendre la DAO plus générique Afin d’éviter la création de nombreuses méthodes (quatre pour chaque entité), nous pouvons maintenant doter notre classe Dao de nouvelles méthodes génériques : public <T> T find(Class<T> clazz, Object id) { EntityManager em = null; try { em = newEntityManager(); return em.find(clazz, id); } finally { closeEntityManager(em); } } public <T> Collection<T> findAll(String query, Class<T> clazz) { EntityManager em = null; try { em = newEntityManager(); TypedQuery<T> q = em.createQuery(query, clazz); return q.getResultList(); } finally { closeEntityManager(em); } } ajout, mise à jour et destruction : 1 public <T> T add(T entity) { EntityManager em = null; try { em = newEntityManager(); em.persist(entity); em.getTransaction().commit(); return (entity); } finally { closeEntityManager(em); } } public <T> T update(T entity) { EntityManager em = null; try { em = newEntityManager(); entity = em.merge(entity); em.getTransaction().commit(); } finally { closeEntityManager(em); } return entity; } public <T> void remove(Class<T> clazz, Object pk) { EntityManager em = null; try { em = newEntityManager(); T entity = em.find(clazz, pk); if (entity != null) { em.remove(entity); } em.getTransaction().commit(); } finally { closeEntityManager(em); } } 2 2.1 Héritage Héritage avec table unique Nous allons étudier la représentation d’un arbre d’héritage dans une structure relationnelle. Définissons trois classes : une pour les UE, une autre (qui hérite de la première) pour les UE de master et une troisième (qui hérite également de la première) pour les UE de Licence : 2 package monpkg.entities; import java.io.Serializable; import javax.persistence.Basic; import javax.persistence.Entity; import javax.persistence.Id; @Entity public class UE implements Serializable { private static final long serialVersionUID = 1L; @Id() private String code; @Basic() private int credits; public UE() { super(); } public UE(String code, int credits) { super(); this.code = code; this.credits = credits; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public int getCredits() { return credits; } public void setCredits(int credits) { this.credits = credits; } @Override public String toString() { return String.format("UE(code=%s,credits=%d)", code, credits); } } Les UE de Master : 3 package monpkg.entities; import javax.persistence.Basic; import javax.persistence.Entity; @Entity public class MasterUE extends UE { private static final long serialVersionUID = 1L; @Basic private String masterName; public MasterUE() { super(); } public MasterUE(String code, int credits, String masterName) { super(code, credits); this.masterName = masterName; } public String getMasterName() { return masterName; } public void setMasterName(String masterName) { this.masterName = masterName; } @Override public String toString() { return String.format("MasterUE(code=%s,credits=%d,master=%s)", getCode(), getCredits(), masterName); } } Les UE de Licence : 4 package monpkg.entities; import javax.persistence.Basic; import javax.persistence.Entity; @Entity public class LicenceUE extends UE { private static final long serialVersionUID = 1L; @Basic private String description; public LicenceUE() { super(); } public LicenceUE(String code, int credits, String description) { super(code, credits); this.description = description; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @Override public String toString() { return String.format("LicenceUE(code=%s,credits=%d,description=%s)", getCode(), getCredits(), description); } } Travail à faire : Faites un test unitaire en créant (en base) une instance de chaque classe. Analysez la table unique créée par JPA. Utilisez ensuite la méthode findAll pour chaque classe et vérifiez que vous obtenez 3 UE, 1 UE de Master et 1 UE de Licence. 2.2 Héritage avec table de jointure Dans cette deuxième stratégie, les classes sont représentées par plusieurs tables mais les propriétés communes sont représentées une seule fois : ... @Entity @Inheritance(strategy = InheritanceType.JOINED) public class UE implements Serializable { ... } Travail à faire : N’oubliez pas détruire la table précédente avant d’exécuter cette version. Analysez les tables créées par JPA. 5 2.3 Héritage avec tables séparées Dans cette troisième stratégie, les classes sont représentées par plusieurs tables spéparées : ... @Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public class UE implements Serializable { ... } Travail à faire : N’oubliez pas détruire la table précédente avant d’exécuter cette version. Analysez les tables créées par JPA. 3 Requêtes construites par programmation Jusqu’à maintenant nous avons directement utilisé des requêtes JPQL sous la forme de chaı̂ne de caractères éventuellement paramétrées. A partir de JPA 2 il est possible de construire dynamiquement une requête bien typée à partir d’une API. Travail à faire : En vous aidant de ce chapitre du tutoriel JEE˜6 1 , améliorez la méthode findAll en supprimant le paramètre query que nous utilisions avant. public <T> Collection<T> findAll(Class<T> clazz) { ... } Tentez ensuite de construire une méthode qui renvoie les UE de Master à 6 crédits. Pour ce faire, vous devez ajouter un critère à votre requête (méthode where appliquée à l’instance de la classe CriteriaQuery<MasterUE>). 1. http://download.oracle.com/javaee/6/tutorial/doc/gjivm.html 6