Pages enfant
  • 3.3.4 Accès aux données avec JPA

Comparaison des versions

Légende

  • Ces lignes ont été ajoutées. Ce mot a été ajouté.
  • Ces lignes ont été supprimées. Ce mot a été supprimé.
  • La mise en forme a été modifiée.
Balise Wiki
{note:title=A compléter}A revoir
\\
Installation de JBossTools Hibernate (si partie toujours valide apres réfection)
{note}
{tip:title=Relu}Relecture RB{tip}

h4. Sommaire :
{toc:maxLevel=3}
----
Les exemples d'accès aux données de _esup-example utilisent JPA. Il existe plusieurs implémentations de JPA. Celle qui est retenue est celle de Hibernate_.

Note : L'implémentation Hibernate permet d'utiliser des fichiers de mapping (objet/base de données) spécifiques à Hibernate ce qui offre une compatibilité ascendante avec ESUP-Commons V1. De même, Hibernate permet potentiellement de faire des choses en plus de ce que la norme JPA prévoit. Mais ces deux fonctionnalités, si elles sont utilisées, ne permettent pas de passer à une autre implémentation de JPA. C'est la raison pour laquelle dans, _esup-example_, nous nous limitons à une utilisation stricte de JPA.

h2. Le gestionnaire d'entités

En JPA, l'élément qui permet de manipuler les objets en base de données est le gestionnaire d'entités. Les objets sont annotés afin de préciser comment ils doivent être enregistés en base de données.

La déclaration se fait dans le fichier *resources/properties/dao/dao.xml* :
{code}
 {color:#008080}<{color}{color:#3f7f7f}bean{color} {color:#7f007f}class{color}{color:#3a3935}={color}{color:#2a00ff}_<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"_{color} {color:#008080}/>{color}\\

 {color:#008080}<{color}{color:#3f7f7f}bean{color} {color:#7f007f}id{color}{color:#3a3935}={color}{color:#2a00ff}_"txManager"_{color} {color:#7f007f}class{color}{color:#3a3935}={color}{color:#2a00ff}_"	<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"_{color}{color:#008080}>{color}

 {color:#008080}<{color}{color:#3f7f7f}property{color} {color:#7f007f}name{color}{color:#3a3935}={color}{color:#2a00ff}_"entityManagerFactory"_{color} {color:#7f007f}ref{color}{color:#3a3935}={color}{color:#2a00ff}_"entityManagerFactory"_{color} {color:#008080}/>{color}

 {color:#008080}</{color}{color:#3f7f7f}bean{color}{color:#008080}>{color}\\

 {color:#008080}<{color}{color:#3f7f7f}bean{color} {color:#7f007f}id{color}{color:#3a3935}={color}{color:#2a00ff}_"entityManagerFactory"_{color} {color:#7f007f}class{color}{color:#3a3935}={color}{color:#2a00ff}_>
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>

	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"_{color}{color:#008080}>{color}

 {color:#008080}<{color}{color:#3f7f7f}property{color} {color:#7f007f}name{color}{color:#3a3935}={color}{color:#2a00ff}_"dataSource"_{color} {color:#7f007f}ref{color}{color:#3a3935}={color}{color:#2a00ff}_"${datasource.bean}"_{color} {color:#008080}/>{color}

 {color:#008080}<{color}{color:#3f7f7f}property{color} {color:#7f007f}name{color}{color:#3a3935}={color}{color:#2a00ff}_"jpaVendorAdapter"_{color} {color:#7f007f}ref{color}{color:#3a3935}={color}{color:#2a00ff}_"jpaVendorAdapter"_{color} {color:#008080}/>{color}

 {color:#008080}<{color}{color:#3f7f7f}property{color} {color:#7f007f}name{color}{color:#3a3935}={color}{color:#2a00ff}_"persistenceXmlLocation"_{color} {color:#7f007f}value{color}{color:#3a3935}={color}{color:#2a00ff}_"classpath:/properties/dao/persistence.xml"_{color} {color:#008080}/>{color}

 {color:#008080}<{color}{color:#3f7f7f}property{color} {color:#7f007f}name{color}{color:#3a3935}={color}{color:#2a00ff}_"jpaProperties"_{color} {color:#7f007f}ref{color}{color:#3a3935}={color}{color:#2a00ff}_"jpaProperties"_{color} {color:#008080}/>{color}

 {color:#008080}</{color}{color:#3f7f7f}bean{color}{color:#008080}>{color}\\

 {color:#008080}<{color}{color:#3f7f7f}bean{color} {color:#7f007f}id{color}{color:#3a3935}={color}{color:#2a00ff}_"JDBCDataSource"_{color} {color:#7f007f}class{color}{color:#3a3935}={color}{color:#2a00ff}_"org.apache.commons.dbcp.BasicDataSource"_{color}

 {color:#7f007f}destroy-method{color}{color:#3a3935}={color}{color:#2a00ff}_"close"_{color}

 {color:#7f007f}lazy-init{color}{color:#3a3935}={color}{color:#2a00ff}_"true"_{color}{color:#008080}>{color}

 {color:#008080}<{color}{color:#3f7f7f}property{color} {color:#7f007f}name{color}{color:#3a3935}={color}{color:#2a00ff}_"driverClassName"_{color} {color:#7f007f}value{color}{color:#3a3935}={color}{color:#2a00ff}_"${jdbc.connection.driver_class}"_{color} {color:#008080}/>{color}

 {color:#008080}<{color}{color:#3f7f7f}property{color} {color:#7f007f}name{color}{color:#3a3935}={color}{color:#2a00ff}_"maxActive"_{color} {color:#7f007f}value{color}{color:#3a3935}={color}{color:#2a00ff}_"100"_{color} {color:#008080}/>{color}

 {color:#008080}<{color}{color:#3f7f7f}property{color} {color:#7f007f}name{color}{color:#3a3935}={color}{color:#2a00ff}_"maxIdle"_{color} {color:#7f007f}value{color}{color:#3a3935}={color}{color:#2a00ff}_"30"_{color} {color:#008080}/>{color}

 {color:#008080}<{color}{color:#3f7f7f}property{color} {color:#7f007f}name{color}{color:#3a3935}={color}{color:#2a00ff}_"maxWait"_{color} {color:#7f007f}value{color}{color:#3a3935}={color}{color:#2a00ff}_"100"_{color} {color:#008080}/>{color}

 {color:#008080}<{color}{color:#3f7f7f}property{color} {color:#7f007f}name{color}{color:#3a3935}={color}{color:#2a00ff}_"url"_{color} {color:#7f007f}value{color}{color:#3a3935}={color}{color:#2a00ff}_"${jdbc.connection.url}"_{color} {color:#008080}/>{color}

 {color:#008080}<{color}{color:#3f7f7f}property{color} {color:#7f007f}name{color}{color:#3a3935}={color}{color:#2a00ff}_"username"_{color} {color:#7f007f}value{color}{color:#3a3935}={color}{color:#2a00ff}_"${jdbc.connection.username}"_{color} {color:#008080}/>{color}

 {color:#008080}<{color}{color:#3f7f7f}property{color} {color:#7f007f}name{color}{color:#3a3935}={color}{color:#2a00ff}_"password"_{color} {color:#7f007f}value{color}{color:#3a3935}={color}{color:#2a00ff}_"${jdbc.connection.password}"_{color} {color:#008080}/>{color}

 {color:#008080}</{color}{color:#3f7f7f}bean{color}{color:#008080}>{color}

 {color:#008080}<{color}{color:#3f7f7f}jee:jndi-lookup{color} {color:#7f007f}id{color}{color:#3a3935}={color}{color:#2a00ff}_"JNDIDataSource"_{color} {color:#7f007f}jndi-name{color}{color:#3a3935}={color}{color:#2a00ff}_"${jndi.datasource}"_{color} {color:#7f007f}lookup-on-startup{color}{color:#3a3935}={color}{color:#2a00ff}_"false"_{color} {color:#7f007f}expected-type{color}{color:#3a3935}={color}{color:#2a00ff}_"javax.sql.DataSource"_{color}{color:#008080}/>{color}\\

 {color:#008080}<{color}{color:#3f7f7f}bean{color} {color:#7f007f}id{color}{color:#3a3935}={color}{color:#2a00ff}_"jpaVendorAdapter"_{color}

 {color:#7f007f}class{color}{color:#3a3935}={color}{color:#2a00ff}_"org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"_{color}{color:#008080}>{color}

 {color:#008080}<{color}{color:#3f7f7f}property{color} {color:#7f007f}name{color}{color:#3a3935}={color}{color:#2a00ff}_"showSql"_{color} {color:#7f007f}value{color}{color:#3a3935}={color}{color:#2a00ff}_"true"_{color} {color:#008080}/>{color}

 {color:#008080}<{color}{color:#3f7f7f}property{color} {color:#7f007f}name{color}{color:#3a3935}={color}{color:#2a00ff}_"generateDdl"_{color} {color:#7f007f}value{color}{color:#3a3935}={color}{color:#2a00ff}_"true"_{color} {color:#008080}/>{color}

 {color:#008080}<{color}{color:#3f7f7f}property{color} {color:#7f007f}name{color}{color:#3a3935}={color}{color:#2a00ff}_"database"_{color} {color:#7f007f}value{color}{color:#3a3935}={color}{color:#2a00ff}_"${jpa.database.type}"_{color} {color:#008080}/>{color}

 {color:#008080}</{color}{color:#3f7f7f}bean{color}{color:#008080}>{color}\\

 {color:#008080}<{color}{color:#3f7f7f}util:properties{color} {color:#7f007f}id{color}{color:#3a3935}={color}{color:#2a00ff}_"jpaProperties"_{color}{color:#008080}>{color}

 {color:#008080}<{color}{color:#3f7f7f}prop{color} {color:#7f007f}key{color}{color:#3a3935}={color}{color:#2a00ff}_"hibernate.cache.provider_class"_{color}{color:#008080}>{color}{color:#3a3935}org.hibernate.cache.NoCacheProvider{color}{color:#008080}</{color}{color:#3f7f7f}prop{color}{color:#008080}>{color}

 {color:#008080}<{color}{color:#3f7f7f}prop{color} {color:#7f007f}key{color}{color:#3a3935}={color}{color:#2a00ff}_"hibernate.cache.use_query_cache"_{color}{color:#008080}>{color}{color:#3a3935}false{color}{color:#008080}</{color}{color:#3f7f7f}prop{color}{color:#008080}>{color}

 {color:#008080}<{color}{color:#3f7f7f}prop{color} {color:#7f007f}key{color}{color:#3a3935}={color}{color:#2a00ff}_"hibernate.cache.use_second_level_cache"_{color}{color:#008080}>{color}{color:#3a3935}false{color}{color:#008080}</{color}{color:#3f7f7f}prop{color}{color:#008080}>{color}

 {color:#008080}</{color}{color:#3f7f7f}util:properties{color}{color:#008080}>{color}\\

 {color:#008080}<{color}{color:#3f7f7f}bean{color} {color:#7f007f}id{color}{color:#3a3935}={color}{color:#2a00ff}_"daoService"_{color} {color:#7f007f}class{color}{color:#3a3935}={color}{color:#2a00ff}_>
		<property name="dataSource" ref="${datasource.bean}" />
		<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
		<property name="persistenceXmlLocation" value="classpath:/properties/dao/persistence.xml" />
		<property name="jpaProperties" ref="jpaProperties" />
	</bean>

	<bean id="JDBCDataSource" class="org.apache.commons.dbcp.BasicDataSource"
		destroy-method="close"
		lazy-init="true">
		<property name="driverClassName" value="${jdbc.connection.driver_class}" />
		<property name="maxActive" value="100" />
		<property name="maxIdle" value="30" />
		<property name="maxWait" value="100" />
		<property name="url" value="${jdbc.connection.url}" />
		<property name="username" value="${jdbc.connection.username}" />
		<property name="password" value="${jdbc.connection.password}" />
	</bean>
	
	<jee:jndi-lookup id="JNDIDataSource" jndi-name="${jndi.datasource}" lookup-on-startup="false" expected-type="javax.sql.DataSource"/>

	<bean id="jpaVendorAdapter"
		class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
		<property name="showSql" value="true" />
		<property name="generateDdl" value="true" />
		<property name="database" value="${jpa.database.type}" />
	</bean>

	<util:properties id="jpaProperties">
		<prop key="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
		<prop key="hibernate.cache.use_query_cache">false</prop>
		<prop key="hibernate.cache.use_second_level_cache">false</prop>
	</util:properties>

	<bean id="daoService" class="org.esupportail.example.dao.JPADaoServiceImpl"_{color}

 {color:#7f007f}
		lazy-init{color}{color:#3a3935}={color}{color:#2a00ff}_"true"_{color}{color:#008080}>{color}

 {color:#008080}</{color}{color:#3f7f7f}bean{color}{color:#008080}>{color}
	</bean>
{code}
Explications&nbsp;:
* Le bean{*}org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor* demande à Spring de rechercher les classes java contenant des 	annotations définissant la façon d'enregistrer les objets en base 	de données.
* Le bean *entityManagerFactory* permet la création du gestionnaire d'entités. Il a comme 	propriétés&nbsp;:
** *dataSource* qui est 		la source de donnée à utiliser. Ici on utilise une variable 		Spring qui permettra de pointer vers un bean définissant une 		source de données JDBC (*JDBCDataSource*) 		ou JNDI (*JNDIDataSource*, 		gérée par le serveur d'applications)
** *jpaVendorAdapter* qui précise l'implémentation JPA utilisée.
** *PersistenceXmlLocation* qui permet de donner le nom du fichier de configuration JPA à 		utiliser (*/properties/dao/persistence.xml*). 		Ce dernier donne le nom du gestionnaire d'entités et les classes 		qui doit gérer.
** *JpaProperties* qui 		pointe vers un bean permettant de donner des informations générales 		liées au comportement de JPA.
* Le bean *JDBCDataSource* définit localement un poll de connexions à la base de données.
* Le bean *JNDIDataSource* permet de pointer vers un poll de connexions à la base de données 	géré par le serveur d'applications. Il a comme propriétés&nbsp;:
** *jndi-name* qui correspond au nom du poll dans la 		configuration JNDI du serveur d'applications. Ici on utilise unevariable Spring.
** *lookup-on-startup="false"* permet de 		préciser que l'on ne fera pas la recherche JNDI du poll de 		connexions au démarrage de l'application. C'est utile car l'on 		utilise une variable Spring pour savoir si on doit utiliser une 		source de données JDBC ou JNDI. Aussi il ne faut pas activer 		systématiquement la recherche alors que la configuration n'y fera 		peut-être pas référence.
* Le bean *jpaProperties* permet de donner des informations générales liées au comportement 	de JPA.
* Le bean *daoService* permet de définir la classe qui, dans notre application, contiendra 	les méthodes d'accès aux données.

h3. Utilisation de plusieurs gestionnaires d'entités.

Si on souhaite accéder à n bases de données il est possible de déclarer n gestionnaires d'entités.

TODO

ICI&nbsp;????

Le choix du gestionnaire de base de données Hibernate doit se faire en fonction de la maîtrise qu'a le développeur de la base de données. Deux cas se présentent&nbsp;:
* *Le 	développeur a la totale maîtrise de la base de données*, 	c'est lui qui la fait évoluer en fonction des besoins de son 	application. Il utilisera dans ce cas l'implémentation *UgradableHibernateDatabaseManagerImpl*. 	Cette implémentation lui permettra de faire évoluer la structure 	de sa base de données en modifiant son _mapping_, 	de manière automatique sans même toucher au code _SQL_.
* *Le 	développeur n'a pas la maîtrise de la base de données*&nbsp;: 	il s'agit d'une base de données institutionnelle, ou bien encore 	d'une base maîtrisée par une autre application. Il utilisera dans 	ce cas l'implémentation BasicHibernateDatabaseManagerImpl, et devra 	alors faire coller son mapping aux structures de la base de données.
\\

h2. Mapping avec la base de données

Le fichier de configuration JPA (*/properties/dao/persistence.xml*) contient la liste des classes dont il doit assurer la persistance.

En JPA il est possible de définir se mapping directement sous forme d'annotations dans le code java des classes à persister. C'est la solution préconisée dans le cadre de ESUP-Commons V2.

Pour avoir une information complète sur ces annotations Cf.&nbsp;????

Voici un extrait de la classe User&nbsp;:

{color:#646464}@Entity{color}

{color:#7f0055}{*}public{*}{color} {color:#7f0055}{*}class{*}{color} {color:#000000}User{color} {color:#7f0055}{*}implements{*}{color} {color:#000000}Serializable {{color}

 {color:#3f5fbf}/*\*{color}

{color:#3f5fbf}\:
{code}@Entity
public class User implements Serializable {
	
	/**
	 * Id of the user.{color}

{color:#3f5fbf}\*/{color}

 {color:#646464}@Id{color}

 {color:#7f0055}{*}private{*}{color} {color:#000000}String{color} {color:#0000c0}id{color}{color:#000000};{color}

 {color:#3f5fbf}/*\*{color}

{color:#3f5fbf}\.
	 */
	@Id
	private String id;
	
    /**
	 * Display Name of the user.{color}

{color:#3f5fbf}\*/{color}

 {color:#7f0055}{*}private{*}{color} {color:#000000}String{color} {color:#0000c0}displayName{color}{color:#000000};{color}

 {color:#3f5fbf}/*\*{color}

{color:#3f5fbf}\
	 */
    private String displayName;
    
    /**
	 * True for administrators.{color}

{color:#3f5fbf}\*/{color}

 {color:#7f0055}{*}private{*}{color} {color:#7f0055}{*}boolean{*}{color} {color:#0000c0}admin{color}{color:#000000};{color}

 {color:#3f5fbf}/*\*{color}

 {color:#3f5fbf}\* The{color} {color:#3f5fbf}{+}prefered{+}{color} {color:#3f5fbf}language.{color}

 {color:#3f5fbf}\*/{color}

 {color:#7f0055}{*}private{*}{color} {color:#000000}String{color} {color:#0000c0}language{color}{color:#000000};{color}

 {color:#3f5fbf}/*\*{color}

 {color:#3f5fbf}\
	 */
    private boolean admin;
	
    /**
     * The prefered language.
     */
    private String language;
     
    /**
     * information recorded during database insert{color}

 {color:#3f5fbf}\ 
     * used in{color} {color:#3f5fbf}{+}esup{+}{color}{color:#7f7f9f}\-{color}{color:#3f5fbf}example to illustrate open session in view mechanism{color}

 {color:#3f5fbf}\*/{color}

 {color:#646464}@OneToMany{color}{color:#000000}
     */
    @OneToMany(cascade={CascadeType.{color}{color:#0000c0}{_}ALL{_}{color}{color:#000000}}){color}

 {color:#7f0055}{*}private{*}{color} {color:#000000}List<Information>{color} {color:#0000c0}informations{color}{color:#000000};{color}\\

    private List<Information> informations;

{code}
Explications&nbsp;:
* L'annotation *@Entity* précise que la Classe est une 	entité à persister. Par défaut tous les propriétés de la classe 	seront persistées. Un règle de nommage par défaut (si pas de 	présence d'une annotation sur la propriété pour une déclaration 	explicite) sera appliquée afin de déterminer le nom de la colonne 	en base de données.
* L'annotation *@Id* précise que cette propriété sera 	utilisée comme clé primaire de la table dans la base de données.
** Note&nbsp;: En JPA comme en Hibernate il est recommandé 		d'utiliser une clé physique (celle qui sera utilisée comme clé 		primaire de la table dans la base de données) différente de la 		clé métier utilisé par l'application. Il est aussi recommandé 		de créer des méthodes equals et hcode basée sur la clé métier.
Ici *User* est un cas particulier où la clé physique est 		aussi la clé métier dans la mesure où la clé n'est pas calculée 		(non utilisation de l'annotation *@GeneratedValue* en plus de*@Id*). Néanmoins cette pratique reste déconseillée car si 		nous devions faire évoluer notre besoin métier (par exemple 		utiliser une autre propriété de la classe \-en plus de *id*\- 		en tant que clé métier) nous n'arriverions pas à le faire (la 		contrainte d'unicité physique portant exclusivement sur *id*)
* L'annotation @OneToMany(cascade={CascadeType.ALL}) défini 	une association un à plusieurs. La cascade permet de préciser que 	si on fait une opération, typiquement un effacement, sur le père 	alors elle sera répercutée sur les enfants.

h2. Utilisation de EJB QL

_EJB QL_ est un langage d'interrogation de base de données de _JPA_. Il est orienté objet et a une forme proche du _SQL_ mais travaille sur les objets _Java_ et pas sur des noms de tables de votre base de données.

Note&nbsp;: Contrairement à _SQL_, le mot clé *SELECT* de _HQL_ n'est pas obligatoire. S'il n'est pas utilisé ce sont des objets qui sont retournés. S'il est utilisé, il est possible de seulement retourner les propriétés de ces objets.

Après le mot-clé *FROM*, on n'utilise pas des noms de tables mais des noms de classes. Ce nom de classe est sensible à la casse comme en _Java_. Le nom du _package_ n'est pas obligatoire car _Hibernate_ a un mécanisme d'_auto-import_.

Exemple d'une requête _EJB QL_ simple qui récupère toutes les instances de la classe *User* de la base de données&nbsp;:"SELECT user FROM User user"Pour une information complète sur l'utilisation de _EJB QL_ Cf.&nbsp;????