prep for gettext conversion
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@14114 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
3fbbda75d1
commit
426dccd83a
|
@ -1,4 +1,4 @@
|
|||
<?xml version='1.0' encoding="iso-8859-1"?>
|
||||
<?xml version='1.0' encoding="UTF-8"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!ENTITY versionNumber "3.3.0.alpha1">
|
||||
<!ENTITY copyrightYear "2004">
|
||||
|
@ -9,7 +9,7 @@
|
|||
|
||||
<bookinfo>
|
||||
<title>HIBERNATE - Persistance relationnelle en Java standard</title>
|
||||
<subtitle>Documentation de référence d'Hibernate</subtitle>
|
||||
<subtitle>Documentation de référence d'Hibernate</subtitle>
|
||||
<releaseinfo>&versionNumber;</releaseinfo>
|
||||
<productnumber>&versionNumber;</productnumber>
|
||||
<issuenum>1</issuenum>
|
||||
|
@ -25,7 +25,6 @@
|
|||
<year>©rightYear;</year>
|
||||
<holder>©rightHolder;</holder>
|
||||
</copyright>
|
||||
<xi:include href="translators.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="legal_notice.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</bookinfo>
|
||||
|
||||
|
@ -33,13 +32,13 @@
|
|||
|
||||
<xi:include href="content/preface.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="content/tutorial.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="content/tutorial.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="content/architecture.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="content/architecture.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="content/configuration.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="content/configuration.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="content/persistent_classes.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="content/persistent_classes.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="content/basic_mapping.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="content/collection_mapping.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
|
|
@ -1,28 +1,15 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
~ Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
|
||||
~
|
||||
~ This copyrighted material is made available to anyone wishing to use, modify,
|
||||
~ copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
~ Lesser General Public License, v. 2.1. This program is distributed in the
|
||||
~ hope that it will be useful, but WITHOUT A WARRANTY; without even the implied
|
||||
~ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
~ Lesser General Public License for more details. You should have received a
|
||||
~ copy of the GNU Lesser General Public License, v.2.1 along with this
|
||||
~ distribution; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
~
|
||||
~ Red Hat Author(s): Steve Ebersole
|
||||
-->
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="architecture">
|
||||
|
||||
<title>Architecture</title>
|
||||
|
||||
<sect1 id="architecture-overview" revision="1">
|
||||
<title>Généralités</title>
|
||||
<title>Généralités</title>
|
||||
|
||||
<para>
|
||||
Voici une vue (très) haut niveau de l'architecture d'Hibernate :
|
||||
Voici une vue (très) haut niveau de l'architecture d'Hibernate :
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
|
@ -35,16 +22,16 @@
|
|||
</mediaobject>
|
||||
|
||||
<para>
|
||||
Ce diagramme montre Hibernate utilisant une base de données et des données
|
||||
Ce diagramme montre Hibernate utilisant une base de données et des données
|
||||
de configuration pour fournir un service de persistance (et des objets
|
||||
persistants) à l'application.
|
||||
persistants) à l'application.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Nous aimerions décrire une vue plus détaillée de l'architecture. Malheureusement,
|
||||
Hibernate est flexible et supporte différentes approches. Nous allons en
|
||||
montrer les deux extrêmes. L'architecture légère laisse l'application fournir
|
||||
ses propres connexions JDBC et gérer ses propres transactions. Cette approche
|
||||
Nous aimerions décrire une vue plus détaillée de l'architecture. Malheureusement,
|
||||
Hibernate est flexible et supporte différentes approches. Nous allons en
|
||||
montrer les deux extrêmes. L'architecture légère laisse l'application fournir
|
||||
ses propres connexions JDBC et gérer ses propres transactions. Cette approche
|
||||
utilise le minimum des APIs Hibernate :
|
||||
</para>
|
||||
|
||||
|
@ -58,8 +45,8 @@
|
|||
</mediaobject>
|
||||
|
||||
<para>
|
||||
L'architecture la plus complète abstrait l'application des APIs JDBC/JTA
|
||||
sous-jacentes et laisse Hibernate s'occuper des détails.
|
||||
L'architecture la plus complète abstrait l'application des APIs JDBC/JTA
|
||||
sous-jacentes et laisse Hibernate s'occuper des détails.
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
|
@ -72,7 +59,7 @@
|
|||
</mediaobject>
|
||||
|
||||
<para>
|
||||
Voici quelques définitions des objets des diagrammes :
|
||||
Voici quelques définitions des objets des diagrammes :
|
||||
|
||||
<variablelist spacing="compact">
|
||||
<varlistentry>
|
||||
|
@ -80,10 +67,10 @@
|
|||
<listitem>
|
||||
<para>
|
||||
Un cache threadsafe (immuable) des mappings vers une (et une seule) base
|
||||
de données. Une factory (fabrique) de <literal>Session</literal> et un client
|
||||
de données. Une factory (fabrique) de <literal>Session</literal> et un client
|
||||
de <literal>ConnectionProvider</literal>. Peut contenir un cache optionnel de
|
||||
données (de second niveau) qui est réutilisable entre les différentes transactions
|
||||
que cela soit au sein du même processus (JVLM) ou par plusieurs n½uds d'un cluster.
|
||||
données (de second niveau) qui est réutilisable entre les différentes transactions
|
||||
que cela soit au sein du même processus (JVLM) ou par plusieurs nœuds d'un cluster.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -91,11 +78,11 @@
|
|||
<term>Session (<literal>org.hibernate.Session</literal>)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Un objet mono-threadé, à durée de vie courte, qui représente une conversation
|
||||
entre l'application et l'entrepôt de persistance. Encapsule une connexion JDBC.
|
||||
Un objet mono-threadé, à durée de vie courte, qui représente une conversation
|
||||
entre l'application et l'entrepôt de persistance. Encapsule une connexion JDBC.
|
||||
Factory (fabrique) des objets <literal>Transaction</literal>. Contient un cache
|
||||
(de premier niveau) des objets persistants, ce cache est obligatoire. Il est
|
||||
utilisé lors de la navigation dans le graphe d'objets ou lors de la récupération
|
||||
utilisé lors de la navigation dans le graphe d'objets ou lors de la récupération
|
||||
d'objets par leur identifiant.
|
||||
</para>
|
||||
</listitem>
|
||||
|
@ -104,13 +91,13 @@
|
|||
<term>Objets et Collections persistants</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Objets mono-threadés à vie courte contenant l'état de persistance
|
||||
et la fonction métier. Ceux-ci sont en général les objets de type JavaBean
|
||||
(ou POJOs) ; la seule particularité est qu'ils sont associés avec une (et
|
||||
une seule) <literal>Session</literal>. Dès que la <literal>Session</literal>
|
||||
est fermée, ils seront détachés et libres d'être utilisés par n'importe laquelle
|
||||
des couches de l'application (ie. de et vers la présentation en tant que Data
|
||||
Transfer Objects - DTO : objet de transfert de données).
|
||||
Objets mono-threadés à vie courte contenant l'état de persistance
|
||||
et la fonction métier. Ceux-ci sont en général les objets de type JavaBean
|
||||
(ou POJOs) ; la seule particularité est qu'ils sont associés avec une (et
|
||||
une seule) <literal>Session</literal>. Dès que la <literal>Session</literal>
|
||||
est fermée, ils seront détachés et libres d'être utilisés par n'importe laquelle
|
||||
des couches de l'application (ie. de et vers la présentation en tant que Data
|
||||
Transfer Objects - DTO : objet de transfert de données).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -118,10 +105,10 @@
|
|||
<term>Objets et collections transients</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Instances de classes persistantes qui ne sont actuellement pas associées à
|
||||
une <literal>Session</literal>. Elles ont pu être instanciées par l'application
|
||||
et ne pas avoir (encore) été persistées ou elle ont pu être instanciées par
|
||||
une <literal>Session</literal> fermée.
|
||||
Instances de classes persistantes qui ne sont actuellement pas associées à
|
||||
une <literal>Session</literal>. Elles ont pu être instanciées par l'application
|
||||
et ne pas avoir (encore) été persistées ou elle ont pu être instanciées par
|
||||
une <literal>Session</literal> fermée.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -129,11 +116,11 @@
|
|||
<term>Transaction (<literal>org.hibernate.Transaction</literal>)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
(Optionnel) Un objet mono-threadé à vie courte utilisé par l'application
|
||||
pour définir une unité de travail atomique. Abstrait l'application des
|
||||
(Optionnel) Un objet mono-threadé à vie courte utilisé par l'application
|
||||
pour définir une unité de travail atomique. Abstrait l'application des
|
||||
transactions sous-jacentes qu'elles soient JDBC, JTA ou CORBA. Une
|
||||
<literal>Session</literal> peut fournir plusieurs <literal>Transaction</literal>s
|
||||
dans certains cas. Toutefois, la délimitation des transactions, via l'API d'Hibernate
|
||||
dans certains cas. Toutefois, la délimitation des transactions, via l'API d'Hibernate
|
||||
ou par la <literal>Transaction</literal> sous-jacente, n'est jamais optionnelle!
|
||||
</para>
|
||||
</listitem>
|
||||
|
@ -144,7 +131,7 @@
|
|||
<para>
|
||||
(Optionnel) Une fabrique de (pool de) connexions JDBC. Abstrait l'application
|
||||
de la <literal>Datasource</literal> ou du <literal>DriverManager</literal> sous-jacent.
|
||||
Non exposé à l'application, mais peut être étendu/implémenté par le développeur.
|
||||
Non exposé à l'application, mais peut être étendu/implémenté par le développeur.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -153,7 +140,7 @@
|
|||
<listitem>
|
||||
<para>
|
||||
(Optionnel) Une fabrique d'instances de <literal>Transaction</literal>. Non
|
||||
exposé à l'application, mais peut être étendu/implémenté par le développeur.
|
||||
exposé à l'application, mais peut être étendu/implémenté par le développeur.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -162,8 +149,8 @@
|
|||
<listitem>
|
||||
<para>
|
||||
Hibernate fournit de nombreuses interfaces d'extensions optionnelles que
|
||||
vous pouvez implémenter pour personnaliser le comportement de votre couche de persistance.
|
||||
Reportez vous à la documentation de l'API pour plus de détails.
|
||||
vous pouvez implémenter pour personnaliser le comportement de votre couche de persistance.
|
||||
Reportez vous à la documentation de l'API pour plus de détails.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -171,7 +158,7 @@
|
|||
</para>
|
||||
|
||||
<para>
|
||||
Dans une architecture légère, l'application n'aura pas à utiliser les APIs
|
||||
Dans une architecture légère, l'application n'aura pas à utiliser les APIs
|
||||
<literal>Transaction</literal>/<literal>TransactionFactory</literal>
|
||||
et/ou n'utilisera pas les APIs <literal>ConnectionProvider</literal>
|
||||
pour utiliser JTA ou JDBC.
|
||||
|
@ -181,9 +168,9 @@
|
|||
<sect1 id="architecture-states" revision="1">
|
||||
<title>Etats des instances</title>
|
||||
<para>
|
||||
Une instance d'une classe persistante peut être dans l'un des trois états suivants,
|
||||
définis par rapport à un <emphasis>contexte de persistance</emphasis>.
|
||||
L'objet <literal>Session</literal> d'hibernate correspond à ce concept de
|
||||
Une instance d'une classe persistante peut être dans l'un des trois états suivants,
|
||||
définis par rapport à un <emphasis>contexte de persistance</emphasis>.
|
||||
L'objet <literal>Session</literal> d'hibernate correspond à ce concept de
|
||||
contexte de persistance :
|
||||
</para>
|
||||
|
||||
|
@ -192,8 +179,8 @@
|
|||
<term>passager (transient)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
L'instance n'est pas et n'a jamais été associée à un contexte
|
||||
de persistance. Elle ne possède pas d'identité persistante (valeur de clé primaire)
|
||||
L'instance n'est pas et n'a jamais été associée à un contexte
|
||||
de persistance. Elle ne possède pas d'identité persistante (valeur de clé primaire)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -201,26 +188,26 @@
|
|||
<term>persistant</term>
|
||||
<listitem>
|
||||
<para>
|
||||
L'instance est associée au contexte de persistance.
|
||||
Elle possède une identité persistante (valeur de clé primaire)
|
||||
et, peut-être, un enregistrement correspondant dans la base.
|
||||
L'instance est associée au contexte de persistance.
|
||||
Elle possède une identité persistante (valeur de clé primaire)
|
||||
et, peut-être, un enregistrement correspondant dans la base.
|
||||
Pour un contexte de persistance particulier, Hibernate
|
||||
<emphasis>garantit</emphasis> que l'identité persistante
|
||||
est équivalente à l'identité Java (emplacement mémoire de l'objet)
|
||||
<emphasis>garantit</emphasis> que l'identité persistante
|
||||
est équivalente à l'identité Java (emplacement mémoire de l'objet)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>détaché</term>
|
||||
<term>détaché</term>
|
||||
<listitem>
|
||||
<para>
|
||||
L'instance a été associée au contexte de persistance mais ce
|
||||
contexte a été fermé, ou l'instance a été sérialisée vers un
|
||||
autre processus. Elle possède une identité persistante et
|
||||
peut-être un enregistrement correspondant dans la base.
|
||||
Pour des instances détachées, Hibernate ne donne aucune
|
||||
garantie sur la relation entre l'identité persistante et
|
||||
l'identité Java.
|
||||
L'instance a été associée au contexte de persistance mais ce
|
||||
contexte a été fermé, ou l'instance a été sérialisée vers un
|
||||
autre processus. Elle possède une identité persistante et
|
||||
peut-être un enregistrement correspondant dans la base.
|
||||
Pour des instances détachées, Hibernate ne donne aucune
|
||||
garantie sur la relation entre l'identité persistante et
|
||||
l'identité Java.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -228,39 +215,39 @@
|
|||
</sect1>
|
||||
|
||||
<sect1 id="architecture-jmx" revision="1">
|
||||
<title>Intégration JMX</title>
|
||||
<title>Intégration JMX</title>
|
||||
<para>
|
||||
JMX est le standard J2EE de gestion des composants Java.
|
||||
Hibernate peut être géré via un service JMX standard. Nous fournissons une implémentation
|
||||
Hibernate peut être géré via un service JMX standard. Nous fournissons une implémentation
|
||||
d'un MBean dans la distribution : <literal>org.hibernate.jmx.HibernateService</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Pour avoir un exemple sur la manière de déployer Hibernate en tant que service JMX dans le
|
||||
serveur d'application JBoss Application Server, référez vous au guide utilisateur JBoss (JBoss User Guide).
|
||||
Si vous déployez Hibernate via JMX sur JBoss AS, vous aurez également les bénéfices suivants :
|
||||
Pour avoir un exemple sur la manière de déployer Hibernate en tant que service JMX dans le
|
||||
serveur d'application JBoss Application Server, référez vous au guide utilisateur JBoss (JBoss User Guide).
|
||||
Si vous déployez Hibernate via JMX sur JBoss AS, vous aurez également les bénéfices suivants :
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Gestion de la session :</emphasis> Le cycle de vie de la <literal>Session</literal>
|
||||
Hibernate peut être automatiquement limitée à la portée d'une transaction JTA.
|
||||
Hibernate peut être automatiquement limitée à la portée d'une transaction JTA.
|
||||
Cela signifie que vous n'avez plus besoin d'ouvrir et de fermer la <literal>Session</literal>
|
||||
manuellement, cela devient le travail de l'intercepteur EJB de JBoss. Vous n'avez
|
||||
pas non plus à vous occuper des démarcations des transactions dans votre code (sauf
|
||||
si vous voulez écrire une couche de persistance qui soit portable, dans ce cas vous
|
||||
pas non plus à vous occuper des démarcations des transactions dans votre code (sauf
|
||||
si vous voulez écrire une couche de persistance qui soit portable, dans ce cas vous
|
||||
pouvez utiliser l'API optionnelle <literal>Transaction</literal> d'Hibernate).
|
||||
Vous appelez l'<literal>HibernateContext</literal> pour accéder à la <literal>Session</literal>.
|
||||
Vous appelez l'<literal>HibernateContext</literal> pour accéder à la <literal>Session</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Déploiement HAR :</emphasis> Habituellement vous déployez le service JMX
|
||||
Hibernate en utilisant le descripteur de déploiement de JBoss (dans un fichier EAR et/ou un SAR),
|
||||
<emphasis>Déploiement HAR :</emphasis> Habituellement vous déployez le service JMX
|
||||
Hibernate en utilisant le descripteur de déploiement de JBoss (dans un fichier EAR et/ou un SAR),
|
||||
il supporte toutes les options de configuration usuelles d'une <literal>SessionFactory</literal>
|
||||
Hibernate. Cependant, vous devez toujours nommer tous vos fichiers de mapping dans le
|
||||
descripteur de déploiement. Si vous décidez d'utiliser le déploiement optionnel sous forme
|
||||
de HAR, JBoss détectera automatiquement tous vos fichiers de mapping dans votre fichier HAR.
|
||||
descripteur de déploiement. Si vous décidez d'utiliser le déploiement optionnel sous forme
|
||||
de HAR, JBoss détectera automatiquement tous vos fichiers de mapping dans votre fichier HAR.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
@ -270,8 +257,8 @@
|
|||
</para>
|
||||
|
||||
<para>
|
||||
Les statistiques pendant l'exécution d'Hibernate (au runtime) sont une
|
||||
autre fonctionnalité disponible en tant que service JMX. Voyez pour cela
|
||||
Les statistiques pendant l'exécution d'Hibernate (au runtime) sont une
|
||||
autre fonctionnalité disponible en tant que service JMX. Voyez pour cela
|
||||
<xref linkend="configuration-optional-statistics"/>.
|
||||
</para>
|
||||
</sect1>
|
||||
|
@ -279,46 +266,46 @@
|
|||
<sect1 id="architecture-jca" revision="1">
|
||||
<title>Support JCA</title>
|
||||
<para>
|
||||
Hibernate peut aussi être configuré en tant que connecteur JCA. Référez-vous au site
|
||||
web pour de plus amples détails. Il est important de noter que le support JCA d'Hibernate
|
||||
est encore considéré comme expérimental.
|
||||
Hibernate peut aussi être configuré en tant que connecteur JCA. Référez-vous au site
|
||||
web pour de plus amples détails. Il est important de noter que le support JCA d'Hibernate
|
||||
est encore considéré comme expérimental.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="architecture-current-session" revision="1">
|
||||
<title>Sessions Contextuelles</title>
|
||||
<para>
|
||||
Certaines applications utilisant Hibernate ont besoin d'une sorte de session "contextuelle", où
|
||||
une session est liée à la portée d'un contexte particulier. Cependant, les applications ne définissent
|
||||
pas toutes la notion de contexte de la même manière, et différents contextes définissent différentes
|
||||
portées à la notion de "courant". Les applications à base d'Hibernate, versions précédentes à la 3.0
|
||||
utilisaient généralement un principe maison de sessions contextuelles basées sur le <literal>ThreadLocal</literal>,
|
||||
Certaines applications utilisant Hibernate ont besoin d'une sorte de session "contextuelle", où
|
||||
une session est liée à la portée d'un contexte particulier. Cependant, les applications ne définissent
|
||||
pas toutes la notion de contexte de la même manière, et différents contextes définissent différentes
|
||||
portées à la notion de "courant". Les applications à base d'Hibernate, versions précédentes à la 3.0
|
||||
utilisaient généralement un principe maison de sessions contextuelles basées sur le <literal>ThreadLocal</literal>,
|
||||
ainsi que sur des classes utilitaires comme <literal>HibernateUtil</literal>, ou utilisaient des
|
||||
framework tiers (comme Spring ou Pico) qui fournissaient des sessions contextuelles basées sur
|
||||
framework tiers (comme Spring ou Pico) qui fournissaient des sessions contextuelles basées sur
|
||||
l'utilisation de proxy/interception.
|
||||
</para>
|
||||
<para>
|
||||
A partir de la version 3.0.1, Hibernate a ajouté la méthode <literal>SessionFactory.getCurrentSession()</literal>.
|
||||
Initialement, cela demandait l'usage de transactions <literal>JTA</literal>, où la
|
||||
transaction <literal>JTA</literal> définissait la portée et le contexte de la session courante.
|
||||
L'équipe Hibernate pense que, étant donnée la maturité des implémentations de <literal>JTA TransactionManager</literal> ,
|
||||
A partir de la version 3.0.1, Hibernate a ajouté la méthode <literal>SessionFactory.getCurrentSession()</literal>.
|
||||
Initialement, cela demandait l'usage de transactions <literal>JTA</literal>, où la
|
||||
transaction <literal>JTA</literal> définissait la portée et le contexte de la session courante.
|
||||
L'équipe Hibernate pense que, étant donnée la maturité des implémentations de <literal>JTA TransactionManager</literal> ,
|
||||
la plupart (sinon toutes) des applications devraient utiliser la gestion des transactions par <literal>JTA</literal>
|
||||
qu'elles soient ou non déployées dans un conteneur <literal>J2EE</literal>. Par conséquent,
|
||||
vous devriez toujours contextualiser vos sessions, si vous en avez besoin, via la méthode basée sur JTA.
|
||||
qu'elles soient ou non déployées dans un conteneur <literal>J2EE</literal>. Par conséquent,
|
||||
vous devriez toujours contextualiser vos sessions, si vous en avez besoin, via la méthode basée sur JTA.
|
||||
</para>
|
||||
<para>
|
||||
Cependant, depuis la version 3.1, la logique derrière
|
||||
<literal>SessionFactory.getCurrentSession()</literal> est désormais branchable.
|
||||
Cependant, depuis la version 3.1, la logique derrière
|
||||
<literal>SessionFactory.getCurrentSession()</literal> est désormais branchable.
|
||||
A cette fin, une nouvelle interface d'extension (<literal>org.hibernate.context.CurrentSessionContext</literal>)
|
||||
et un nouveau paramètre de configuration (<literal>hibernate.current_session_context_class</literal>)
|
||||
ont été ajoutés pour permettre de configurer d'autres moyens de définir la portée et le contexte des
|
||||
et un nouveau paramètre de configuration (<literal>hibernate.current_session_context_class</literal>)
|
||||
ont été ajoutés pour permettre de configurer d'autres moyens de définir la portée et le contexte des
|
||||
sessions courantes.
|
||||
</para>
|
||||
<para>
|
||||
Allez voir les Javadocs de l'interface <literal>org.hibernate.context.CurrentSessionContext</literal>
|
||||
pour une description détaillée de son contrat. Elle définit une seule méthode,
|
||||
<literal>currentSession()</literal>, depuis laquelle l'implémentation est responsable
|
||||
de traquer la session courante du contexte. Hibernate fournit deux implémentation
|
||||
pour une description détaillée de son contrat. Elle définit une seule méthode,
|
||||
<literal>currentSession()</literal>, depuis laquelle l'implémentation est responsable
|
||||
de traquer la session courante du contexte. Hibernate fournit deux implémentation
|
||||
de cette interface.
|
||||
</para>
|
||||
|
||||
|
@ -326,38 +313,38 @@
|
|||
<listitem>
|
||||
<para>
|
||||
<literal>org.hibernate.context.JTASessionContext</literal> - les sessions courantes sont
|
||||
associées à une transaction <literal>JTA</literal>. La logique est la même que
|
||||
l'ancienne approche basée sur JTA. Voir les javadocs pour les détails.
|
||||
associées à une transaction <literal>JTA</literal>. La logique est la même que
|
||||
l'ancienne approche basée sur JTA. Voir les javadocs pour les détails.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>org.hibernate.context.ThreadLocalSessionContext</literal> - les sessions
|
||||
courantes sont associées au thread d'exécution. Voir les javadocs pour les détails.
|
||||
courantes sont associées au thread d'exécution. Voir les javadocs pour les détails.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Les deux implémentations fournissent un modèle de programmation de type "une session - une transaction
|
||||
à la base de données", aussi connu sous le nom de <emphasis>session-per-request</emphasis>.
|
||||
Le début et la fin d'une session Hibernate sont définis par la durée d'une transaction de base de données.
|
||||
Si vous utilisez une démarcation programmatique de la transaction (par exemple sous J2SE ou JTA/UserTransaction/BMT),
|
||||
nous vous conseillons d'utiliser l'API Hibernate <literal>Transaction</literal> pour masquer le système
|
||||
de transaction utilisé. Si vous exécutez sous un conteneur EJB qui supporte CMT, vous n'avez besoin d'aucune
|
||||
opérations de démarcations de session ou transaction dans votre code puisque tout
|
||||
est géré de manière déclarative. Référez vous à <xref linkend="transactions"/> pour plus d'informations
|
||||
Les deux implémentations fournissent un modèle de programmation de type "une session - une transaction
|
||||
à la base de données", aussi connu sous le nom de <emphasis>session-per-request</emphasis>.
|
||||
Le début et la fin d'une session Hibernate sont définis par la durée d'une transaction de base de données.
|
||||
Si vous utilisez une démarcation programmatique de la transaction (par exemple sous J2SE ou JTA/UserTransaction/BMT),
|
||||
nous vous conseillons d'utiliser l'API Hibernate <literal>Transaction</literal> pour masquer le système
|
||||
de transaction utilisé. Si vous exécutez sous un conteneur EJB qui supporte CMT, vous n'avez besoin d'aucune
|
||||
opérations de démarcations de session ou transaction dans votre code puisque tout
|
||||
est géré de manière déclarative. Référez vous à <xref linkend="transactions"/> pour plus d'informations
|
||||
et des exemples de code.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Le paramètre de configuration <literal>hibernate.current_session_context_class</literal>
|
||||
définit quelle implémentation de <literal>org.hibernate.context.CurrentSessionContext</literal>
|
||||
doit être utilisée. Notez que pour assurer la compatibilité avec les versions précédentes, si
|
||||
ce paramètre n'est pas défini mais qu'un <literal>org.hibernate.transaction.TransactionManagerLookup</literal>
|
||||
est configuré, Hibernate utilisera le <literal>org.hibernate.context.JTASessionContext</literal>.
|
||||
La valeur de ce paramètre devrait juste nommer la classe d'implémentation à utiliser,
|
||||
pour les deux implémentations fournies, il y a cependant deux alias correspondant: "jta" et "thread".
|
||||
Le paramètre de configuration <literal>hibernate.current_session_context_class</literal>
|
||||
définit quelle implémentation de <literal>org.hibernate.context.CurrentSessionContext</literal>
|
||||
doit être utilisée. Notez que pour assurer la compatibilité avec les versions précédentes, si
|
||||
ce paramètre n'est pas défini mais qu'un <literal>org.hibernate.transaction.TransactionManagerLookup</literal>
|
||||
est configuré, Hibernate utilisera le <literal>org.hibernate.context.JTASessionContext</literal>.
|
||||
La valeur de ce paramètre devrait juste nommer la classe d'implémentation à utiliser,
|
||||
pour les deux implémentations fournies, il y a cependant deux alias correspondant: "jta" et "thread".
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="associations">
|
||||
|
||||
<title>Mapper les associations</title>
|
||||
|
@ -7,27 +9,27 @@
|
|||
<title>Introduction</title>
|
||||
|
||||
<para>
|
||||
Correctement mapper les associations est souvent la tâche la plus difficile.
|
||||
Dans cette section nous traiterons les cas classiques les uns après les autres.
|
||||
Correctement mapper les associations est souvent la tâche la plus difficile.
|
||||
Dans cette section nous traiterons les cas classiques les uns après les autres.
|
||||
Nous commencerons d'abbord par les mappings unidirectionnels, puis nous aborderons
|
||||
la question des mappings bidirectionnels. Nous illustrerons tous nos exemples
|
||||
avec les classes <literal>Person</literal> et <literal>Address</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Nous utiliserons deux critères pour classer les associations : le premier
|
||||
sera de savoir si l'association est bâti sur une table supplémentaire d'association
|
||||
et le deuxieme sera basé sur la multiplicité de cette association.
|
||||
Nous utiliserons deux critères pour classer les associations : le premier
|
||||
sera de savoir si l'association est bâti sur une table supplémentaire d'association
|
||||
et le deuxieme sera basé sur la multiplicité de cette association.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Autoriser une clé étrangère nulle est considéré comme un mauvais choix dans
|
||||
la construction d'un modèle de données. Nous supposerons donc que dans tous
|
||||
les exemples qui vont suivre on aura interdit la valeur nulle pour les clés
|
||||
étrangères. Attention, ceci ne veut pas dire que Hibernate ne supporte pas
|
||||
les clés étrangères pouvant prendre des valeurs nulles, les exemples qui suivent
|
||||
continueront de fonctionner si vous décidiez ne plus imposer la contrainte
|
||||
de non-nullité sur les clés étrangères.
|
||||
Autoriser une clé étrangère nulle est considéré comme un mauvais choix dans
|
||||
la construction d'un modèle de données. Nous supposerons donc que dans tous
|
||||
les exemples qui vont suivre on aura interdit la valeur nulle pour les clés
|
||||
étrangères. Attention, ceci ne veut pas dire que Hibernate ne supporte pas
|
||||
les clés étrangères pouvant prendre des valeurs nulles, les exemples qui suivent
|
||||
continueront de fonctionner si vous décidiez ne plus imposer la contrainte
|
||||
de non-nullité sur les clés étrangères.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
@ -36,10 +38,10 @@
|
|||
<title>Association unidirectionnelle</title>
|
||||
|
||||
<sect2 id="assoc-unidirectional-m21" >
|
||||
<title>plusieurs à un</title>
|
||||
<title>plusieurs à un</title>
|
||||
|
||||
<para>
|
||||
Une <emphasis>association plusieurs-à-un (many-to-one) unidirectionnelle </emphasis>
|
||||
Une <emphasis>association plusieurs-à-un (many-to-one) unidirectionnelle </emphasis>
|
||||
est le type que l'on rencontre le plus souvent dans les associations unidirectionnelles.
|
||||
</para>
|
||||
|
||||
|
@ -66,12 +68,12 @@ create table Address ( addressId bigint not null primary key )
|
|||
</sect2>
|
||||
|
||||
<sect2 id="assoc-unidirectional-121">
|
||||
<title>un à un</title>
|
||||
<title>un à un</title>
|
||||
|
||||
<para>
|
||||
une <emphasis>association un-à-un (one-to-one) sur une clé étrangère</emphasis>
|
||||
est presque identique. La seule différence est sur la contrainte d'unicité que
|
||||
l'on impose à cette colonne.
|
||||
une <emphasis>association un-à-un (one-to-one) sur une clé étrangère</emphasis>
|
||||
est presque identique. La seule différence est sur la contrainte d'unicité que
|
||||
l'on impose à cette colonne.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
|
@ -95,8 +97,8 @@ create table Address ( addressId bigint not null primary key )
|
|||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
Une <emphasis>association un-à-un (one-to-one) unidirectionnelle sur une clé primaire</emphasis>
|
||||
utilise un générateur d'identifiant particulier. (Remarquez que nous avons inversé le sens de cette
|
||||
Une <emphasis>association un-à-un (one-to-one) unidirectionnelle sur une clé primaire</emphasis>
|
||||
utilise un générateur d'identifiant particulier. (Remarquez que nous avons inversé le sens de cette
|
||||
association dans cet exemple.)
|
||||
</para>
|
||||
|
||||
|
@ -122,11 +124,11 @@ create table Address ( personId bigint not null primary key )
|
|||
</sect2>
|
||||
|
||||
<sect2 id="assoc-unidirectional-12m">
|
||||
<title>un à plusieurs</title>
|
||||
<title>un à plusieurs</title>
|
||||
|
||||
<para>
|
||||
Une <emphasis>association un-à-plusieurs (one-to-many) unidirectionnelle sur une
|
||||
clé étrangère</emphasis> est vraiment inhabituelle, et n'est pas vraiment recommandée.
|
||||
Une <emphasis>association un-à-plusieurs (one-to-many) unidirectionnelle sur une
|
||||
clé étrangère</emphasis> est vraiment inhabituelle, et n'est pas vraiment recommandée.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
|
@ -151,7 +153,7 @@ create table Address ( addressId bigint not null primary key, personId bigint no
|
|||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
Nous pensons qu'il est préférable d'utiliser une table de jointure pour ce type d'association.
|
||||
Nous pensons qu'il est préférable d'utiliser une table de jointure pour ce type d'association.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
@ -162,14 +164,14 @@ create table Address ( addressId bigint not null primary key, personId bigint no
|
|||
<title>Associations unidirectionnelles avec tables de jointure</title>
|
||||
|
||||
<sect2 id="assoc-unidirectional-join-12m">
|
||||
<title>un à plusieurs</title>
|
||||
<title>un à plusieurs</title>
|
||||
|
||||
<para>
|
||||
Une <emphasis>association unidirectionnelle un-à-plusieurs (one-to-many) avec
|
||||
Une <emphasis>association unidirectionnelle un-à-plusieurs (one-to-many) avec
|
||||
une table de jointure</emphasis> est un bien meilleur choix.
|
||||
Remarquez qu'en spécifiant <literal>unique="true"</literal>,
|
||||
on a changé la multiplicité plusieurs-à-plusieurs (many-to-many) pour
|
||||
un-à-plusieurs (one-to-many).
|
||||
Remarquez qu'en spécifiant <literal>unique="true"</literal>,
|
||||
on a changé la multiplicité plusieurs-à-plusieurs (many-to-many) pour
|
||||
un-à-plusieurs (one-to-many).
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
|
@ -198,11 +200,11 @@ create table Address ( addressId bigint not null primary key )
|
|||
</sect2>
|
||||
|
||||
<sect2 id="assoc-unidirectional-join-m21">
|
||||
<title>plusieurs à un</title>
|
||||
<title>plusieurs à un</title>
|
||||
|
||||
<para>
|
||||
Une <emphasis>assiociation plusieurs-à-un (many-to-one) unidirectionnelle sur
|
||||
une table de jointure</emphasis> est très fréquente quand l'association est optionnelle.
|
||||
Une <emphasis>assiociation plusieurs-à-un (many-to-one) unidirectionnelle sur
|
||||
une table de jointure</emphasis> est très fréquente quand l'association est optionnelle.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
|
@ -232,11 +234,11 @@ create table Address ( addressId bigint not null primary key )
|
|||
</sect2>
|
||||
|
||||
<sect2 id="assoc-unidirectional-join-121">
|
||||
<title>un à un</title>
|
||||
<title>un à un</title>
|
||||
|
||||
<para>
|
||||
Une <emphasis>association unidirectionnelle un-à-un (one-to-one) sur une table
|
||||
de jointure</emphasis> est extrèmement rare mais envisageable.
|
||||
Une <emphasis>association unidirectionnelle un-à-un (one-to-one) sur une table
|
||||
de jointure</emphasis> est extrèmement rare mais envisageable.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
|
@ -268,10 +270,10 @@ create table Address ( addressId bigint not null primary key )
|
|||
</sect2>
|
||||
|
||||
<sect2 id="assoc-unidirectional-join-m2m">
|
||||
<title>plusieurs à plusieurs</title>
|
||||
<title>plusieurs à plusieurs</title>
|
||||
|
||||
<para>
|
||||
Finallement, nous avons <emphasis>l'association unidirectionnelle plusieurs-à-plusieurs (many-to-many)</emphasis>.
|
||||
Finallement, nous avons <emphasis>l'association unidirectionnelle plusieurs-à-plusieurs (many-to-many)</emphasis>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
|
@ -304,11 +306,11 @@ create table Address ( addressId bigint not null primary key )
|
|||
<title>Associations bidirectionnelles</title>
|
||||
|
||||
<sect2 id="assoc-bidirectional-m21" revision="2">
|
||||
<title>un à plusieurs / plusieurs à un</title>
|
||||
<title>un à plusieurs / plusieurs à un</title>
|
||||
|
||||
<para>
|
||||
Une <emphasis>association bidirectionnelle plusieurs à un (many-to-one)</emphasis>
|
||||
est le type d'association que l'on rencontre le plus souvent. (c'est la façon standard de créer
|
||||
Une <emphasis>association bidirectionnelle plusieurs à un (many-to-one)</emphasis>
|
||||
est le type d'association que l'on rencontre le plus souvent. (c'est la façon standard de créer
|
||||
des relations parents/enfants.)
|
||||
</para>
|
||||
|
||||
|
@ -337,10 +339,10 @@ create table Address ( addressId bigint not null primary key )
|
|||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
Si vous utilisez une <literal>List</literal> (ou toute autre collection indexée) vous devez
|
||||
paramétrer la colonne <literal>key</literal> de la clé étrangère à <literal>not null</literal>,
|
||||
et laisser Hibernate gérer l'association depuis l'extrémité collection pour maintenir l'index
|
||||
de chaque élément (rendant l'autre extrémité virtuellement inverse en paramétrant
|
||||
Si vous utilisez une <literal>List</literal> (ou toute autre collection indexée) vous devez
|
||||
paramétrer la colonne <literal>key</literal> de la clé étrangère à <literal>not null</literal>,
|
||||
et laisser Hibernate gérer l'association depuis l'extrémité collection pour maintenir l'index
|
||||
de chaque élément (rendant l'autre extrémité virtuellement inverse en paramétrant
|
||||
<literal>update="false"</literal> et <literal>insert="false"</literal>):
|
||||
</para>
|
||||
|
||||
|
@ -367,11 +369,11 @@ create table Address ( addressId bigint not null primary key )
|
|||
</sect2>
|
||||
|
||||
<sect2 id="assoc-bidirectional-121">
|
||||
<title>Un à un</title>
|
||||
<title>Un à un</title>
|
||||
|
||||
<para>
|
||||
Une <emphasis>association bidirectionnelle un à un (one-to-one) sur une clé étrangère</emphasis>
|
||||
est aussi très fréquente.
|
||||
Une <emphasis>association bidirectionnelle un à un (one-to-one) sur une clé étrangère</emphasis>
|
||||
est aussi très fréquente.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
|
@ -397,8 +399,8 @@ create table Address ( addressId bigint not null primary key )
|
|||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
Une <emphasis>association bidirectionnelle un-à-un (one-to-one) sur une clé primaire</emphasis>
|
||||
utilise un générateur particulier d'id.
|
||||
Une <emphasis>association bidirectionnelle un-à-un (one-to-one) sur une clé primaire</emphasis>
|
||||
utilise un générateur particulier d'id.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
|
@ -430,11 +432,11 @@ create table Address ( personId bigint not null primary key )
|
|||
<title>Associations bidirectionnelles avec table de jointure</title>
|
||||
|
||||
<sect2 id="assoc-bidirectional-join-12m">
|
||||
<title>un à plusieurs / plusieurs à un</title>
|
||||
<title>un à plusieurs / plusieurs à un</title>
|
||||
|
||||
<para>
|
||||
Une <emphasis>association bidirectionnelle un-à-plusieurs (one-to-many) sur une table de jointure </emphasis>.
|
||||
Remarquez que <literal>inverse="true"</literal> peut s'appliquer sur les deux extrémités de l'
|
||||
Une <emphasis>association bidirectionnelle un-à-plusieurs (one-to-many) sur une table de jointure </emphasis>.
|
||||
Remarquez que <literal>inverse="true"</literal> peut s'appliquer sur les deux extrémités de l'
|
||||
association, sur la collection, ou sur la jointure.
|
||||
</para>
|
||||
|
||||
|
@ -473,11 +475,11 @@ create table Address ( addressId bigint not null primary key )
|
|||
</sect2>
|
||||
|
||||
<sect2 id="assoc-bidirectional-join-121">
|
||||
<title>Un à un</title>
|
||||
<title>Un à un</title>
|
||||
|
||||
<para>
|
||||
Une <emphasis>association bidirectionnelle un-à-un (one-to-one) sur une table de jointure</emphasis>
|
||||
est extrèmement rare mais envisageable.
|
||||
Une <emphasis>association bidirectionnelle un-à-un (one-to-one) sur une table de jointure</emphasis>
|
||||
est extrèmement rare mais envisageable.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
|
@ -519,10 +521,10 @@ create table Address ( addressId bigint not null primary key )
|
|||
</sect2>
|
||||
|
||||
<sect2 id="assoc-bidirectional-join-m2m" revision="1">
|
||||
<title>plusieurs à plusieurs</title>
|
||||
<title>plusieurs à plusieurs</title>
|
||||
|
||||
<para>
|
||||
Finallement nous avons <emphasis>l'association bidirectionnelle plusieurs à plusieurs</emphasis>.
|
||||
Finallement nous avons <emphasis>l'association bidirectionnelle plusieurs à plusieurs</emphasis>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
|
@ -561,12 +563,12 @@ create table Address ( addressId bigint not null primary key )
|
|||
<title>Des mappings plus complexes</title>
|
||||
|
||||
<para>
|
||||
Des associations encore plus complexes sont <emphasis>extrêmement</emphasis> rares.
|
||||
Hibernate permet de gérer des situations plus complexes en utilisant des
|
||||
Des associations encore plus complexes sont <emphasis>extrêmement</emphasis> rares.
|
||||
Hibernate permet de gérer des situations plus complexes en utilisant des
|
||||
parties SQL dans les fichiers de mapping. Par exemple, si une table
|
||||
avec l'historiques des informations d'un compte définit les colonnes
|
||||
avec l'historiques des informations d'un compte définit les colonnes
|
||||
<literal>accountNumber</literal>, <literal>effectiveEndDate</literal>
|
||||
et <literal>effectiveStartDate</literal>, mappées de telle sorte:
|
||||
et <literal>effectiveStartDate</literal>, mappées de telle sorte:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<properties name="currentAccountKey">
|
||||
|
@ -579,7 +581,7 @@ create table Address ( addressId bigint not null primary key )
|
|||
<property name="effectiveStateDate" type="date" not-null="true"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
alors nous pouvons mapper une association à l'instance <emphasis>courante</emphasis>
|
||||
alors nous pouvons mapper une association à l'instance <emphasis>courante</emphasis>
|
||||
(celle avec une <literal>effectiveEndDate</literal>) nulle en utilisant:
|
||||
</para>
|
||||
|
||||
|
@ -592,10 +594,10 @@ create table Address ( addressId bigint not null primary key )
|
|||
|
||||
<para>
|
||||
Dans un exemple plus complexe, imaginez qu'une association entre
|
||||
<literal>Employee</literal> et <literal>Organization</literal> est gérée
|
||||
dans une table <literal>Employment</literal> pleines de données historiques.
|
||||
Dans ce cas, une association vers l'employeur <emphasis>le plus récent</emphasis>
|
||||
(celui avec la <literal>startDate</literal> la plus récente) pourrait être mappée comme cela:
|
||||
<literal>Employee</literal> et <literal>Organization</literal> est gérée
|
||||
dans une table <literal>Employment</literal> pleines de données historiques.
|
||||
Dans ce cas, une association vers l'employeur <emphasis>le plus récent</emphasis>
|
||||
(celui avec la <literal>startDate</literal> la plus récente) pourrait être mappée comme cela:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<join>
|
||||
|
@ -612,8 +614,8 @@ create table Address ( addressId bigint not null primary key )
|
|||
</join>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Vous pouvez être créatif grace à ces possibilités, mais il est généralement plus pratique
|
||||
d'utiliser des requêtes HQL ou criteria dans ce genre de situation.
|
||||
Vous pouvez être créatif grace à ces possibilités, mais il est généralement plus pratique
|
||||
d'utiliser des requêtes HQL ou criteria dans ce genre de situation.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,10 +1,12 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="batch">
|
||||
<title>Traitement par paquet</title>
|
||||
|
||||
<para>
|
||||
Une approche naïve pour insérer 100 000 lignes dans la base de données en utilisant
|
||||
Hibernate pourrait ressembler à ça :
|
||||
Une approche naïve pour insérer 100 000 lignes dans la base de données en utilisant
|
||||
Hibernate pourrait ressembler à ça :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
|
@ -17,14 +19,14 @@ tx.commit();
|
|||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Ceci devrait s'écrouler avec une <literal>OutOfMemoryException</literal> quelque
|
||||
part aux alentours de la 50 000ème ligne. C'est parce qu'Hibernate cache toutes
|
||||
les instances de <literal>Customer</literal> nouvellement insérées dans le cache
|
||||
Ceci devrait s'écrouler avec une <literal>OutOfMemoryException</literal> quelque
|
||||
part aux alentours de la 50 000ème ligne. C'est parce qu'Hibernate cache toutes
|
||||
les instances de <literal>Customer</literal> nouvellement insérées dans le cache
|
||||
de second niveau.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Dans ce chapitre nous montrerons comment éviter ce problème. D'abord, cependant,
|
||||
Dans ce chapitre nous montrerons comment éviter ce problème. D'abord, cependant,
|
||||
si vous faites des traitements par batch, il est absolument critique que vous
|
||||
activiez l'utilisation ds paquet JDBC (NdT : JDBC batching), si vous avez l'intention
|
||||
d'obtenir des performances raisonnables. Configurez la taille du paquet JDBC avec un
|
||||
|
@ -34,8 +36,8 @@ session.close();]]></programlisting>
|
|||
<programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
|
||||
|
||||
<para>
|
||||
Vous pourriez aussi vouloir faire cette sorte de travail dans un traitement où
|
||||
l'interaction avec le cache de second niveau est complètement désactivé :
|
||||
Vous pourriez aussi vouloir faire cette sorte de travail dans un traitement où
|
||||
l'interaction avec le cache de second niveau est complètement désactivé :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
|
||||
|
@ -44,9 +46,9 @@ session.close();]]></programlisting>
|
|||
<title>Insertions en paquet</title>
|
||||
|
||||
<para>
|
||||
Lorsque vous rendez des nouveaux objets persistants, vous devez régulièrement appeler
|
||||
Lorsque vous rendez des nouveaux objets persistants, vous devez régulièrement appeler
|
||||
<literal>flush()</literal> et puis <literal>clear()</literal> sur la session,
|
||||
pour contrôler la taille du cache de premier niveau.
|
||||
pour contrôler la taille du cache de premier niveau.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
|
@ -55,8 +57,8 @@ Transaction tx = session.beginTransaction();
|
|||
for ( int i=0; i<100000; i++ ) {
|
||||
Customer customer = new Customer(.....);
|
||||
session.save(customer);
|
||||
if ( i % 20 == 0 ) { //20, même taille que la taille du paquet JDBC
|
||||
//flush un paquet d'insertions et libère la mémoire :
|
||||
if ( i % 20 == 0 ) { //20, même taille que la taille du paquet JDBC
|
||||
//flush un paquet d'insertions et libère la mémoire :
|
||||
session.flush();
|
||||
session.clear();
|
||||
}
|
||||
|
@ -68,12 +70,12 @@ session.close();]]></programlisting>
|
|||
</sect1>
|
||||
|
||||
<sect1 id="batch-update" >
|
||||
<title>Paquet de mises à jour</title>
|
||||
<title>Paquet de mises à jour</title>
|
||||
|
||||
<para>
|
||||
Pour récupérer et mettre à jour des données les mêmes idées s'appliquent. En plus,
|
||||
Pour récupérer et mettre à jour des données les mêmes idées s'appliquent. En plus,
|
||||
vous avez besoin d'utiliser <literal>scroll()</literal> pour tirer partie des
|
||||
curseurs côté serveur pour les requêtes qui retournent beaucoup de lignes de données.
|
||||
curseurs côté serveur pour les requêtes qui retournent beaucoup de lignes de données.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
|
@ -87,7 +89,7 @@ while ( customers.next() ) {
|
|||
Customer customer = (Customer) customers.get(0);
|
||||
customer.updateStuff(...);
|
||||
if ( ++count % 20 == 0 ) {
|
||||
//flush un paquet de mises à jour et libère la mémoire :
|
||||
//flush un paquet de mises à jour et libère la mémoire :
|
||||
session.flush();
|
||||
session.clear();
|
||||
}
|
||||
|
@ -101,20 +103,20 @@ session.close();]]></programlisting>
|
|||
<sect1 id="batch-statelesssession">
|
||||
<title>L'interface StatelessSession</title>
|
||||
<para>
|
||||
Alternativement, Hibernate fournit une API orientée commande qui peut être
|
||||
utilisée avec des flux de données pour et en provenance de la base de données
|
||||
sous la forme d'objets détachés. Une <literal>StatelessSession</literal> n'a pas
|
||||
de contexte de persistance associé et ne fournit pas beaucoup de sémantique de
|
||||
durée de vie de haut niveau. En particulier, une session sans état n'implémente
|
||||
Alternativement, Hibernate fournit une API orientée commande qui peut être
|
||||
utilisée avec des flux de données pour et en provenance de la base de données
|
||||
sous la forme d'objets détachés. Une <literal>StatelessSession</literal> n'a pas
|
||||
de contexte de persistance associé et ne fournit pas beaucoup de sémantique de
|
||||
durée de vie de haut niveau. En particulier, une session sans état n'implémente
|
||||
pas de cache de premier niveau et n'interagit pas non plus avec un cache de
|
||||
seconde niveau ou un cache de requêtes. Elle n'implémente pas les transactions
|
||||
ou la vérification sale automatique (NdT : automatic dirty checking). Les
|
||||
opérations réalisées avec une session sans état ne sont jamais répercutées
|
||||
en cascade sur les instances associées. Les collections sont ignorées par une
|
||||
session sans état. Les opérations exécutées via une session sans état outrepasse
|
||||
le modèle d'événements d'Hibernate et les intercepteurs. Les sessions sans état sont
|
||||
vulnérables aux effets de modification des données, ceci est dû au manque de cache
|
||||
de premier niveau. Une session sans état est une abstraction bas niveau, plus
|
||||
seconde niveau ou un cache de requêtes. Elle n'implémente pas les transactions
|
||||
ou la vérification sale automatique (NdT : automatic dirty checking). Les
|
||||
opérations réalisées avec une session sans état ne sont jamais répercutées
|
||||
en cascade sur les instances associées. Les collections sont ignorées par une
|
||||
session sans état. Les opérations exécutées via une session sans état outrepasse
|
||||
le modèle d'événements d'Hibernate et les intercepteurs. Les sessions sans état sont
|
||||
vulnérables aux effets de modification des données, ceci est dû au manque de cache
|
||||
de premier niveau. Une session sans état est une abstraction bas niveau, plus
|
||||
proche de la couche JDBC sous-jacente.
|
||||
</para>
|
||||
|
||||
|
@ -134,39 +136,39 @@ session.close();]]></programlisting>
|
|||
|
||||
<para>
|
||||
Notez que dans le code de l'exemple, les intances de <literal>Customer</literal>
|
||||
retournées par la requête sont immédiatement détachées. Elles ne sont jamais
|
||||
associées à un contexte de persistance.
|
||||
retournées par la requête sont immédiatement détachées. Elles ne sont jamais
|
||||
associées à un contexte de persistance.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Les opérations <literal>insert()</literal>, <literal>update()</literal> et
|
||||
<literal>delete()</literal> définies par l'interface <literal>StatelessSession</literal>
|
||||
sont considérées comme des opérations d'accès direct aux lignes de la base de données,
|
||||
ce qui résulte en une exécution immédiate du SQL <literal>INSERT</literal>, <literal>UPDATE</literal>
|
||||
ou <literal>DELETE</literal> respectif. De là, elles ont des sémantiques tres différentes des
|
||||
opérations <literal>save()</literal>, <literal>saveOrUpdate()</literal>
|
||||
et <literal>delete()</literal> définies par l'interface <literal>Session</literal>.
|
||||
Les opérations <literal>insert()</literal>, <literal>update()</literal> et
|
||||
<literal>delete()</literal> définies par l'interface <literal>StatelessSession</literal>
|
||||
sont considérées comme des opérations d'accès direct aux lignes de la base de données,
|
||||
ce qui résulte en une exécution immédiate du SQL <literal>INSERT</literal>, <literal>UPDATE</literal>
|
||||
ou <literal>DELETE</literal> respectif. De là, elles ont des sémantiques tres différentes des
|
||||
opérations <literal>save()</literal>, <literal>saveOrUpdate()</literal>
|
||||
et <literal>delete()</literal> définies par l'interface <literal>Session</literal>.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="batch-direct" revision="2">
|
||||
<title>Opérations de style DML</title>
|
||||
<title>Opérations de style DML</title>
|
||||
|
||||
<para>
|
||||
Comme déjà discuté avant, le mapping objet/relationnel automatique et transparent
|
||||
est intéressé par la gestion de l'état de l'objet. Ceci implique que l'état de l'objet
|
||||
est disponible en mémoire, d'où manipuler (en utilisant des expressions du langage de
|
||||
manipulation de données - <literal>Data Manipulation Language</literal> (DML) - SQL)
|
||||
les données directement dans la base n'affectera pas l'état en mémoire. Pourtant, Hibernate
|
||||
fournit des méthodes pour l'exécution d'expression DML de style SQL lesquelles sont
|
||||
réalisées à travers le langage de requête d'Hibernate (<xref linkend="queryhql">HQL</xref>).
|
||||
Comme déjà discuté avant, le mapping objet/relationnel automatique et transparent
|
||||
est intéressé par la gestion de l'état de l'objet. Ceci implique que l'état de l'objet
|
||||
est disponible en mémoire, d'où manipuler (en utilisant des expressions du langage de
|
||||
manipulation de données - <literal>Data Manipulation Language</literal> (DML) - SQL)
|
||||
les données directement dans la base n'affectera pas l'état en mémoire. Pourtant, Hibernate
|
||||
fournit des méthodes pour l'exécution d'expression DML de style SQL lesquelles sont
|
||||
réalisées à travers le langage de requête d'Hibernate (<xref linkend="queryhql">HQL</xref>).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
La pseudo-syntaxe pour les expressions <literal>UPDATE</literal> et <literal>DELETE</literal>
|
||||
est : <literal>( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?</literal>.
|
||||
Certains points sont à noter :
|
||||
Certains points sont à noter :
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
|
@ -177,18 +179,18 @@ session.close();]]></programlisting>
|
|||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Il ne peut y avoir qu'une seule entité nommée dans la clause from ; elle peut
|
||||
optionnellement avoir un alias. Si le nom de l'entité a un alias, alors
|
||||
n'importe quelle référence de propriété doit être qualifiée en ayant un alias ;
|
||||
si le nom de l'entité n'a pas d'alias, alors il est illégal pour n'importe quelle
|
||||
référence de propriété d'être qualifiée.
|
||||
Il ne peut y avoir qu'une seule entité nommée dans la clause from ; elle peut
|
||||
optionnellement avoir un alias. Si le nom de l'entité a un alias, alors
|
||||
n'importe quelle référence de propriété doit être qualifiée en ayant un alias ;
|
||||
si le nom de l'entité n'a pas d'alias, alors il est illégal pour n'importe quelle
|
||||
référence de propriété d'être qualifiée.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Aucune jointure (implicite ou explicite) ne peut être spécifiée dans une requête HQL.
|
||||
Les sous-requêtes peuvent être utilisées dans la clause where ; les sous-requêtes,
|
||||
elles-mêmes, peuvent contenir des jointures.
|
||||
Aucune jointure (implicite ou explicite) ne peut être spécifiée dans une requête HQL.
|
||||
Les sous-requêtes peuvent être utilisées dans la clause where ; les sous-requêtes,
|
||||
elles-mêmes, peuvent contenir des jointures.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
|
@ -199,8 +201,8 @@ session.close();]]></programlisting>
|
|||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Par exemple, pour exécuter un <literal>UPDATE</literal> HQL, utilisez la méthode
|
||||
<literal>Query.executeUpdate()</literal> (la méthode est données pour ceux
|
||||
Par exemple, pour exécuter un <literal>UPDATE</literal> HQL, utilisez la méthode
|
||||
<literal>Query.executeUpdate()</literal> (la méthode est données pour ceux
|
||||
qui sont familiers avec <literal>PreparedStatement.executeUpdate()</literal> de
|
||||
JDBC) :
|
||||
</para>
|
||||
|
@ -218,7 +220,7 @@ tx.commit();
|
|||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Pour exécuter un <literal>DELETE</literal> HQL, utilisez la même méthode
|
||||
Pour exécuter un <literal>DELETE</literal> HQL, utilisez la même méthode
|
||||
<literal>Query.executeUpdate()</literal> :
|
||||
</para>
|
||||
|
||||
|
@ -234,85 +236,85 @@ tx.commit();
|
|||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
La valeur du <literal>int</literal> retourné par la méthode <literal>Query.executeUpdate()</literal>
|
||||
indique le nombre d'entités affectées par l'opération. Considérez que cela peut ou pas
|
||||
corréler le nombre de lignes affectés dans la base de données. Une opération HQL
|
||||
pourrait entraîner l'exécution de multiples expressions SQL réelles, pour des classes
|
||||
filles mappées par jointure (NdT: join-subclass), par exemple. Le nombre retourné
|
||||
indique le nombre d'entités réelles affectées par l'expression. Retour à l'exemple de la
|
||||
classe fille mappée par jointure, un effacement d'une des classes filles peut réellement
|
||||
entraîner des suppressions pas seulement dans la table qui mappe la classe fille, mais
|
||||
La valeur du <literal>int</literal> retourné par la méthode <literal>Query.executeUpdate()</literal>
|
||||
indique le nombre d'entités affectées par l'opération. Considérez que cela peut ou pas
|
||||
corréler le nombre de lignes affectés dans la base de données. Une opération HQL
|
||||
pourrait entraîner l'exécution de multiples expressions SQL réelles, pour des classes
|
||||
filles mappées par jointure (NdT: join-subclass), par exemple. Le nombre retourné
|
||||
indique le nombre d'entités réelles affectées par l'expression. Retour à l'exemple de la
|
||||
classe fille mappée par jointure, un effacement d'une des classes filles peut réellement
|
||||
entraîner des suppressions pas seulement dans la table qui mappe la classe fille, mais
|
||||
aussi dans la table "racine" et potentillement dans les tables des classes filles plus bas
|
||||
dans la hiérarchie d'héritage.
|
||||
dans la hiérarchie d'héritage.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
La pseudo-syntaxe pour l'expression <literal>INSERT</literal> est :
|
||||
<literal>INSERT INTO EntityName properties_list select_statement</literal>. Quelques
|
||||
points sont à noter :
|
||||
points sont à noter :
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
Seule la forme INSERT INTO ... SELECT ... est supportée ; pas la forme INSERT INTO ... VALUES ... .
|
||||
Seule la forme INSERT INTO ... SELECT ... est supportée ; pas la forme INSERT INTO ... VALUES ... .
|
||||
</para>
|
||||
<para>
|
||||
La properties_list est analogue à la <literal>spécification de la colonne</literal>
|
||||
La properties_list est analogue à la <literal>spécification de la colonne</literal>
|
||||
|
||||
The properties_list is analogous to the <literal>column speficiation</literal> dans
|
||||
l'expression SQL <literal>INSERT</literal>. Pour les entités impliquées dans
|
||||
un héritage mappé, seules les propriétés directement définies à ce niveau de classe
|
||||
donné peuvent être utilisées dans properties_list. Les propriétés de la classe mère
|
||||
ne sont pas permises ; et les propriétés des classes filles n'ont pas de sens. En
|
||||
l'expression SQL <literal>INSERT</literal>. Pour les entités impliquées dans
|
||||
un héritage mappé, seules les propriétés directement définies à ce niveau de classe
|
||||
donné peuvent être utilisées dans properties_list. Les propriétés de la classe mère
|
||||
ne sont pas permises ; et les propriétés des classes filles n'ont pas de sens. En
|
||||
d'autres mots, les expressions <literal>INSERT</literal> par nature non polymorphiques.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
select_statement peut être n'importe quelle requête de sélection HQl valide, avec
|
||||
select_statement peut être n'importe quelle requête de sélection HQl valide, avec
|
||||
l'avertissement que les types de retour doivent correspondre aux types attendus par
|
||||
l'insertion. Actuellement, c'est vérifié durant la compilation de la requête plutôt
|
||||
que la vérification soit reléguée à la base de données. Notez cependant que cela
|
||||
pourrait poser des problèmes entre les <literal>Type</literal>s d'Hibernate qui
|
||||
sont <emphasis>équivalents</emphasis> opposé à <emphasis>égaux</emphasis>. Cela
|
||||
pourrait poser des problèmes avec des disparités entre une propriété définie
|
||||
comme un <literal>org.hibernate.type.DateType</literal> et une propriété définie
|
||||
comme un <literal>org.hibernate.type.TimestampType</literal>, même si la base de données
|
||||
ne ferait pas de distinction ou ne serait pas capable de gérer la conversion.
|
||||
l'insertion. Actuellement, c'est vérifié durant la compilation de la requête plutôt
|
||||
que la vérification soit reléguée à la base de données. Notez cependant que cela
|
||||
pourrait poser des problèmes entre les <literal>Type</literal>s d'Hibernate qui
|
||||
sont <emphasis>équivalents</emphasis> opposé à <emphasis>égaux</emphasis>. Cela
|
||||
pourrait poser des problèmes avec des disparités entre une propriété définie
|
||||
comme un <literal>org.hibernate.type.DateType</literal> et une propriété définie
|
||||
comme un <literal>org.hibernate.type.TimestampType</literal>, même si la base de données
|
||||
ne ferait pas de distinction ou ne serait pas capable de gérer la conversion.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Pour la propriéte id, l'expression d'insertion vous donne deux options. Vous
|
||||
pouvez soit spécifier explicitement la propriété id dans properties_list
|
||||
(auquel cas sa valeur est extraite de l'expression de sélection correspondante),
|
||||
soit l'omettre de properties_list (auquel cas une valeur générée est utilisée).
|
||||
Cette dernière option est seulement disponible en utilisant le générateur d'identifiant
|
||||
qui opère dans la base de données ; tenter d'utiliser cette option avec n'importe quel
|
||||
type de générateur "en mémoire" causera une exception durant l'analyse. Notez
|
||||
que pour les buts de cette discussion, les générateurs "en base" sont considérés
|
||||
être <literal>org.hibernate.id.SequenceGenerator</literal> (et ses classes filles)
|
||||
et n'importe quelles implémentations de
|
||||
Pour la propriéte id, l'expression d'insertion vous donne deux options. Vous
|
||||
pouvez soit spécifier explicitement la propriété id dans properties_list
|
||||
(auquel cas sa valeur est extraite de l'expression de sélection correspondante),
|
||||
soit l'omettre de properties_list (auquel cas une valeur générée est utilisée).
|
||||
Cette dernière option est seulement disponible en utilisant le générateur d'identifiant
|
||||
qui opère dans la base de données ; tenter d'utiliser cette option avec n'importe quel
|
||||
type de générateur "en mémoire" causera une exception durant l'analyse. Notez
|
||||
que pour les buts de cette discussion, les générateurs "en base" sont considérés
|
||||
être <literal>org.hibernate.id.SequenceGenerator</literal> (et ses classes filles)
|
||||
et n'importe quelles implémentations de
|
||||
<literal>org.hibernate.id.PostInsertIdentifierGenerator</literal>.
|
||||
L'exception la plus notable ici est <literal>org.hibernate.id.TableHiLoGenerator</literal>,
|
||||
qu ne peut pas être utilisée parce qu'il ne propose pas un moyen de d'exposer ses valeurs
|
||||
qu ne peut pas être utilisée parce qu'il ne propose pas un moyen de d'exposer ses valeurs
|
||||
par un select.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Pour des propriétés mappées comme <literal>version</literal> ou <literal>timestamp</literal>,
|
||||
l'expression d'insertion vous donne deux options. Vous pouvez soit spécifier la propriété dans
|
||||
Pour des propriétés mappées comme <literal>version</literal> ou <literal>timestamp</literal>,
|
||||
l'expression d'insertion vous donne deux options. Vous pouvez soit spécifier la propriété dans
|
||||
properties_list (auquel cas sa valeur est extraite des expressions select correspondantes),
|
||||
soit l'omettre de properties_list (auquel cas la <literal>valeur de graine</literal>
|
||||
(NdT : seed value) définie par le <literal>org.hibernate.type.VersionType</literal> est utilisée).
|
||||
(NdT : seed value) définie par le <literal>org.hibernate.type.VersionType</literal> est utilisée).
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Un exemple d'exécution d'une expression <literal>INSERT</literal> HQL :
|
||||
Un exemple d'exécution d'une expression <literal>INSERT</literal> HQL :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
|
|
|
@ -1,25 +1,27 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="best-practices" revision="3">
|
||||
<title>Meilleures pratiques</title>
|
||||
|
||||
<variablelist spacing="compact">
|
||||
<varlistentry>
|
||||
<term>Découpez finement vos classes et mappez les en utilisant <literal><component></literal>.</term>
|
||||
<term>Découpez finement vos classes et mappez les en utilisant <literal><component></literal>.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Utilisez une classe <literal>Adresse</literal> pour encapsuler <literal>Rue</literal>,
|
||||
<literal>Region</literal>, <literal>CodePostal</literal>.
|
||||
Ceci permet la réutilisation du code et simplifie la maintenance.
|
||||
Ceci permet la réutilisation du code et simplifie la maintenance.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Déclarez des propriétés d'identifiants dans les classes persistantes.</term>
|
||||
<term>Déclarez des propriétés d'identifiants dans les classes persistantes.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernate rend les propriétés d'identifiants optionnelles. Il existe beaucoup de raisons
|
||||
Hibernate rend les propriétés d'identifiants optionnelles. Il existe beaucoup de raisons
|
||||
pour lesquelles vous devriez les utiliser. Nous recommandons que vous utilisiez des identifiants
|
||||
techniques (générés, et sans connotation métier).
|
||||
techniques (générés, et sans connotation métier).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -27,9 +29,9 @@
|
|||
<term>Identifiez les clefs naturelles.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Identifiez les clefs naturelles pour toutes les entités, et mappez les avec
|
||||
<literal><natural-id></literal>. Implémentez <literal>equals()</literal> et
|
||||
<literal>hashCode()</literal> pour comparer les propriétés qui composent la clef naturelle.
|
||||
Identifiez les clefs naturelles pour toutes les entités, et mappez les avec
|
||||
<literal><natural-id></literal>. Implémentez <literal>equals()</literal> et
|
||||
<literal>hashCode()</literal> pour comparer les propriétés qui composent la clef naturelle.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -39,7 +41,7 @@
|
|||
<para>
|
||||
N'utilisez pas un unique document de mapping. Mappez <literal>com.eg.Foo</literal> dans
|
||||
le fichier <literal>com/eg/Foo.hbm.xml</literal>. Cela prend tout son sens lors
|
||||
d'un travail en équipe.
|
||||
d'un travail en équipe.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -47,63 +49,63 @@
|
|||
<term>Chargez les mappings comme des ressources.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Déployez les mappings en même temps que les classes qu'ils mappent.
|
||||
Déployez les mappings en même temps que les classes qu'ils mappent.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Pensez à externaliser les chaînes de caractères.</term>
|
||||
<term>Pensez à externaliser les chaînes de caractères.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Ceci est une bonne habitude si vos requêtes appellent des fonctions SQL qui ne sont
|
||||
Ceci est une bonne habitude si vos requêtes appellent des fonctions SQL qui ne sont
|
||||
pas au standard ANSI. Cette externalisation dans les fichiers de mapping rendra votre
|
||||
application plus portable.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Utilisez les variables "bindées".</term>
|
||||
<term>Utilisez les variables "bindées".</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Comme en JDBC, remplacez toujours les valeurs non constantes par "?". N'utilisez jamais
|
||||
la manipulation des chaînes de caractères pour remplacer des valeurs non constantes dans
|
||||
une requête ! Encore mieux, utilisez les paramètres nommés dans les requêtes.
|
||||
la manipulation des chaînes de caractères pour remplacer des valeurs non constantes dans
|
||||
une requête ! Encore mieux, utilisez les paramètres nommés dans les requêtes.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Ne gérez pas vous même les connexions JDBC.</term>
|
||||
<term>Ne gérez pas vous même les connexions JDBC.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernate laisse l'application gérer les connexions JDBC. Vous ne devriez gérer vos connexions
|
||||
qu'en dernier recours. Si vous ne pouvez pas utiliser les systèmes de connexions livrés,
|
||||
réfléchissez à l'idée de fournir votre propre implémentation de <literal>org.hibernate.connection.ConnectionProvider</literal>.
|
||||
Hibernate laisse l'application gérer les connexions JDBC. Vous ne devriez gérer vos connexions
|
||||
qu'en dernier recours. Si vous ne pouvez pas utiliser les systèmes de connexions livrés,
|
||||
réfléchissez à l'idée de fournir votre propre implémentation de <literal>org.hibernate.connection.ConnectionProvider</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Pensez à utiliser les types utilisateurs.</term>
|
||||
<term>Pensez à utiliser les types utilisateurs.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Supposez que vous ayez une type Java, de telle bibliothèque, qui a besoin d'être persisté mais
|
||||
qui ne fournit pas les accesseurs nécessaires pour le mapper comme composant. Vous devriez
|
||||
implémenter
|
||||
<literal>org.hibernate.UserType</literal>.Cette approche libère le code de l'application
|
||||
de l'implémentation des transformations vers / depuis les types Hibernate.
|
||||
Supposez que vous ayez une type Java, de telle bibliothèque, qui a besoin d'être persisté mais
|
||||
qui ne fournit pas les accesseurs nécessaires pour le mapper comme composant. Vous devriez
|
||||
implémenter
|
||||
<literal>org.hibernate.UserType</literal>.Cette approche libère le code de l'application
|
||||
de l'implémentation des transformations vers / depuis les types Hibernate.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Utilisez du JDBC pur dans les goulets d'étranglement.</term>
|
||||
<term>Utilisez du JDBC pur dans les goulets d'étranglement.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Dans certaines parties critiques de votre système d'un point de vue performance, quelques opérations
|
||||
Dans certaines parties critiques de votre système d'un point de vue performance, quelques opérations
|
||||
peuvent tirer partie d'un appel JDBC natif.
|
||||
Mais attendez de <emphasis>savoir</emphasis>
|
||||
que c'est un goulet d'étranglement. Ne supposez jamais qu'un appel JDBC sera forcément plus
|
||||
que c'est un goulet d'étranglement. Ne supposez jamais qu'un appel JDBC sera forcément plus
|
||||
rapide. Si vous avez besoin d'utiliser JDBC directement, ouvrez une <literal>Session</literal>
|
||||
Hibernate et utilisez la connexion SQL sous-jacente. Ainsi vous pourrez utiliser la même stratégie
|
||||
de transation et la même gestion des connexions.
|
||||
Hibernate et utilisez la connexion SQL sous-jacente. Ainsi vous pourrez utiliser la même stratégie
|
||||
de transation et la même gestion des connexions.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -111,101 +113,101 @@
|
|||
<term>Comprendre le flush de <literal>Session</literal>.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
De temps en temps la Session synchronise ses états persistants avec la base de données.
|
||||
Les performances seront affectées si ce processus arrive trop souvent. Vous pouvez parfois
|
||||
minimiser les flush non nécessaires en désactivant le flush automatique ou même en changeant
|
||||
l'ordre des opérations menées dans une transaction particulière.
|
||||
De temps en temps la Session synchronise ses états persistants avec la base de données.
|
||||
Les performances seront affectées si ce processus arrive trop souvent. Vous pouvez parfois
|
||||
minimiser les flush non nécessaires en désactivant le flush automatique ou même en changeant
|
||||
l'ordre des opérations menées dans une transaction particulière.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Dans une architecture à trois couches, pensez à utiliser <literal>saveOrUpdate()</literal>.</term>
|
||||
<term>Dans une architecture à trois couches, pensez à utiliser <literal>saveOrUpdate()</literal>.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Quand vous utilisez une architecture à base de servlet / session bean, vous pourriez passer
|
||||
des objets chargés dans le bean session vers et depuis la couche servlet / JSP. Utilisez
|
||||
une nouvelle session pour traiter chaque requête.
|
||||
Quand vous utilisez une architecture à base de servlet / session bean, vous pourriez passer
|
||||
des objets chargés dans le bean session vers et depuis la couche servlet / JSP. Utilisez
|
||||
une nouvelle session pour traiter chaque requête.
|
||||
Utilisez <literal>Session.merge()</literal> ou <literal>Session.saveOrUpdate()</literal> pour
|
||||
synchroniser les objets avec la base de données.
|
||||
synchroniser les objets avec la base de données.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Dans une architecture à deux couches, pensez à utiliser la déconnexion de session.</term>
|
||||
<term>Dans une architecture à deux couches, pensez à utiliser la déconnexion de session.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Les transactions de bases de données doivent être aussi courtes que possible
|
||||
pour une meilleure montée en charge.Cependant, il est souvent nécessaire d'implémenter
|
||||
de longues <emphasis>transactions applicatives</emphasis>, une simple unité de travail du point de vue de
|
||||
Les transactions de bases de données doivent être aussi courtes que possible
|
||||
pour une meilleure montée en charge.Cependant, il est souvent nécessaire d'implémenter
|
||||
de longues <emphasis>transactions applicatives</emphasis>, une simple unité de travail du point de vue de
|
||||
l'utilisateur. Une transaction applicative
|
||||
peut s'étaler sur plusieurs cycles de requêtes/réponses du client.
|
||||
Il est commun d'utiliser des objets détachés pour implémenter des transactions applicatives.
|
||||
Une alternative, extrêmement appropriée dans une architecture à 2 couches, est de
|
||||
maintenir un seul contact de persistance ouvert (session) pour toute la durée de vie
|
||||
de la transaction applicative et simplement se déconnecter de la connexion JDBC à la fin de chaque requête,
|
||||
et se reconnecter au début de la requête suivante. Ne partagez jamais une seule
|
||||
peut s'étaler sur plusieurs cycles de requêtes/réponses du client.
|
||||
Il est commun d'utiliser des objets détachés pour implémenter des transactions applicatives.
|
||||
Une alternative, extrêmement appropriée dans une architecture à 2 couches, est de
|
||||
maintenir un seul contact de persistance ouvert (session) pour toute la durée de vie
|
||||
de la transaction applicative et simplement se déconnecter de la connexion JDBC à la fin de chaque requête,
|
||||
et se reconnecter au début de la requête suivante. Ne partagez jamais une seule
|
||||
session avec plus d'une transaction applicative, ou vous travaillerez avec des
|
||||
données périmées.
|
||||
données périmées.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Considérez que les exceptions ne sont pas rattrapables.</term>
|
||||
<term>Considérez que les exceptions ne sont pas rattrapables.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Il s'agit plus d'une pratique obligatoire que d'une "meilleure pratique". Quand une exception
|
||||
intervient, il faut faire un rollback de la <literal>Transaction</literal> et
|
||||
fermer la <literal>Session</literal>.
|
||||
Sinon, Hibernate ne peut garantir l'intégrité des états persistants en mémoire. En particulier,
|
||||
n'utilisez pas <literal>Session.load()</literal> pour déterminer si une instance avec un identifiant
|
||||
donné existe en base de données, utilisez <literal>Session.get()</literal> ou un requête.
|
||||
Sinon, Hibernate ne peut garantir l'intégrité des états persistants en mémoire. En particulier,
|
||||
n'utilisez pas <literal>Session.load()</literal> pour déterminer si une instance avec un identifiant
|
||||
donné existe en base de données, utilisez <literal>Session.get()</literal> ou un requête.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Préférez le chargement tardif des associations.</term>
|
||||
<term>Préférez le chargement tardif des associations.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Utilisez le chargement complet avec modération.
|
||||
Utilisez les proxies et les collections chargées tardivement
|
||||
Utilisez le chargement complet avec modération.
|
||||
Utilisez les proxies et les collections chargées tardivement
|
||||
pour la plupart des associations vers des classes qui ne sont pas susceptibles
|
||||
d'être complètement retenues dans le cache de second niveau.
|
||||
Pour les assocations de classes en cache, où il y a une extrêmement
|
||||
forte probabilité que l'élément soit en cache, désactivez explicitement le chargement
|
||||
d'être complètement retenues dans le cache de second niveau.
|
||||
Pour les assocations de classes en cache, où il y a une extrêmement
|
||||
forte probabilité que l'élément soit en cache, désactivez explicitement le chargement
|
||||
par jointures ouvertes en utilisant <literal>outer-join="false"</literal>.
|
||||
Lorsqu'un chargement par jointure ouverte est approprié pour un cas d'utilisation
|
||||
particulier, utilisez une requête avec un <literal>left join fetch</literal>.
|
||||
Lorsqu'un chargement par jointure ouverte est approprié pour un cas d'utilisation
|
||||
particulier, utilisez une requête avec un <literal>left join fetch</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
Utilisez le pattern <emphasis>d'une ouverture de session dans une vue</emphasis>,
|
||||
ou une <emphasis>phase d'assemblage</emphasis> disciplinée pour éviter des problèmes
|
||||
avec des données non rapatriées.
|
||||
ou une <emphasis>phase d'assemblage</emphasis> disciplinée pour éviter des problèmes
|
||||
avec des données non rapatriées.
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernate libère les développeurs de l'écriture fastidieuse des <emphasis>objets de transfert
|
||||
de données (NdT : Data Transfer Objects)</emphasis> (DTO). Dans une architecture EJB traditionnelle,
|
||||
les DTOs ont deux buts : premièrement, ils contournent le problème des "entity bean" qui ne sont pas
|
||||
sérialisables ; deuxièmement, ils définissent implicitement une phase d'assemblage où toutes les
|
||||
données utilisées par la vue sont rapatriées et organisées dans les DTOs avant de retourner sous le
|
||||
contrôle de la couche de présentation. Hibernate élimine le premier but. Pourtant, vous aurez encore
|
||||
besoin d'une phase d'assemblage (pensez vos méthodes métier comme ayant un contrat strict avec la
|
||||
couche de présentation à propos de quelles données sont disponibles dans les objets détachés)
|
||||
à moins que vous soyez préparés à garder le contexte de
|
||||
persistance (la session) ouvert à travers tout le processus de rendu de la vue.
|
||||
Hibernate libère les développeurs de l'écriture fastidieuse des <emphasis>objets de transfert
|
||||
de données (NdT : Data Transfer Objects)</emphasis> (DTO). Dans une architecture EJB traditionnelle,
|
||||
les DTOs ont deux buts : premièrement, ils contournent le problème des "entity bean" qui ne sont pas
|
||||
sérialisables ; deuxièmement, ils définissent implicitement une phase d'assemblage où toutes les
|
||||
données utilisées par la vue sont rapatriées et organisées dans les DTOs avant de retourner sous le
|
||||
contrôle de la couche de présentation. Hibernate élimine le premier but. Pourtant, vous aurez encore
|
||||
besoin d'une phase d'assemblage (pensez vos méthodes métier comme ayant un contrat strict avec la
|
||||
couche de présentation à propos de quelles données sont disponibles dans les objets détachés)
|
||||
à moins que vous soyez préparés à garder le contexte de
|
||||
persistance (la session) ouvert à travers tout le processus de rendu de la vue.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Pensez à abstraite votre logique métier d'Hibernate.</term>
|
||||
<term>Pensez à abstraite votre logique métier d'Hibernate.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Cachez le mécanisme d'accès aux données (Hibernate) derrière une interface. Combinez les patterns
|
||||
<emphasis>DAO</emphasis> et <emphasis>Thread Local Session</emphasis>. Vous pouvez même avoir quelques
|
||||
classes persistées par du JDBC pur, associées à Hibernate via un <literal>UserType</literal> (ce conseil est
|
||||
Cachez le mécanisme d'accès aux données (Hibernate) derrière une interface. Combinez les patterns
|
||||
<emphasis>DAO</emphasis> et <emphasis>Thread Local Session</emphasis>. Vous pouvez même avoir quelques
|
||||
classes persistées par du JDBC pur, associées à Hibernate via un <literal>UserType</literal> (ce conseil est
|
||||
valable pour des applications de taille respectables ; il n'est pas valable pour une application
|
||||
avec cinq tables).
|
||||
</para>
|
||||
|
@ -217,20 +219,20 @@
|
|||
<para>
|
||||
De bons cas d'utilisation pour de vraies associations plusieurs-vers-plusieurs
|
||||
sont rares. La plupart du temps vous avez besoin d'informations additionnelles
|
||||
stockées dans la table d'association.
|
||||
Dans ce cas, il est préférable d'utiliser deux associations un-vers-plusieurs vers une classe
|
||||
de liaisons intermédiaire. En fait, nous pensons que la plupart des associations sont
|
||||
de type un-vers-plusieurs ou plusieurs-vers-un, vous devez être très attentifs lorsque
|
||||
vous utilisez autre chose et vous demander si c'est vraiment nécessaire.
|
||||
stockées dans la table d'association.
|
||||
Dans ce cas, il est préférable d'utiliser deux associations un-vers-plusieurs vers une classe
|
||||
de liaisons intermédiaire. En fait, nous pensons que la plupart des associations sont
|
||||
de type un-vers-plusieurs ou plusieurs-vers-un, vous devez être très attentifs lorsque
|
||||
vous utilisez autre chose et vous demander si c'est vraiment nécessaire.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Préférez les associations bidirectionnelles.</term>
|
||||
<term>Préférez les associations bidirectionnelles.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Les associations unidirectionnelles sont plus difficiles à questionner.
|
||||
Dans une grande application, la plupart des associations devraient être navigables dans les deux directions dans les requêtes.
|
||||
Les associations unidirectionnelles sont plus difficiles à questionner.
|
||||
Dans une grande application, la plupart des associations devraient être navigables dans les deux directions dans les requêtes.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="collections">
|
||||
<title>Mapping des collections</title>
|
||||
|
||||
|
@ -6,7 +8,7 @@
|
|||
<title>Collections persistantes</title>
|
||||
|
||||
<para>
|
||||
Hibernate requiert que les champs contenant des collections persistantes soient déclarés
|
||||
Hibernate requiert que les champs contenant des collections persistantes soient déclarés
|
||||
comme des types d'interface, par exemple :
|
||||
</para>
|
||||
|
||||
|
@ -21,21 +23,21 @@
|
|||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
L'interface réelle devrait être <literal>java.util.Set</literal>,
|
||||
L'interface réelle devrait être <literal>java.util.Set</literal>,
|
||||
<literal>java.util.Collection</literal>, <literal>java.util.List</literal>,
|
||||
<literal>java.util.Map</literal>, <literal>java.util.SortedSet</literal>,
|
||||
<literal>java.util.SortedMap</literal> ou ... n'importe quoi d'autre ! (Où
|
||||
"n'importe quoi d'autre" signifie que vous devrez écrire une implémentation de
|
||||
<literal>java.util.SortedMap</literal> ou ... n'importe quoi d'autre ! (Où
|
||||
"n'importe quoi d'autre" signifie que vous devrez écrire une implémentation de
|
||||
<literal>org.hibernate.usertype.UserCollectionType</literal>.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Notez comment nous avons initialisé les variables d'instance avec une instance de
|
||||
Notez comment nous avons initialisé les variables d'instance avec une instance de
|
||||
<literal>HashSet</literal>. C'est le meilleur moyen pour initialiser les
|
||||
collections d'instances nouvellement créées (non persistantes). Quand
|
||||
collections d'instances nouvellement créées (non persistantes). Quand
|
||||
nous fabriquons l'instance persistante - en appelant <literal>persist()</literal>,
|
||||
par exemple - Hibernate remplacera réellement le <literal>HashSet</literal>
|
||||
avec une instance d'une implémentation propre à Hibernate de <literal>Set</literal>.
|
||||
par exemple - Hibernate remplacera réellement le <literal>HashSet</literal>
|
||||
avec une instance d'une implémentation propre à Hibernate de <literal>Set</literal>.
|
||||
Prenez garde aux erreurs :
|
||||
</para>
|
||||
|
||||
|
@ -50,7 +52,7 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
(HashSet) cat.getKittens(); // Erreur !]]></programlisting>
|
||||
|
||||
<para>
|
||||
Les collections persistantes injectées par Hibernate se comportent de la même manière que
|
||||
Les collections persistantes injectées par Hibernate se comportent de la même manière que
|
||||
<literal>HashMap</literal>, <literal>HashSet</literal>,
|
||||
<literal>TreeMap</literal>, <literal>TreeSet</literal> ou
|
||||
<literal>ArrayList</literal>, selon le type de l'interface.
|
||||
|
@ -58,19 +60,19 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
|
||||
<para>
|
||||
Les instances des collections ont le comportement habituel des types des valeurs.
|
||||
Elles sont automatiquement persistées quand elles sont référencées par un objet persistant et
|
||||
automatiquement effacées quand elles sont déréférencées. Si une collection est passée
|
||||
d'un objet persistant à un autre, ses éléments pourraient être déplacés d'une table
|
||||
à une autre. Deux entités ne peuvent pas partager une référence vers une même instance
|
||||
d'une collection. Dû au modèle relationnel sous-jacent, les propriétés contenant des
|
||||
collections ne supportent pas la sémantique de la valeur null ; Hibernate ne distingue pas
|
||||
une référence vers une collection nulle d'une collection vide.
|
||||
Elles sont automatiquement persistées quand elles sont référencées par un objet persistant et
|
||||
automatiquement effacées quand elles sont déréférencées. Si une collection est passée
|
||||
d'un objet persistant à un autre, ses éléments pourraient être déplacés d'une table
|
||||
à une autre. Deux entités ne peuvent pas partager une référence vers une même instance
|
||||
d'une collection. Dû au modèle relationnel sous-jacent, les propriétés contenant des
|
||||
collections ne supportent pas la sémantique de la valeur null ; Hibernate ne distingue pas
|
||||
une référence vers une collection nulle d'une collection vide.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Vous ne devriez pas vous préoccuper trop de ça. Utilisez les collections persistantes de
|
||||
la même manière que vous utilisez des collections Java ordinaires. Assurez-vous
|
||||
de comprendre la sémantique des associations bidirectionnelles (traitée plus loin).
|
||||
Vous ne devriez pas vous préoccuper trop de ça. Utilisez les collections persistantes de
|
||||
la même manière que vous utilisez des collections Java ordinaires. Assurez-vous
|
||||
de comprendre la sémantique des associations bidirectionnelles (traitée plus loin).
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
@ -79,9 +81,9 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
<title>Mapper une collection</title>
|
||||
|
||||
<para>
|
||||
L'élément de mapping d'Hibernate utilisé pour mapper une collection dépend du type de
|
||||
l'interface. Par exemple, un élément <literal><set></literal> est utilisé
|
||||
pour mapper des propriétés de type <literal>Set</literal>.
|
||||
L'élément de mapping d'Hibernate utilisé pour mapper une collection dépend du type de
|
||||
l'interface. Par exemple, un élément <literal><set></literal> est utilisé
|
||||
pour mapper des propriétés de type <literal>Set</literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Product">
|
||||
|
@ -93,11 +95,11 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
À part <literal><set></literal>, il y aussi les éléments de mapping
|
||||
À part <literal><set></literal>, il y aussi les éléments de mapping
|
||||
<literal><list></literal>, <literal><map></literal>,
|
||||
<literal><bag></literal>, <literal><array></literal> et
|
||||
<literal><primitive-array></literal>.
|
||||
L'élément <literal><map></literal> est représentatif :
|
||||
L'élément <literal><map></literal> est représentatif :
|
||||
</para>
|
||||
|
||||
<programlistingco>
|
||||
|
@ -143,97 +145,97 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
<calloutlist>
|
||||
<callout arearefs="mappingcollection1">
|
||||
<para>
|
||||
<literal>name</literal> : le nom de la propriété contenant la collection
|
||||
<literal>name</literal> : le nom de la propriété contenant la collection
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="mappingcollection2">
|
||||
<para>
|
||||
<literal>table</literal> (optionnel - par défaut = nom de la propriété) : le
|
||||
nom de la table de la collection (non utilisé pour les associations one-to-many)
|
||||
<literal>table</literal> (optionnel - par défaut = nom de la propriété) : le
|
||||
nom de la table de la collection (non utilisé pour les associations one-to-many)
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="mappingcollection3">
|
||||
<para>
|
||||
<literal>schema</literal> (optionnel) : le nom du schéma pour surcharger le
|
||||
schéma déclaré dans l'élément racine
|
||||
<literal>schema</literal> (optionnel) : le nom du schéma pour surcharger le
|
||||
schéma déclaré dans l'élément racine
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="mappingcollection4">
|
||||
<para>
|
||||
<literal>lazy</literal> (optionnel - par défaut = <literal>true</literal>) :
|
||||
peut être utilisé pour désactiver l'initialisation tardive et spécifier
|
||||
que l'association est toujours rapportée, ou pour activer la
|
||||
récupération extra-paresseuse (NdT : extra-lazy) où la plupart des
|
||||
opérations n'initialisent pas la collection (approprié pour de très
|
||||
<literal>lazy</literal> (optionnel - par défaut = <literal>true</literal>) :
|
||||
peut être utilisé pour désactiver l'initialisation tardive et spécifier
|
||||
que l'association est toujours rapportée, ou pour activer la
|
||||
récupération extra-paresseuse (NdT : extra-lazy) où la plupart des
|
||||
opérations n'initialisent pas la collection (approprié pour de très
|
||||
grosses collections)
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="mappingcollection5">
|
||||
<para>
|
||||
<literal>inverse</literal> (optionnel - par défaut = <literal>false</literal>) :
|
||||
définit cette collection comme l'extrêmité "inverse" de l'association
|
||||
<literal>inverse</literal> (optionnel - par défaut = <literal>false</literal>) :
|
||||
définit cette collection comme l'extrêmité "inverse" de l'association
|
||||
bidirectionnelle
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="mappingcollection6">
|
||||
<para>
|
||||
<literal>cascade</literal> (optionnel - par défaut = <literal>none</literal>) :
|
||||
active les opérations de cascade vers les entités filles
|
||||
<literal>cascade</literal> (optionnel - par défaut = <literal>none</literal>) :
|
||||
active les opérations de cascade vers les entités filles
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="mappingcollection7">
|
||||
<para>
|
||||
<literal>sort</literal> (optionnel) : spécifie une collection triée via un ordre
|
||||
de tri <literal>naturel</literal>, ou via une classe comparateur donnée (implémentant Comparator)
|
||||
<literal>sort</literal> (optionnel) : spécifie une collection triée via un ordre
|
||||
de tri <literal>naturel</literal>, ou via une classe comparateur donnée (implémentant Comparator)
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="mappingcollection8">
|
||||
<para>
|
||||
<literal>order-by</literal> (optionnel, seulement à partir du JDK1.4) :
|
||||
spécifie une colonne de table
|
||||
(ou des colonnes) qui définit l'ordre d'itération de <literal>Map</literal>, <literal>Set</literal>
|
||||
<literal>order-by</literal> (optionnel, seulement à partir du JDK1.4) :
|
||||
spécifie une colonne de table
|
||||
(ou des colonnes) qui définit l'ordre d'itération de <literal>Map</literal>, <literal>Set</literal>
|
||||
ou Bag, avec en option <literal>asc</literal> ou <literal>desc</literal>
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="mappingcollection9">
|
||||
<para>
|
||||
<literal>where</literal> (optionnel) : spécifie une condition SQL arbitraire <literal>WHERE</literal>
|
||||
à utiliser au chargement ou à la suppression d'une collection (utile si la collection
|
||||
ne doit contenir qu'un sous ensemble des données disponibles)
|
||||
<literal>where</literal> (optionnel) : spécifie une condition SQL arbitraire <literal>WHERE</literal>
|
||||
à utiliser au chargement ou à la suppression d'une collection (utile si la collection
|
||||
ne doit contenir qu'un sous ensemble des données disponibles)
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="mappingcollection10">
|
||||
<para>
|
||||
<literal>fetch</literal> (optionnel, par défaut = <literal>select</literal>) :
|
||||
à choisir entre récupération par jointures externes, récupération par
|
||||
selects séquentiels, et récupération par sous-selects séquentiels
|
||||
<literal>fetch</literal> (optionnel, par défaut = <literal>select</literal>) :
|
||||
à choisir entre récupération par jointures externes, récupération par
|
||||
selects séquentiels, et récupération par sous-selects séquentiels
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="mappingcollection11">
|
||||
<para>
|
||||
<literal>batch-size</literal> (optionnel, par défaut = <literal>1</literal>) : une taille
|
||||
de batch (batch size) utilisée pour charger plusieurs instances de cette collection en
|
||||
<literal>batch-size</literal> (optionnel, par défaut = <literal>1</literal>) : une taille
|
||||
de batch (batch size) utilisée pour charger plusieurs instances de cette collection en
|
||||
initialisation tardive
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="mappingcollection12">
|
||||
<para>
|
||||
<literal>access</literal> (optionnel - par défaut = <literal>property</literal>) : La
|
||||
stratégie qu'Hibernate doit utiliser pour accéder à la valeur de la propriété
|
||||
<literal>access</literal> (optionnel - par défaut = <literal>property</literal>) : La
|
||||
stratégie qu'Hibernate doit utiliser pour accéder à la valeur de la propriété
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="mappingcollection13">
|
||||
<para>
|
||||
<literal>optimistic-lock</literal> (optionnel - par défaut = <literal>true</literal>) :
|
||||
spécifie que changer l'état de la collection entraîne l'incrémentation
|
||||
de la version appartenant à l'entité (Pour une association un vers plusieurs,
|
||||
il est souvent raisonnable de désactiver ce paramètre)
|
||||
<literal>optimistic-lock</literal> (optionnel - par défaut = <literal>true</literal>) :
|
||||
spécifie que changer l'état de la collection entraîne l'incrémentation
|
||||
de la version appartenant à l'entité (Pour une association un vers plusieurs,
|
||||
il est souvent raisonnable de désactiver ce paramètre)
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="mappingcollection14">
|
||||
<para>
|
||||
<literal>mutable</literal> (optionnel - par défaut = <literal>true</literal>) :
|
||||
une valeur à <literal>false</literal> spécifie que les éléments de la
|
||||
<literal>mutable</literal> (optionnel - par défaut = <literal>true</literal>) :
|
||||
une valeur à <literal>false</literal> spécifie que les éléments de la
|
||||
collection ne changent jamais (une optimisation mineure dans certains cas)
|
||||
</para>
|
||||
</callout>
|
||||
|
@ -241,74 +243,74 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
</programlistingco>
|
||||
|
||||
<sect2 id="collections-foreignkeys" >
|
||||
<title>Les clefs étrangères d'une collection</title>
|
||||
<title>Les clefs étrangères d'une collection</title>
|
||||
|
||||
<para>
|
||||
Les instances d'une collection sont distinguées dans la base par la clef étrangère
|
||||
de l'entité qui possède la collection. Cette clef étrangère est référencée comme la(es)
|
||||
Les instances d'une collection sont distinguées dans la base par la clef étrangère
|
||||
de l'entité qui possède la collection. Cette clef étrangère est référencée comme la(es)
|
||||
<emphasis>colonne(s) de la clef de la collection</emphasis> de la table de la collection.
|
||||
La colonne de la clef de la collection est mappée par l'élément <literal><key></literal>.
|
||||
La colonne de la clef de la collection est mappée par l'élément <literal><key></literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Il peut y avoir une contrainte de nullité sur la colonne de la clef étrangère. Pour les
|
||||
associations unidirectionnelles un vers plusieurs, la colonne de la clef étrangère
|
||||
peut être nulle par défaut, donc vous pourriez avoir besoin de spécifier
|
||||
Il peut y avoir une contrainte de nullité sur la colonne de la clef étrangère. Pour les
|
||||
associations unidirectionnelles un vers plusieurs, la colonne de la clef étrangère
|
||||
peut être nulle par défaut, donc vous pourriez avoir besoin de spécifier
|
||||
<literal>not-null="true"</literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<key column="productSerialNumber" not-null="true"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
La contraite de la clef étrangère peut utiliser <literal>ON DELETE CASCADE</literal>.
|
||||
La contraite de la clef étrangère peut utiliser <literal>ON DELETE CASCADE</literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<key column="productSerialNumber" on-delete="cascade"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Voir le chapitre précédent pour une définition complète de l'élément <literal><key></literal>.
|
||||
Voir le chapitre précédent pour une définition complète de l'élément <literal><key></literal>.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="collections-elements" >
|
||||
<title>Les éléments d'une collection</title>
|
||||
<title>Les éléments d'une collection</title>
|
||||
|
||||
<para>
|
||||
Les collections peuvent contenir la plupart des autres types Hibernate, dont tous les types
|
||||
basiques, les types utilisateur, les composants, et bien sûr, les références vers
|
||||
d'autres entités. C'est une distinction importante : un objet dans une collection
|
||||
pourrait être géré avec une sémantique de "valeur" (sa durée de vie dépend complètement
|
||||
du propriétaire de la collection) ou il pourrait avoir une référence vers une autre
|
||||
entité, avec sa propre durée de vie. Dans le dernier cas, seul le "lien" entre les 2 objets
|
||||
est considéré être l'état retenu par la collection.
|
||||
basiques, les types utilisateur, les composants, et bien sûr, les références vers
|
||||
d'autres entités. C'est une distinction importante : un objet dans une collection
|
||||
pourrait être géré avec une sémantique de "valeur" (sa durée de vie dépend complètement
|
||||
du propriétaire de la collection) ou il pourrait avoir une référence vers une autre
|
||||
entité, avec sa propre durée de vie. Dans le dernier cas, seul le "lien" entre les 2 objets
|
||||
est considéré être l'état retenu par la collection.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Le type contenu est référencé comme le <emphasis>type de l'élément de la collection</emphasis>.
|
||||
Les éléments de la collections sont mappés par <literal><element></literal> ou
|
||||
<literal><composite-element></literal>, ou dans le cas des références d'entité, avec
|
||||
Le type contenu est référencé comme le <emphasis>type de l'élément de la collection</emphasis>.
|
||||
Les éléments de la collections sont mappés par <literal><element></literal> ou
|
||||
<literal><composite-element></literal>, ou dans le cas des références d'entité, avec
|
||||
<literal><one-to-many></literal> ou <literal><many-to-many></literal>.
|
||||
Les deux premiers mappent des éléments avec un sémantique de valeur, les deux suivants sont
|
||||
utilisés pour mapper des associations d'entité.
|
||||
Les deux premiers mappent des éléments avec un sémantique de valeur, les deux suivants sont
|
||||
utilisés pour mapper des associations d'entité.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="collections-indexed">
|
||||
<title>Collections indexées</title>
|
||||
<title>Collections indexées</title>
|
||||
|
||||
<para>
|
||||
Tous les mappings de collection, exceptés ceux avec les sémantiques d'ensemble (NdT : set) et
|
||||
Tous les mappings de collection, exceptés ceux avec les sémantiques d'ensemble (NdT : set) et
|
||||
de sac (NdT : bag), ont besoin d'une <emphasis>colonne d'index</emphasis> dans la
|
||||
table de la collection - une colonne qui mappe un index de tableau, ou un index de
|
||||
<literal>List</literal>, ou une clef de <literal>Map</literal>. L'index d'une
|
||||
<literal>Map</literal> peut être n'importe quel type basique, mappé avec
|
||||
<literal><map-key></literal>, ça peut être une référence d'entité mappée avec
|
||||
<literal><map-key-many-to-many></literal>, ou ça peut être un type composé, mappé avec
|
||||
<literal>Map</literal> peut être n'importe quel type basique, mappé avec
|
||||
<literal><map-key></literal>, ça peut être une référence d'entité mappée avec
|
||||
<literal><map-key-many-to-many></literal>, ou ça peut être un type composé, mappé avec
|
||||
<literal><composite-map-key></literal>. L'index d'un tableau ou d'une liste est toujours
|
||||
de type <literal>integer</literal> et est mappé en utilisant l'élément <literal><list-index></literal>.
|
||||
Les colonnes mappées contiennent des entiers séquentiels (numérotés à partir de zéro par défaut).
|
||||
de type <literal>integer</literal> et est mappé en utilisant l'élément <literal><list-index></literal>.
|
||||
Les colonnes mappées contiennent des entiers séquentiels (numérotés à partir de zéro par défaut).
|
||||
</para>
|
||||
|
||||
<programlistingco>
|
||||
|
@ -327,8 +329,8 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
</callout>
|
||||
<callout arearefs="index1">
|
||||
<para>
|
||||
<literal>base</literal> (optionnel, par défaut = <literal>0</literal>) : la valeur
|
||||
de la colonne de l'index qui correspond au premier élément de la liste ou du tableau
|
||||
<literal>base</literal> (optionnel, par défaut = <literal>0</literal>) : la valeur
|
||||
de la colonne de l'index qui correspond au premier élément de la liste ou du tableau
|
||||
</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
|
@ -356,7 +358,7 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
<callout arearefs="mapkey2">
|
||||
<para>
|
||||
<literal>formula</literal> (optionnel) :
|
||||
une formule SQL utilisée pour évaluer la clef de la map
|
||||
une formule SQL utilisée pour évaluer la clef de la map
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="mapkey3">
|
||||
|
@ -382,35 +384,35 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
<callout arearefs="indexmanytomany1">
|
||||
<para>
|
||||
<literal>column</literal> (optionnel) :
|
||||
le nom de la colonne de la clef étrangère pour les valeurs de l'index de la collection
|
||||
le nom de la colonne de la clef étrangère pour les valeurs de l'index de la collection
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="indexmanytomany2">
|
||||
<para>
|
||||
<literal>formula</literal> (optionnel) :
|
||||
une formulre SQL utilisée pour évaluer la clef étrangère de la clef de la map
|
||||
une formulre SQL utilisée pour évaluer la clef étrangère de la clef de la map
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="indexmanytomany3">
|
||||
<para>
|
||||
<literal>class</literal> (requis): la classe de l'entité utilisée comme clef de la map
|
||||
<literal>class</literal> (requis): la classe de l'entité utilisée comme clef de la map
|
||||
</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
</programlistingco>
|
||||
<para>
|
||||
Si votre table n'a pas de colonne d'index, et que vous souhaitez tout de même utiliser
|
||||
<literal>List</literal> comme type de propriété, vous devriez mapper la propriété comme un
|
||||
Si votre table n'a pas de colonne d'index, et que vous souhaitez tout de même utiliser
|
||||
<literal>List</literal> comme type de propriété, vous devriez mapper la propriété comme un
|
||||
<emphasis><bag></emphasis> Hibernate. Un sac (NdT : bag) ne garde pas son ordre quand
|
||||
il est récupéré de la base de données, mais il peut être optionnellement trié ou ordonné.
|
||||
il est récupéré de la base de données, mais il peut être optionnellement trié ou ordonné.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<para>
|
||||
Il y a pas mal de variétés de mappings qui peuvent être générés pour les collections,
|
||||
couvrant beaucoup des modèles relationnels communs. Nous vous suggérons d'expérimenter avec l'outil de
|
||||
génération de schéma pour avoir une idée de comment traduire les différentes déclarations de mapping vers des table de la base de données.
|
||||
Il y a pas mal de variétés de mappings qui peuvent être générés pour les collections,
|
||||
couvrant beaucoup des modèles relationnels communs. Nous vous suggérons d'expérimenter avec l'outil de
|
||||
génération de schéma pour avoir une idée de comment traduire les différentes déclarations de mapping vers des table de la base de données.
|
||||
</para>
|
||||
|
||||
<sect2 id="collections-ofvalues" revision="2">
|
||||
|
@ -418,8 +420,8 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
|
||||
<para>
|
||||
N'importe quelle collection de valeurs ou association plusieurs-vers-plusieurs requiert une
|
||||
<emphasis>table de collection</emphasis> avec une(des) colonne(s) de clef étrangère, une(des)
|
||||
<emphasis>colonne(s) d'élément de la collection</emphasis> ou des colonnes et possiblement
|
||||
<emphasis>table de collection</emphasis> avec une(des) colonne(s) de clef étrangère, une(des)
|
||||
<emphasis>colonne(s) d'élément de la collection</emphasis> ou des colonnes et possiblement
|
||||
une(des) colonne(s) d'index.
|
||||
</para>
|
||||
|
||||
|
@ -447,25 +449,25 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
<calloutlist>
|
||||
<callout arearefs="element1b">
|
||||
<para>
|
||||
<literal>column</literal> (optionnel) : le nom de la colonne contenant les valeurs de l'élément de la collection
|
||||
<literal>column</literal> (optionnel) : le nom de la colonne contenant les valeurs de l'élément de la collection
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="element2b">
|
||||
<para>
|
||||
<literal>formula</literal> (optionnel) : une formule SQL utilisée pour évaluer l'élément
|
||||
<literal>formula</literal> (optionnel) : une formule SQL utilisée pour évaluer l'élément
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="element3b">
|
||||
<para>
|
||||
<literal>type</literal> (requis) : le type de l'élément de la collection
|
||||
<literal>type</literal> (requis) : le type de l'élément de la collection
|
||||
</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
</programlistingco>
|
||||
|
||||
<para>
|
||||
Une <emphasis>association plusieurs-vers-plusieurs</emphasis> est spécifiée en
|
||||
utilisant l'élément <literal><many-to-many></literal>.
|
||||
Une <emphasis>association plusieurs-vers-plusieurs</emphasis> est spécifiée en
|
||||
utilisant l'élément <literal><many-to-many></literal>.
|
||||
</para>
|
||||
|
||||
<programlistingco>
|
||||
|
@ -494,63 +496,63 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
<calloutlist>
|
||||
<callout arearefs="manytomany1">
|
||||
<para>
|
||||
<literal>column</literal> (optionnel) : le nom de la colonne de la clef étrangère de l'élément
|
||||
<literal>column</literal> (optionnel) : le nom de la colonne de la clef étrangère de l'élément
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="manytomany2">
|
||||
<para>
|
||||
<literal>formula</literal> (optionnel) :
|
||||
une formule SQL utilisée pour évaluer la valeur de la clef étrangère de l'élément
|
||||
une formule SQL utilisée pour évaluer la valeur de la clef étrangère de l'élément
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="manytomany3">
|
||||
<para>
|
||||
<literal>class</literal> (requis) : le nom de la classe associée
|
||||
<literal>class</literal> (requis) : le nom de la classe associée
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="manytomany4">
|
||||
<para>
|
||||
<literal>fetch</literal> (optionnel - par défaut <literal>join</literal>) :
|
||||
active les récupérations par jointures externes ou par selects séquentiels pour cette association.
|
||||
C'est un cas spécial ; pour une récupération complète sans attente (dans un seul <literal>SELECT</literal>) d'une
|
||||
entité et de ses relations plusieurs-vers-plusieurs vers d'autres entités,
|
||||
vous devriez activer la récupération <literal>join</literal> non seulement sur
|
||||
la collection elle-même, mais aussi avec cet attribut sur l'élément imbriqué
|
||||
<literal>fetch</literal> (optionnel - par défaut <literal>join</literal>) :
|
||||
active les récupérations par jointures externes ou par selects séquentiels pour cette association.
|
||||
C'est un cas spécial ; pour une récupération complète sans attente (dans un seul <literal>SELECT</literal>) d'une
|
||||
entité et de ses relations plusieurs-vers-plusieurs vers d'autres entités,
|
||||
vous devriez activer la récupération <literal>join</literal> non seulement sur
|
||||
la collection elle-même, mais aussi avec cet attribut sur l'élément imbriqué
|
||||
<literal><many-to-many></literal>.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="manytomany5">
|
||||
<para>
|
||||
<literal>unique</literal> (optionnel) : activer la génération DDL d'une
|
||||
contrainte d'unicité pour la colonne de la clef étrangère. Ça rend la pluralité
|
||||
<literal>unique</literal> (optionnel) : activer la génération DDL d'une
|
||||
contrainte d'unicité pour la colonne de la clef étrangère. Ça rend la pluralité
|
||||
de l'association effectivement un-vers-plusieurs.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="manytomany6">
|
||||
<para>
|
||||
<literal>not-found</literal> (optionnel - par défaut <literal>exception</literal>) :
|
||||
spécifie comment les clefs étrangères qui référencent la lignes
|
||||
manquantes seront gérées : <literal>ignore</literal> traitera
|
||||
<literal>not-found</literal> (optionnel - par défaut <literal>exception</literal>) :
|
||||
spécifie comment les clefs étrangères qui référencent la lignes
|
||||
manquantes seront gérées : <literal>ignore</literal> traitera
|
||||
une ligne manquante comme une association nulle.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="manytomany7">
|
||||
<para>
|
||||
<literal>entity-name</literal> (optionnel) : le nom de l'entité de la classe associée, comme une alternative à <literal>class</literal>
|
||||
<literal>entity-name</literal> (optionnel) : le nom de l'entité de la classe associée, comme une alternative à <literal>class</literal>
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="manytomany8">
|
||||
<para>
|
||||
<literal>property-ref</literal> (optionnel) : le nom d'une propriété de
|
||||
la classe associée qui est jointe à cette clef étrangère. Si non spécifiée,
|
||||
la clef primaire de la classe associée est utilisée.
|
||||
<literal>property-ref</literal> (optionnel) : le nom d'une propriété de
|
||||
la classe associée qui est jointe à cette clef étrangère. Si non spécifiée,
|
||||
la clef primaire de la classe associée est utilisée.
|
||||
</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
</programlistingco>
|
||||
|
||||
<para>
|
||||
Quelques exemples, d'abord, un ensemble de chaînes de caractères :
|
||||
Quelques exemples, d'abord, un ensemble de chaînes de caractères :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="names" table="person_names">
|
||||
|
@ -559,7 +561,7 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Un bag contenant des entiers (avec un ordre d'itération déterminé par l'attribut <literal>order-by</literal>) :
|
||||
Un bag contenant des entiers (avec un ordre d'itération déterminé par l'attribut <literal>order-by</literal>) :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<bag name="sizes"
|
||||
|
@ -570,7 +572,7 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
</bag>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Un tableau d'entités - dans ce cas, une association plusieurs-vers-plusieurs :
|
||||
Un tableau d'entités - dans ce cas, une association plusieurs-vers-plusieurs :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<array name="addresses"
|
||||
|
@ -582,7 +584,7 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
</array>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Une map de chaînes de caractères vers des dates :
|
||||
Une map de chaînes de caractères vers des dates :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<map name="holidays"
|
||||
|
@ -616,26 +618,26 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
|
||||
<para>
|
||||
Une <emphasis>association un vers plusieurs</emphasis> lie les tables de deux classes
|
||||
par une clef étrangère, sans l'intervention d'une table de collection. Ce mapping perd certaines sémantiques des collections Java normales :
|
||||
par une clef étrangère, sans l'intervention d'une table de collection. Ce mapping perd certaines sémantiques des collections Java normales :
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
Une instance de la classe de l'entité contenue ne peut pas appartenir à plus d'une
|
||||
Une instance de la classe de l'entité contenue ne peut pas appartenir à plus d'une
|
||||
instance de la collection
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Une instance de la classe de l'entité contenue ne peut pas apparaître plus plus d'une valeur d'index de la collection
|
||||
Une instance de la classe de l'entité contenue ne peut pas apparaître plus plus d'une valeur d'index de la collection
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Une association de <literal>Product</literal> vers <literal>Part</literal> requiert l'existence d'une
|
||||
clef étrangère et possiblement une colonne d'index pour la table <literal>Part</literal>. Une balise
|
||||
clef étrangère et possiblement une colonne d'index pour la table <literal>Part</literal>. Une balise
|
||||
<literal><one-to-many></literal> indique que c'est une association un vers plusieurs.
|
||||
</para>
|
||||
|
||||
|
@ -655,41 +657,41 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
<calloutlist>
|
||||
<callout arearefs="onetomany1">
|
||||
<para>
|
||||
<literal>class</literal> (requis) : le nom de la classe associée
|
||||
<literal>class</literal> (requis) : le nom de la classe associée
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="onetomany2">
|
||||
<para>
|
||||
<literal>not-found</literal> (optionnel - par défaut <literal>exception</literal>) :
|
||||
spécifie comment les identifiants cachés qui référencent des lignes manquantes seront gérés :
|
||||
<literal>not-found</literal> (optionnel - par défaut <literal>exception</literal>) :
|
||||
spécifie comment les identifiants cachés qui référencent des lignes manquantes seront gérés :
|
||||
<literal>ignore</literal> traitera une ligne manquante comme une association nulle
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="onetomany3">
|
||||
<para>
|
||||
<literal>entity-name</literal> (optionnel) : le nom de l'entité de la
|
||||
classe associée, comme une alternative à <literal>class</literal>.
|
||||
<literal>entity-name</literal> (optionnel) : le nom de l'entité de la
|
||||
classe associée, comme une alternative à <literal>class</literal>.
|
||||
</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
</programlistingco>
|
||||
|
||||
<para>
|
||||
Notez que l'élément <literal><one-to-many></literal> n'a pas besoin de déclarer de colonnes. Il n'est pas non plus nécessaire de spécifier le nom de la table nulle part.
|
||||
Notez que l'élément <literal><one-to-many></literal> n'a pas besoin de déclarer de colonnes. Il n'est pas non plus nécessaire de spécifier le nom de la table nulle part.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>Note très importante :</emphasis> si la colonne de la clef d'une association
|
||||
<literal><one-to-many></literal> est déclarée <literal>NOT NULL</literal>, vous devez déclarer le
|
||||
<emphasis>Note très importante :</emphasis> si la colonne de la clef d'une association
|
||||
<literal><one-to-many></literal> est déclarée <literal>NOT NULL</literal>, vous devez déclarer le
|
||||
mapping de <literal><key></literal> avec <literal>not-null="true"</literal> ou
|
||||
<emphasis>utiliser une association bidirectionnelle</emphasis> avec le mapping de la
|
||||
collection marqué <literal>inverse="true"</literal>. Voir la discussion sur les associations bidirectionnelles plus tard dans ce chapitre.
|
||||
collection marqué <literal>inverse="true"</literal>. Voir la discussion sur les associations bidirectionnelles plus tard dans ce chapitre.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Cet exemple montre une map d'entités <literal>Part</literal> par nom (où
|
||||
<literal>partName</literal> est une propriété persistante de <literal>Part</literal>).
|
||||
Notez l'utilisation d'un index basé sur une formule.
|
||||
Cet exemple montre une map d'entités <literal>Part</literal> par nom (où
|
||||
<literal>partName</literal> est une propriété persistante de <literal>Part</literal>).
|
||||
Notez l'utilisation d'un index basé sur une formule.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<map name="parts"
|
||||
|
@ -703,14 +705,14 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
</sect1>
|
||||
|
||||
<sect1 id="collections-advancedmappings">
|
||||
<title>Mappings de collection avancés</title>
|
||||
<title>Mappings de collection avancés</title>
|
||||
|
||||
<sect2 id="collections-sorted" revision="2">
|
||||
<title>Collections triées</title>
|
||||
<title>Collections triées</title>
|
||||
|
||||
<para>
|
||||
Hibernate supporte des collections implémentant <literal>java.util.SortedMap</literal> et
|
||||
<literal>java.util.SortedSet</literal>. Vous devez spécifier un comparateur dans le fichier de mapping :
|
||||
Hibernate supporte des collections implémentant <literal>java.util.SortedMap</literal> et
|
||||
<literal>java.util.SortedSet</literal>. Vous devez spécifier un comparateur dans le fichier de mapping :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="aliases"
|
||||
|
@ -728,21 +730,21 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
|
||||
<para>
|
||||
Les valeurs permises pour l'attribut <literal>sort</literal> sont <literal>unsorted</literal>,
|
||||
<literal>natural</literal> et le nom d'une classe implémentant
|
||||
<literal>natural</literal> et le nom d'une classe implémentant
|
||||
<literal>java.util.Comparator</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Les collections triées se comportent réellement comme <literal>java.util.TreeSet</literal> ou
|
||||
Les collections triées se comportent réellement comme <literal>java.util.TreeSet</literal> ou
|
||||
<literal>java.util.TreeMap</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Si vous voulez que la base de données elle-même ordonne les éléments de la collection, utilisez l'attribut
|
||||
Si vous voulez que la base de données elle-même ordonne les éléments de la collection, utilisez l'attribut
|
||||
<literal>order-by</literal> des mappings <literal>set</literal>, <literal>bag</literal>
|
||||
ou <literal>map</literal>. Cette solution est seulement disponible à partir du JDK 1.4 (c'est
|
||||
implémenté en utilisant <literal>LinkedHashSet</literal> ou
|
||||
<literal>LinkedHashMap</literal>). Ceci exécute le tri dans la requête SQL, pas en mémoire.
|
||||
ou <literal>map</literal>. Cette solution est seulement disponible à partir du JDK 1.4 (c'est
|
||||
implémenté en utilisant <literal>LinkedHashSet</literal> ou
|
||||
<literal>LinkedHashMap</literal>). Ceci exécute le tri dans la requête SQL, pas en mémoire.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="aliases" table="person_aliases" order-by="lower(name) asc">
|
||||
|
@ -761,7 +763,7 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
</para>
|
||||
|
||||
<para>
|
||||
Les associations peuvent même être triées sur des critères arbitraires à l'exécution en utilisant un <literal>filter()</literal> de collection.
|
||||
Les associations peuvent même être triées sur des critères arbitraires à l'exécution en utilisant un <literal>filter()</literal> de collection.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[sortedUsers = s.createFilter( group.getUsers(), "order by this.name" ).list();]]></programlisting>
|
||||
|
@ -772,14 +774,14 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
<title>Associations bidirectionnelles</title>
|
||||
|
||||
<para>
|
||||
Une <emphasis>association bidirectionnelle</emphasis> permet une navigation à
|
||||
partir de la "fin" de l'association. Deux sortes d'associations bidirectionnelles sont supportées :
|
||||
Une <emphasis>association bidirectionnelle</emphasis> permet une navigation à
|
||||
partir de la "fin" de l'association. Deux sortes d'associations bidirectionnelles sont supportées :
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>un-vers-plusieurs (NdT : one-to-many)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
ensemble ou sac à une extrémité, une seule valeur à l'autre
|
||||
ensemble ou sac à une extrémité, une seule valeur à l'autre
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -787,7 +789,7 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
<term>plusieurs-vers-plusieurs (NdT : many-to-many)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
ensemble ou sac aux deux extrémités
|
||||
ensemble ou sac aux deux extrémités
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -795,13 +797,13 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
</para>
|
||||
|
||||
<para>
|
||||
Vous pouvez spécifier une association plusieurs-vers-plusieurs bidirectionnelle simplement
|
||||
en mappant deux associations plusieurs-vers-plusieurs vers la même table de base de données et en déclarant une extrémité comme <emphasis>inverse</emphasis> (celle de votre choix, mais ça ne peut pas être une collection indexée).
|
||||
Vous pouvez spécifier une association plusieurs-vers-plusieurs bidirectionnelle simplement
|
||||
en mappant deux associations plusieurs-vers-plusieurs vers la même table de base de données et en déclarant une extrémité comme <emphasis>inverse</emphasis> (celle de votre choix, mais ça ne peut pas être une collection indexée).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Voici un exemple d'association bidirectionnelle plusieurs-vers-plusieurs ; chaque catégorie peut
|
||||
avoir plusieurs objets et chaque objet peut être dans plusieurs catégories :
|
||||
Voici un exemple d'association bidirectionnelle plusieurs-vers-plusieurs ; chaque catégorie peut
|
||||
avoir plusieurs objets et chaque objet peut être dans plusieurs catégories :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Category">
|
||||
|
@ -825,28 +827,28 @@ kittens = cat.getKittens(); // Ok, la collection kittens est un Set
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Les changements faits uniquement sur l'extréminté inverse de l'association <emphasis>ne sont pas</emphasis>
|
||||
persistés. Ceci signifie qu'Hibernate a deux représentations en mémoire pour chaque
|
||||
Les changements faits uniquement sur l'extréminté inverse de l'association <emphasis>ne sont pas</emphasis>
|
||||
persistés. Ceci signifie qu'Hibernate a deux représentations en mémoire pour chaque
|
||||
association bidirectionnelles, un lien de A vers B et un autre de B vers A. C'est
|
||||
plus facile à comprendre si vous pensez au modèle objet de Java et comment nous
|
||||
créons une relation plusieurs-vers-plusieurs en Java :
|
||||
plus facile à comprendre si vous pensez au modèle objet de Java et comment nous
|
||||
créons une relation plusieurs-vers-plusieurs en Java :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
category.getItems().add(item); // La catégorie est maintenant "au courant" de la relation
|
||||
category.getItems().add(item); // La catégorie est maintenant "au courant" de la relation
|
||||
item.getCategories().add(category); // L'objet est maintenant "au courant" de la relation
|
||||
|
||||
session.persist(item); // La relation ne sera pas sauvegardée !
|
||||
session.persist(category); // La relation sera sauvegardée]]></programlisting>
|
||||
session.persist(item); // La relation ne sera pas sauvegardée !
|
||||
session.persist(category); // La relation sera sauvegardée]]></programlisting>
|
||||
|
||||
<para>
|
||||
La partie non-inverse est utilisée pour sauvegarder la représentation en mémoire dans la base de données.
|
||||
La partie non-inverse est utilisée pour sauvegarder la représentation en mémoire dans la base de données.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Vous pouvez définir une association un-vers-plusieurs bidirectionnelle en mappant une
|
||||
association un-vers-plusieurs vers la(es) même(s) colonne(s) de table qu'une association
|
||||
plusieurs-vers-un et en déclarant l'extrémité pluri-valuée <literal>inverse="true"</literal>.
|
||||
Vous pouvez définir une association un-vers-plusieurs bidirectionnelle en mappant une
|
||||
association un-vers-plusieurs vers la(es) même(s) colonne(s) de table qu'une association
|
||||
plusieurs-vers-un et en déclarant l'extrémité pluri-valuée <literal>inverse="true"</literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Parent">
|
||||
|
@ -868,19 +870,19 @@ session.persist(category); // La relation sera sauvegard
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Mapper une extrémité d'une association avec <literal>inverse="true"</literal> n'affecte
|
||||
pas l'opération de cascades, ce sont des concepts orthogonaux !
|
||||
Mapper une extrémité d'une association avec <literal>inverse="true"</literal> n'affecte
|
||||
pas l'opération de cascades, ce sont des concepts orthogonaux !
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="collections-indexedbidirectional">
|
||||
<title>Associations bidirectionnelles avec des collections indexées</title>
|
||||
<title>Associations bidirectionnelles avec des collections indexées</title>
|
||||
<para>
|
||||
Une association bidirectionnelle où une extrémité est représentée comme une <literal><list></literal>
|
||||
ou une <literal><map></literal> requiert une considération spéciale. Si il y a une
|
||||
propriété de la classe enfant qui mappe la colonne de l'index, pas de problème, nous pouvons
|
||||
continuer à utiliser <literal>inverse="true"</literal> sur le mapping de la collection :
|
||||
Une association bidirectionnelle où une extrémité est représentée comme une <literal><list></literal>
|
||||
ou une <literal><map></literal> requiert une considération spéciale. Si il y a une
|
||||
propriété de la classe enfant qui mappe la colonne de l'index, pas de problème, nous pouvons
|
||||
continuer à utiliser <literal>inverse="true"</literal> sur le mapping de la collection :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Parent">
|
||||
|
@ -906,10 +908,10 @@ session.persist(category); // La relation sera sauvegard
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Mais, si il n'y a pas de telle prorpriété sur la classe enfant, nous ne pouvons pas penser
|
||||
à l'association comme vraiment bidirectionnelle (il y a des informations disponibles à une
|
||||
extrémité de l'association qui ne sont pas disponibles à l'autre extrémité). Dans ce cas,
|
||||
nous ne pouvons pas mapper la collection <literal>inverse="true"</literal>. À la place, nous
|
||||
Mais, si il n'y a pas de telle prorpriété sur la classe enfant, nous ne pouvons pas penser
|
||||
à l'association comme vraiment bidirectionnelle (il y a des informations disponibles à une
|
||||
extrémité de l'association qui ne sont pas disponibles à l'autre extrémité). Dans ce cas,
|
||||
nous ne pouvons pas mapper la collection <literal>inverse="true"</literal>. À la place, nous
|
||||
pourrions utiliser le mapping suivant :
|
||||
</para>
|
||||
|
||||
|
@ -937,8 +939,8 @@ session.persist(category); // La relation sera sauvegard
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Notez que dans ce mapping, l'extrémité de l'association contenant la collection est responsable
|
||||
des mises à jour de la clef étrangère. À faire : cela entraîne-t-il réellement des expressions
|
||||
Notez que dans ce mapping, l'extrémité de l'association contenant la collection est responsable
|
||||
des mises à jour de la clef étrangère. À faire : cela entraîne-t-il réellement des expressions
|
||||
updates inutiles ?
|
||||
</para>
|
||||
|
||||
|
@ -965,12 +967,12 @@ session.persist(category); // La relation sera sauvegard
|
|||
</map>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Une seconde approche est simplement de remodeler l'association comme une classe d'entité. C'est
|
||||
Une seconde approche est simplement de remodeler l'association comme une classe d'entité. C'est
|
||||
l'approche la plus commune.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Une alternative finale est d'utiliser des éléments composites, dont nous discuterons plus tard.
|
||||
Une alternative finale est d'utiliser des éléments composites, dont nous discuterons plus tard.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
@ -979,21 +981,21 @@ session.persist(category); // La relation sera sauvegard
|
|||
<title>Utiliser un <literal><idbag></literal></title>
|
||||
|
||||
<para>
|
||||
Si vous embrassez pleinement notre vue que les clefs composées sont une mauvaise
|
||||
chose et que des entités devraient avoir des identifiants artificiels (des clefs
|
||||
subrogées), alors vous pourriez trouver un peu curieux que les associations
|
||||
plusieurs-vers-plusieurs et les collections de valeurs que nous avons montré jusqu'ici
|
||||
mappent toutes des tables avec des clefs composées ! Maintenant, ce point est assez
|
||||
discutable ; une table d'association pure ne semble pas beaucoup bénéficier d'une clef
|
||||
subrogée (bien qu'une collection de valeur composées le <emphasis>pourrait</emphasis>).
|
||||
Néanmoins, Hibernate fournit une foncionnalité qui vous permet de mapper
|
||||
Si vous embrassez pleinement notre vue que les clefs composées sont une mauvaise
|
||||
chose et que des entités devraient avoir des identifiants artificiels (des clefs
|
||||
subrogées), alors vous pourriez trouver un peu curieux que les associations
|
||||
plusieurs-vers-plusieurs et les collections de valeurs que nous avons montré jusqu'ici
|
||||
mappent toutes des tables avec des clefs composées ! Maintenant, ce point est assez
|
||||
discutable ; une table d'association pure ne semble pas beaucoup bénéficier d'une clef
|
||||
subrogée (bien qu'une collection de valeur composées le <emphasis>pourrait</emphasis>).
|
||||
Néanmoins, Hibernate fournit une foncionnalité qui vous permet de mapper
|
||||
des associations plusieurs-vers-plusieurs et des collections de valeurs vers une
|
||||
table avec une clef subrogée.
|
||||
table avec une clef subrogée.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
L'élément <literal><idbag></literal> vous laisse mapper une <literal>List</literal>
|
||||
(ou une <literal>Collection</literal>) avec une sémantique de sac.
|
||||
L'élément <literal><idbag></literal> vous laisse mapper une <literal>List</literal>
|
||||
(ou une <literal>Collection</literal>) avec une sémantique de sac.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<idbag name="lovers" table="LOVERS">
|
||||
|
@ -1005,22 +1007,22 @@ session.persist(category); // La relation sera sauvegard
|
|||
</idbag>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Comme vous pouvez voir, un <literal><idbag></literal> a un généréteur d'id
|
||||
artificiel, comme une classe d'entité ! Une clef subrogée différente est assignée
|
||||
à chaque ligne de la collection. Cependant, Hibernate ne fournit pas de mécanisme pour
|
||||
découvrir la valeur d'une clef subrogée d'une ligne particulière.
|
||||
Comme vous pouvez voir, un <literal><idbag></literal> a un généréteur d'id
|
||||
artificiel, comme une classe d'entité ! Une clef subrogée différente est assignée
|
||||
à chaque ligne de la collection. Cependant, Hibernate ne fournit pas de mécanisme pour
|
||||
découvrir la valeur d'une clef subrogée d'une ligne particulière.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Notez que les performances de la mise à jour d'un <literal><idbag></literal>
|
||||
Notez que les performances de la mise à jour d'un <literal><idbag></literal>
|
||||
sont <emphasis>bien</emphasis> meilleures qu'un <literal><bag></literal> ordinaire !
|
||||
Hibernate peut localiser des lignes individuelles efficacement et les mettre à jour ou
|
||||
Hibernate peut localiser des lignes individuelles efficacement et les mettre à jour ou
|
||||
les effacer individuellement, comme une liste, une map ou un ensemble.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Dans l'implémentation actuelle, la stratégie de la génération de l'identifiant <literal>native</literal>
|
||||
n'est pas supportée pour les identifiants de collection <literal><idbag></literal>.
|
||||
Dans l'implémentation actuelle, la stratégie de la génération de l'identifiant <literal>native</literal>
|
||||
n'est pas supportée pour les identifiants de collection <literal><idbag></literal>.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
@ -1045,7 +1047,7 @@ session.persist(category); // La relation sera sauvegard
|
|||
<title>Exemples de collections</title>
|
||||
|
||||
<para>
|
||||
Les sections précédentes sont assez confuses. Donc prenons un exemple. Cette classe :
|
||||
Les sections précédentes sont assez confuses. Donc prenons un exemple. Cette classe :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
|
@ -1093,7 +1095,7 @@ public class Parent {
|
|||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Ceci mappe les définitions de tables suivantes :
|
||||
Ceci mappe les définitions de tables suivantes :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[create table parent ( id bigint not null primary key )
|
||||
|
@ -1139,7 +1141,7 @@ alter table child add constraint childfk0 (parent_id) references parent]]></prog
|
|||
|
||||
<para>
|
||||
Alternativement, si vous insistez absolument pour que cette association soit unidirectionnelle,
|
||||
vous pouvez déclarer la contrainte <literal>NOT NULL</literal> sur le mapping <literal><key></literal> :
|
||||
vous pouvez déclarer la contrainte <literal>NOT NULL</literal> sur le mapping <literal><key></literal> :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
@ -1164,8 +1166,8 @@ alter table child add constraint childfk0 (parent_id) references parent]]></prog
|
|||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<para>
|
||||
D'un autre côté, si un enfant pouvait avoir plusieurs parent, une association
|
||||
plusieurs-vers-plusieurs est plus appropriée :
|
||||
D'un autre côté, si un enfant pouvait avoir plusieurs parent, une association
|
||||
plusieurs-vers-plusieurs est plus appropriée :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
@ -1190,7 +1192,7 @@ alter table child add constraint childfk0 (parent_id) references parent]]></prog
|
|||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Définitions des tables :
|
||||
Définitions des tables :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[create table parent ( id bigint not null primary key )
|
||||
|
@ -1202,12 +1204,12 @@ alter table childset add constraint childsetfk0 (parent_id) references parent
|
|||
alter table childset add constraint childsetfk1 (child_id) references child]]></programlisting>
|
||||
|
||||
<para>
|
||||
Pour plus d'exemples et une revue complète du mapping de la relation parent/enfant, voir
|
||||
Pour plus d'exemples et une revue complète du mapping de la relation parent/enfant, voir
|
||||
see <xref linkend="example-parentchild"/>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Des mappings d'association plus exotiques sont possibles, nous cataloguerons toutes les possibilités
|
||||
Des mappings d'association plus exotiques sont possibles, nous cataloguerons toutes les possibilités
|
||||
dans le prochain chapitre.
|
||||
</para>
|
||||
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
<?xml version='1.0' encoding="iso-8859-1"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="components">
|
||||
<title>Mapping de composants</title>
|
||||
|
||||
<para>
|
||||
La notion de <emphasis>composants</emphasis> est réutilisé dans différents contextes,
|
||||
avec différents objectifs, à travers Hibernate.
|
||||
La notion de <emphasis>composants</emphasis> est réutilisé dans différents contextes,
|
||||
avec différents objectifs, à travers Hibernate.
|
||||
</para>
|
||||
|
||||
<sect1 id="components-dependentobjects" revision="2" >
|
||||
<title>Objects dépendants</title>
|
||||
<title>Objects dépendants</title>
|
||||
|
||||
<para>
|
||||
Le composant est un objet inclu dans un autre qui est sauvegardé comme une valeur, et
|
||||
non pas comme une entité.
|
||||
Le composant fait référence à la notion (au sens objet) de composition
|
||||
Le composant est un objet inclu dans un autre qui est sauvegardé comme une valeur, et
|
||||
non pas comme une entité.
|
||||
Le composant fait référence à la notion (au sens objet) de composition
|
||||
(et non pas de composant au sens d'architecture de composants).
|
||||
Par exemple on pourrait modélisé l'objet personne de cette façon:
|
||||
Par exemple on pourrait modélisé l'objet personne de cette façon:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public class Person {
|
||||
|
@ -69,14 +71,14 @@
|
|||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
Maintenant <literal>Name</literal> peut-être sauvegardé comme un composant de
|
||||
<literal>Person</literal>. Remarquer que <literal>Name</literal> définit des methodes
|
||||
d'accès et de modification pour ses propriétés persistantes, mais il n'a pas besoin
|
||||
des interfaces ou des propriétés d'identification ( par exemple getId() ) qui sont propres aux entités.
|
||||
Maintenant <literal>Name</literal> peut-être sauvegardé comme un composant de
|
||||
<literal>Person</literal>. Remarquer que <literal>Name</literal> définit des methodes
|
||||
d'accès et de modification pour ses propriétés persistantes, mais il n'a pas besoin
|
||||
des interfaces ou des propriétés d'identification ( par exemple getId() ) qui sont propres aux entités.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Nous serions alors amené à mapper ce composant de cette façon:
|
||||
Nous serions alors amené à mapper ce composant de cette façon:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Person" table="person">
|
||||
|
@ -100,24 +102,24 @@
|
|||
</para>
|
||||
|
||||
<para>
|
||||
Comme tous les types valeurs, les composants ne supportent pas les références partagés.
|
||||
En d'autres mots, deux instances de person peuvent avoir un même nom, mais ces noms sont
|
||||
indépendants, ils peuvent être identiques si on les compare par valeur mais ils représentent
|
||||
deux objets distincts en mémoire. La notion de nullité pour un composant est
|
||||
Comme tous les types valeurs, les composants ne supportent pas les références partagés.
|
||||
En d'autres mots, deux instances de person peuvent avoir un même nom, mais ces noms sont
|
||||
indépendants, ils peuvent être identiques si on les compare par valeur mais ils représentent
|
||||
deux objets distincts en mémoire. La notion de nullité pour un composant est
|
||||
<emphasis>ad hoc</emphasis>. Quand il recharge l'objet qui contient le composant, Hibernate
|
||||
supposera que si tous les champs du composants sont nuls alors le composant sera positionné
|
||||
à la valeur null. Ce choix programmatif devrait être satisfaisant dans la plupart des cas.
|
||||
supposera que si tous les champs du composants sont nuls alors le composant sera positionné
|
||||
à la valeur null. Ce choix programmatif devrait être satisfaisant dans la plupart des cas.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Les propriétés d'un composant peuvent être de tous les types qu'Hibernate supporte habituellement
|
||||
Les propriétés d'un composant peuvent être de tous les types qu'Hibernate supporte habituellement
|
||||
(collections, many-to-one associations, autres composants, etc). Les composants inclus ne doivent <emphasis>pas</emphasis>
|
||||
être vus comme quelque chose d'exotique. Hibernate a été conçu pour supporter un modèle objet très granulaire.
|
||||
être vus comme quelque chose d'exotique. Hibernate a été conçu pour supporter un modèle objet très granulaire.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Le <literal><component></literal> peut inclure dans la liste de ses propriétés
|
||||
une référence au <literal><parent></literal> conteneur.
|
||||
Le <literal><component></literal> peut inclure dans la liste de ses propriétés
|
||||
une référence au <literal><parent></literal> conteneur.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Person" table="person">
|
||||
|
@ -126,7 +128,7 @@
|
|||
</id>
|
||||
<property name="birthday" type="date"/>
|
||||
<component name="Name" class="eg.Name" unique="true">
|
||||
<parent name="namedPerson"/> <!-- référence arrière à Person -->
|
||||
<parent name="namedPerson"/> <!-- référence arrière à Person -->
|
||||
<property name="initial"/>
|
||||
<property name="first"/>
|
||||
<property name="last"/>
|
||||
|
@ -136,11 +138,11 @@
|
|||
</sect1>
|
||||
|
||||
<sect1 id="components-incollections" revision="1">
|
||||
<title>Collection d'objets dépendants</title>
|
||||
<title>Collection d'objets dépendants</title>
|
||||
|
||||
<para>
|
||||
Les collections d'objets dépendants sont supportés (exemple: un tableau de type
|
||||
<literal>Name</literal>). Déclarer la collection de composants en remplaçant le tag <literal><element></literal>
|
||||
Les collections d'objets dépendants sont supportés (exemple: un tableau de type
|
||||
<literal>Name</literal>). Déclarer la collection de composants en remplaçant le tag <literal><element></literal>
|
||||
par le tag <literal><composite-element></literal>.
|
||||
</para>
|
||||
|
||||
|
@ -154,39 +156,39 @@
|
|||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Remarque: Si vous définissez un <literal>Set</literal> d'élément composite,
|
||||
il est très important d'implémenter la méthode <literal>equals()</literal> et
|
||||
Remarque: Si vous définissez un <literal>Set</literal> d'élément composite,
|
||||
il est très important d'implémenter la méthode <literal>equals()</literal> et
|
||||
<literal>hashCode()</literal> correctement.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Les élements composite peuvent aussi contenir des composants mais pas des collections.
|
||||
Si votre élément composite contient aussi des composants, utilisez l'élément <literal><nested-composite-element></literal>
|
||||
. Une collections de composants qui ccontiennent eux-mêmes des composants est un cas très exotique.
|
||||
A ce stade demandez-vous si une association un-à-plusieurs ne serait pas plus approprié.
|
||||
Essayez de re remodeler votre élément composite comme une entité ( Dans ce cas même si le modèle
|
||||
Java est le même la logique de persitence et de relation sont tout de même différentes)
|
||||
Les élements composite peuvent aussi contenir des composants mais pas des collections.
|
||||
Si votre élément composite contient aussi des composants, utilisez l'élément <literal><nested-composite-element></literal>
|
||||
. Une collections de composants qui ccontiennent eux-mêmes des composants est un cas très exotique.
|
||||
A ce stade demandez-vous si une association un-à-plusieurs ne serait pas plus approprié.
|
||||
Essayez de re remodeler votre élément composite comme une entité ( Dans ce cas même si le modèle
|
||||
Java est le même la logique de persitence et de relation sont tout de même différentes)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Remarque, le mapping d'éléments composites ne supporte pas la nullité des
|
||||
propriétés lorsqu'on utilise un <literal><set></literal>. Hibernate
|
||||
Remarque, le mapping d'éléments composites ne supporte pas la nullité des
|
||||
propriétés lorsqu'on utilise un <literal><set></literal>. Hibernate
|
||||
lorsqu'il supprime un objet utilise chaque colonne pour identifier un objet
|
||||
(on ne peut pas utiliser des clés primaires distinctes dans une table d'éléments composites),
|
||||
ce qui n'est pas possible avec des valeurs nulles. Vous devez donc choisir d'interdire la nullité
|
||||
des propriétés d'un élément composite ou choisir un autre type de collection comme :
|
||||
(on ne peut pas utiliser des clés primaires distinctes dans une table d'éléments composites),
|
||||
ce qui n'est pas possible avec des valeurs nulles. Vous devez donc choisir d'interdire la nullité
|
||||
des propriétés d'un élément composite ou choisir un autre type de collection comme :
|
||||
<literal><list></literal>, <literal><map></literal>,
|
||||
<literal><bag></literal> ou <literal><idbag></literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Un cas particulier d'élément composite est un élément composite qui inclut un élément
|
||||
Un cas particulier d'élément composite est un élément composite qui inclut un élément
|
||||
<literal><many-to-one></literal>. Un mapping comme celui-ci
|
||||
vous permet d'associer les colonnes d'une table d'association plusieurs à plusieurs (many-to-many)
|
||||
à la classse de l'élément composite. L'exemple suivant est une association plusieurs à plusieurs
|
||||
de <literal>Order</literal> à <literal>Item</literal> à
|
||||
vous permet d'associer les colonnes d'une table d'association plusieurs à plusieurs (many-to-many)
|
||||
à la classse de l'élément composite. L'exemple suivant est une association plusieurs à plusieurs
|
||||
de <literal>Order</literal> à <literal>Item</literal> à
|
||||
<literal>purchaseDate</literal>, <literal>price</literal> et
|
||||
<literal>quantity</literal> sont des propriétés de l'association.
|
||||
<literal>quantity</literal> sont des propriétés de l'association.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Order" .... >
|
||||
|
@ -203,12 +205,12 @@
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Bien sûr, il ne peut pas y avoir de référence à l'achat (purchase) depuis l'article (item), pour
|
||||
pouvoir naviguer de façon bidirectionnelle dans l'association. N'oubliez pas que les composants
|
||||
sont de type valeurs et n'autorise pas les références partagées.
|
||||
Bien sûr, il ne peut pas y avoir de référence à l'achat (purchase) depuis l'article (item), pour
|
||||
pouvoir naviguer de façon bidirectionnelle dans l'association. N'oubliez pas que les composants
|
||||
sont de type valeurs et n'autorise pas les références partagées.
|
||||
</para>
|
||||
|
||||
<para>Même les associations ternaires ou quaternaires sont possibles:</para>
|
||||
<para>Même les associations ternaires ou quaternaires sont possibles:</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Order" .... >
|
||||
....
|
||||
|
@ -222,8 +224,8 @@
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Les éléments composites peuvent apparaître dans les requêtes en utilisant
|
||||
la même syntaxe que associations
|
||||
Les éléments composites peuvent apparaître dans les requêtes en utilisant
|
||||
la même syntaxe que associations
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
@ -232,9 +234,9 @@
|
|||
<title>Utiliser les composants comme index de map</title>
|
||||
|
||||
<para>
|
||||
l'élément <literal><composite-map-key></literal>
|
||||
l'élément <literal><composite-map-key></literal>
|
||||
vous permet d'utiliser une classe de composant comme indice de
|
||||
<literal>Map</literal>. Assurez-vous d'avoir surdéfini
|
||||
<literal>Map</literal>. Assurez-vous d'avoir surdéfini
|
||||
<literal>hashCode()</literal> et <literal>equals()</literal> dans la
|
||||
classe du composant.
|
||||
</para>
|
||||
|
@ -244,42 +246,42 @@
|
|||
<title>Utiliser un composant comme identifiant</title>
|
||||
|
||||
<para>
|
||||
Vous pouvez utiliser un composant comme identifiant d'une entité.
|
||||
Mais pour cela la classe du composant doit respecter certaines règles.
|
||||
Vous pouvez utiliser un composant comme identifiant d'une entité.
|
||||
Mais pour cela la classe du composant doit respecter certaines règles.
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
Elle doit implémenter <literal>java.io.Serializable</literal>.
|
||||
Elle doit implémenter <literal>java.io.Serializable</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Elle doit redéfinir <literal>equals()</literal> et
|
||||
<literal>hashCode()</literal>, de façon cohérente avec le
|
||||
fait qu'elle définit une clé composite dans la base de
|
||||
données.
|
||||
Elle doit redéfinir <literal>equals()</literal> et
|
||||
<literal>hashCode()</literal>, de façon cohérente avec le
|
||||
fait qu'elle définit une clé composite dans la base de
|
||||
données.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
<emphasis>
|
||||
Remarque: avec hibernate3, la seconde règle n'est plus absolument
|
||||
necessaire mais faîtes le quand même.</emphasis>
|
||||
Remarque: avec hibernate3, la seconde règle n'est plus absolument
|
||||
necessaire mais faîtes le quand même.</emphasis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Vous ne pouvez pas utiliser de <literal>IdentifierGenerator</literal> pour générer
|
||||
une clé composite, l'application devra définir elle même ses propres identifiants.
|
||||
Vous ne pouvez pas utiliser de <literal>IdentifierGenerator</literal> pour générer
|
||||
une clé composite, l'application devra définir elle même ses propres identifiants.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Utiliser l'élément <literal><composite-id></literal> (en incluant l'élément
|
||||
<literal><key-property></literal>) à la place de l'habituel déclaration
|
||||
Utiliser l'élément <literal><composite-id></literal> (en incluant l'élément
|
||||
<literal><key-property></literal>) à la place de l'habituel déclaration
|
||||
<literal><id></literal>. Par exemple la classe
|
||||
<literal>OrderLine</literal> qui dépend de la clé primaire
|
||||
<literal>OrderLine</literal> qui dépend de la clé primaire
|
||||
(composite) de <literal>Order</literal>.
|
||||
</para>
|
||||
|
||||
|
@ -303,9 +305,9 @@
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Maintenant toutes clés étrangères référençant la table <literal>OrderLine</literal>
|
||||
devra aussi être composite. Vous devez en tenir compte lorsque vous écrivez vos mapping d'association pour les autres classes.
|
||||
Une association à <literal>OrderLine</literal> devrait être mappé de la façon suivante :
|
||||
Maintenant toutes clés étrangères référençant la table <literal>OrderLine</literal>
|
||||
devra aussi être composite. Vous devez en tenir compte lorsque vous écrivez vos mapping d'association pour les autres classes.
|
||||
Une association à <literal>OrderLine</literal> devrait être mappé de la façon suivante :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
|
||||
|
@ -316,13 +318,13 @@
|
|||
</many-to-one>]]></programlisting>
|
||||
|
||||
<para>
|
||||
(Remarque: l'élément <literal><column></literal> est une alternative à l'attribut
|
||||
(Remarque: l'élément <literal><column></literal> est une alternative à l'attribut
|
||||
<literal>column</literal> que l'on utilise partout.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Une association <literal>plusieurs-à-plusieurs</literal> (many-to-many) à <literal>OrderLine</literal>
|
||||
utilisera aussi une clé étrangère composite:
|
||||
Une association <literal>plusieurs-à-plusieurs</literal> (many-to-many) à <literal>OrderLine</literal>
|
||||
utilisera aussi une clé étrangère composite:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="undeliveredOrderLines">
|
||||
|
@ -348,12 +350,12 @@
|
|||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
(L'élément <literal><one-to-many></literal>, comme d'habitude, ne déclare pas de colonne.)
|
||||
(L'élément <literal><one-to-many></literal>, comme d'habitude, ne déclare pas de colonne.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Si <literal>OrderLine</literal> lui-même possède une collection, celle-ci aura aussi
|
||||
une clé composite étrangère.
|
||||
Si <literal>OrderLine</literal> lui-même possède une collection, celle-ci aura aussi
|
||||
une clé composite étrangère.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="OrderLine">
|
||||
|
@ -378,7 +380,7 @@
|
|||
<title>Composant Dynamique</title>
|
||||
|
||||
<para>
|
||||
Vous pouvez même mapper une propriété de type <literal>Map</literal>:
|
||||
Vous pouvez même mapper une propriété de type <literal>Map</literal>:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<dynamic-component name="userAttributes">
|
||||
|
@ -388,12 +390,12 @@
|
|||
</dynamic-component>]]></programlisting>
|
||||
|
||||
<para>
|
||||
La sémantique de l'association à un <literal><dynamic-component></literal>
|
||||
est identique à celle que l'on utilise pour les composants.
|
||||
L'avantage de ce type de mapping est qu'il pemet de déterminer les véritables propriétés
|
||||
du bean au moment su déploiement en éditant simplement le document de mapping.
|
||||
La sémantique de l'association à un <literal><dynamic-component></literal>
|
||||
est identique à celle que l'on utilise pour les composants.
|
||||
L'avantage de ce type de mapping est qu'il pemet de déterminer les véritables propriétés
|
||||
du bean au moment su déploiement en éditant simplement le document de mapping.
|
||||
La manipulation du document de mapping pendant l'execution de l'application est aussi
|
||||
possible en utilisant un parser DOM. Il ya même mieux, vous pouvez accéder (et changer)
|
||||
possible en utilisant un parser DOM. Il ya même mieux, vous pouvez accéder (et changer)
|
||||
le metamodel de configuration d'hibernate en utilisant l'objet <literal>Configuration</literal>
|
||||
</para>
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,11 +1,13 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="events">
|
||||
<title>Les intercepteurs et les événements</title>
|
||||
<title>Les intercepteurs et les événements</title>
|
||||
|
||||
<para>
|
||||
Il est souvent utile pour l'application de réagir à certains événements
|
||||
qui surviennent dans Hibernate. Cela autorise l'implémentation de certaines sortes de
|
||||
fonctionnalités génériques, et d'extensions de fonctionnalités d'Hibernate.
|
||||
Il est souvent utile pour l'application de réagir à certains événements
|
||||
qui surviennent dans Hibernate. Cela autorise l'implémentation de certaines sortes de
|
||||
fonctionnalités génériques, et d'extensions de fonctionnalités d'Hibernate.
|
||||
</para>
|
||||
|
||||
<sect1 id="objectstate-interceptors" revision="2">
|
||||
|
@ -13,18 +15,18 @@
|
|||
|
||||
<para>
|
||||
L'interface <literal>Interceptor</literal> fournit des "callbacks" de la session vers l'application
|
||||
et permettent à l'application de consulter et/ou de manipuler des propriétés
|
||||
d'un objet persistant avant qu'il soit sauvegardé, mis à jour, supprimé ou chargé.
|
||||
Une utilisation possible de cette fonctionnalité est de tracer l'accès à l'information.
|
||||
et permettent à l'application de consulter et/ou de manipuler des propriétés
|
||||
d'un objet persistant avant qu'il soit sauvegardé, mis à jour, supprimé ou chargé.
|
||||
Une utilisation possible de cette fonctionnalité est de tracer l'accès à l'information.
|
||||
Par exemple, l'<literal>Interceptor</literal> suivant positionne
|
||||
<literal>createTimestamp</literal> quand un <literal>Auditable</literal> est créé
|
||||
et met à jour la propriété <literal>lastUpdateTimestamp</literal> quand un
|
||||
<literal>Auditable</literal> est mis à jour.
|
||||
<literal>createTimestamp</literal> quand un <literal>Auditable</literal> est créé
|
||||
et met à jour la propriété <literal>lastUpdateTimestamp</literal> quand un
|
||||
<literal>Auditable</literal> est mis à jour.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Vous pouvez soit implémenter <literal>Interceptor</literal> directement ou (mieux)
|
||||
étendre <literal>EmptyInterceptor</literal>.
|
||||
Vous pouvez soit implémenter <literal>Interceptor</literal> directement ou (mieux)
|
||||
étendre <literal>EmptyInterceptor</literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package org.hibernate.test;
|
||||
|
@ -115,14 +117,14 @@ public class AuditInterceptor extends EmptyInterceptor {
|
|||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
L'intercepteur doit être spécifié quand une session est créée.
|
||||
L'intercepteur doit être spécifié quand une session est créée.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
|
||||
|
||||
<para>
|
||||
Vous pouvez aussi mettre un intercepteur au niveau global, en utilisant l'objet <literal>Configuration</literal>.
|
||||
Dans ce cas, l'intercepteur doit être "threadsafe".
|
||||
Dans ce cas, l'intercepteur doit être "threadsafe".
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
|
||||
|
@ -130,49 +132,49 @@ public class AuditInterceptor extends EmptyInterceptor {
|
|||
</sect1>
|
||||
|
||||
<sect1 id="objectstate-events" revision="3">
|
||||
<title>Système d'événements</title>
|
||||
<title>Système d'événements</title>
|
||||
|
||||
<para>
|
||||
Si vous devez réagir à des événements particuliers dans votre couche de persistance,
|
||||
vous pouvez aussi utiliser l'architecture d'<emphasis>événements</emphasis> d'Hibernate3.
|
||||
Le système d'événements peut être utilisé en supplément ou en remplacement des interceptors.
|
||||
Si vous devez réagir à des événements particuliers dans votre couche de persistance,
|
||||
vous pouvez aussi utiliser l'architecture d'<emphasis>événements</emphasis> d'Hibernate3.
|
||||
Le système d'événements peut être utilisé en supplément ou en remplacement des interceptors.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Essentiellement toutes les méthodes de l'interface <literal>Session</literal> sont corrélées à
|
||||
un événement. Vous avez un <literal>LoadEvent</literal>, un <literal>FlushEvent</literal>, etc
|
||||
Essentiellement toutes les méthodes de l'interface <literal>Session</literal> sont corrélées à
|
||||
un événement. Vous avez un <literal>LoadEvent</literal>, un <literal>FlushEvent</literal>, etc
|
||||
(consultez la DTD du fichier de configuration XML ou le paquet <literal>org.hibernate.event</literal>
|
||||
pour avoir la liste complète des types d'événement définis).
|
||||
Quand une requête est faite à partir d'une de ces méthodes, la
|
||||
<literal>Session</literal> Hibernate génère un événement approprié et le passe
|
||||
au listener configuré pour ce type.
|
||||
Par défaut, ces listeners implémentent le même traitement dans lequel ces méthodes
|
||||
pour avoir la liste complète des types d'événement définis).
|
||||
Quand une requête est faite à partir d'une de ces méthodes, la
|
||||
<literal>Session</literal> Hibernate génère un événement approprié et le passe
|
||||
au listener configuré pour ce type.
|
||||
Par défaut, ces listeners implémentent le même traitement dans lequel ces méthodes
|
||||
aboutissent toujours.
|
||||
Cependant, vous êtes libre d'implémenter une version personnalisée d'une de ces
|
||||
interfaces de listener (c'est-à-dire, le <literal>LoadEvent</literal> est traité par
|
||||
l'implémentation de l'interface <literal>LoadEventListener</literal> déclarée), dans
|
||||
quel cas leur implémentation devrait être responsable du traitement des
|
||||
requêtes <literal>load()</literal> faites par la <literal>Session</literal>.
|
||||
Cependant, vous êtes libre d'implémenter une version personnalisée d'une de ces
|
||||
interfaces de listener (c'est-à-dire, le <literal>LoadEvent</literal> est traité par
|
||||
l'implémentation de l'interface <literal>LoadEventListener</literal> déclarée), dans
|
||||
quel cas leur implémentation devrait être responsable du traitement des
|
||||
requêtes <literal>load()</literal> faites par la <literal>Session</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Les listeners devraient effectivement être considérés comme des singletons ; dans le sens
|
||||
où ils sont partagés entre des requêtes, et donc ne devraient pas sauvegarder des états
|
||||
Les listeners devraient effectivement être considérés comme des singletons ; dans le sens
|
||||
où ils sont partagés entre des requêtes, et donc ne devraient pas sauvegarder des états
|
||||
de variables d'instance.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Un listener personnalisé devrait implémenter l'interface appropriée pour l'événement
|
||||
qu'il veut traiter et/ou étendre une des classes de base (ou même l'événement prêt à
|
||||
l'emploi utilisé par Hibernate comme ceux déclarés non-finaux à cette intention). Les
|
||||
listeners personnalisés peuvent être soit inscrits par programmation à travers l'objet
|
||||
<literal>Configuration</literal>, ou spécifiés la configuration XML d'Hibernate
|
||||
(la configuration déclarative à travers le fichier de propriétés n'est pas supportée).
|
||||
Voici un exemple de listener personnalisé pour l'événement de chargement :
|
||||
Un listener personnalisé devrait implémenter l'interface appropriée pour l'événement
|
||||
qu'il veut traiter et/ou étendre une des classes de base (ou même l'événement prêt à
|
||||
l'emploi utilisé par Hibernate comme ceux déclarés non-finaux à cette intention). Les
|
||||
listeners personnalisés peuvent être soit inscrits par programmation à travers l'objet
|
||||
<literal>Configuration</literal>, ou spécifiés la configuration XML d'Hibernate
|
||||
(la configuration déclarative à travers le fichier de propriétés n'est pas supportée).
|
||||
Voici un exemple de listener personnalisé pour l'événement de chargement :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public class MyLoadListener implements LoadEventListener {
|
||||
// C'est une simple méthode définie par l'interface LoadEventListener
|
||||
// C'est une simple méthode définie par l'interface LoadEventListener
|
||||
public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
|
||||
throws HibernateException {
|
||||
if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
|
||||
|
@ -182,8 +184,8 @@ public class AuditInterceptor extends EmptyInterceptor {
|
|||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
Vous avez aussi besoin d'une entrée de configuration disant à Hibernate d'utiliser
|
||||
ce listener en plus du listener par défaut :
|
||||
Vous avez aussi besoin d'une entrée de configuration disant à Hibernate d'utiliser
|
||||
ce listener en plus du listener par défaut :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-configuration>
|
||||
|
@ -205,33 +207,33 @@ LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener
|
|||
cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
|
||||
|
||||
<para>
|
||||
Les listeners inscrits déclarativement ne peuvent pas partager d'instances. Si le même
|
||||
nom de classe est utilisée dans plusieurs éléments <literal><listener/></literal>,
|
||||
chaque référence sera une instance distincte de cette classe. Si vous avez besoin de la
|
||||
faculté de partager des instances de listener entre plusieurs types de listener, vous devez
|
||||
Les listeners inscrits déclarativement ne peuvent pas partager d'instances. Si le même
|
||||
nom de classe est utilisée dans plusieurs éléments <literal><listener/></literal>,
|
||||
chaque référence sera une instance distincte de cette classe. Si vous avez besoin de la
|
||||
faculté de partager des instances de listener entre plusieurs types de listener, vous devez
|
||||
utiliser l'approche d'inscription par programmation.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Pourquoi implémenter une interface et définir le type spécifique durant la configuration ?
|
||||
Une implémentation de listener pourrait implémenter plusieurs interfaces de listener
|
||||
d'événements. Avoir en plus le type défini durant l'inscription rend plus facile
|
||||
l'activation ou la désactivation pendant la configuration.
|
||||
Pourquoi implémenter une interface et définir le type spécifique durant la configuration ?
|
||||
Une implémentation de listener pourrait implémenter plusieurs interfaces de listener
|
||||
d'événements. Avoir en plus le type défini durant l'inscription rend plus facile
|
||||
l'activation ou la désactivation pendant la configuration.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="objectstate-decl-security" revision="2">
|
||||
<title>Sécurité déclarative d'Hibernate</title>
|
||||
<title>Sécurité déclarative d'Hibernate</title>
|
||||
<para>
|
||||
Généralement, la sécurité déclarative dans les applications Hibernate est gérée dans la
|
||||
couche de session. Maintenant, Hibernate3 permet à certaines actions d'être approuvées
|
||||
via JACC, et autorisées via JAAS. Cette fonctionnalité optionnelle est construite
|
||||
au dessus de l'architecture d'événements.
|
||||
Généralement, la sécurité déclarative dans les applications Hibernate est gérée dans la
|
||||
couche de session. Maintenant, Hibernate3 permet à certaines actions d'être approuvées
|
||||
via JACC, et autorisées via JAAS. Cette fonctionnalité optionnelle est construite
|
||||
au dessus de l'architecture d'événements.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
D'abord, vous devez configurer les listeners d'événements appropriés pour permettre
|
||||
D'abord, vous devez configurer les listeners d'événements appropriés pour permettre
|
||||
l'utilisation d'autorisations JAAS.
|
||||
</para>
|
||||
|
||||
|
@ -243,18 +245,18 @@ cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
|
|||
<para>
|
||||
Notez que <literal><listener type="..." class="..."/></literal> est juste un raccourci
|
||||
pour <literal><event type="..."><listener class="..."/></event></literal>
|
||||
quand il y a exactement un listener pour un type d'événement particulier.
|
||||
quand il y a exactement un listener pour un type d'événement particulier.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Ensuite, toujours dans <literal>hibernate.cfg.xml</literal>, lier les permissions aux rôles :
|
||||
Ensuite, toujours dans <literal>hibernate.cfg.xml</literal>, lier les permissions aux rôles :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
|
||||
<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Les noms de rôle sont les rôles compris par votre fournisseur JAAC.
|
||||
Les noms de rôle sont les rôles compris par votre fournisseur JAAC.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
~ Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
|
||||
~
|
||||
~ This copyrighted material is made available to anyone wishing to use, modify,
|
||||
~ copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
~ Lesser General Public License, v. 2.1. This program is distributed in the
|
||||
~ hope that it will be useful, but WITHOUT A WARRANTY; without even the implied
|
||||
~ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
~ Lesser General Public License for more details. You should have received a
|
||||
~ copy of the GNU Lesser General Public License, v.2.1 along with this
|
||||
~ distribution; if not, write to the Free Software Foundation, Inc.,
|
||||
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
~
|
||||
~ Red Hat Author(s): Steve Ebersole
|
||||
-->
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="example-mappings">
|
||||
<title>Exemple : quelques mappings</title>
|
||||
|
||||
|
@ -22,14 +9,14 @@
|
|||
</para>
|
||||
|
||||
<sect1 id="example-mappings-emp">
|
||||
<title>Employeur/Employé (Employer/Employee)</title>
|
||||
<title>Employeur/Employé (Employer/Employee)</title>
|
||||
|
||||
<para>
|
||||
Le modèle suivant de relation entre <literal>Employer</literal> et
|
||||
<literal>Employee</literal> utilise une vraie classe entité (<literal>Employment</literal>)
|
||||
pour représenter l'association. On a fait cela parce qu'il peut y avoir plus d'une période
|
||||
d'emploi pour les deux mêmes parties. Des composants sont utilisés pour modéliser les
|
||||
valeurs monétaires et les noms des employés.
|
||||
Le modèle suivant de relation entre <literal>Employer</literal> et
|
||||
<literal>Employee</literal> utilise une vraie classe entité (<literal>Employment</literal>)
|
||||
pour représenter l'association. On a fait cela parce qu'il peut y avoir plus d'une période
|
||||
d'emploi pour les deux mêmes parties. Des composants sont utilisés pour modéliser les
|
||||
valeurs monétaires et les noms des employés.
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
|
@ -95,7 +82,7 @@
|
|||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Et voici le schéma des tables générées par <literal>SchemaExport</literal>.
|
||||
Et voici le schéma des tables générées par <literal>SchemaExport</literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[create table employers (
|
||||
|
@ -138,12 +125,12 @@ create sequence employer_id_seq]]></programlisting>
|
|||
<title>Auteur/Travail (Author/Work)</title>
|
||||
|
||||
<para>
|
||||
Soit le modèle de la relation entre <literal>Work</literal>, <literal>Author</literal>
|
||||
et <literal>Person</literal>. Nous représentons la relation entre <literal>Work</literal>
|
||||
Soit le modèle de la relation entre <literal>Work</literal>, <literal>Author</literal>
|
||||
et <literal>Person</literal>. Nous représentons la relation entre <literal>Work</literal>
|
||||
et <literal>Author</literal> comme une association plusieurs-vers-plusieurs. Nous avons choisi de
|
||||
représenter la relation entre <literal>Author</literal> et <literal>Person</literal>
|
||||
comme une association un-vers-un. Une autre possibilité aurait été que
|
||||
<literal>Author</literal> hérite de <literal>Person</literal>.
|
||||
représenter la relation entre <literal>Author</literal> et <literal>Person</literal>
|
||||
comme une association un-vers-un. Une autre possibilité aurait été que
|
||||
<literal>Author</literal> hérite de <literal>Person</literal>.
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
|
@ -156,7 +143,7 @@ create sequence employer_id_seq]]></programlisting>
|
|||
</mediaobject>
|
||||
|
||||
<para>
|
||||
Le mapping suivant représente exactement ces relations :
|
||||
Le mapping suivant représente exactement ces relations :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
@ -214,9 +201,9 @@ create sequence employer_id_seq]]></programlisting>
|
|||
<para>
|
||||
Il y a quatre tables dans ce mapping. <literal>works</literal>,
|
||||
<literal>authors</literal> et <literal>persons</literal> qui contiennent
|
||||
respectivement les données de work, author et person.
|
||||
respectivement les données de work, author et person.
|
||||
<literal>author_work</literal> est une table d'association qui lie authors
|
||||
à works. Voici le schéma de tables, généré par <literal>SchemaExport</literal>.
|
||||
à works. Voici le schéma de tables, généré par <literal>SchemaExport</literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[create table works (
|
||||
|
@ -260,14 +247,14 @@ alter table author_work
|
|||
<title>Client/Commande/Produit (Customer/Order/Product)</title>
|
||||
|
||||
<para>
|
||||
Imaginons maintenant le modèle de relation entre <literal>Customer</literal>,
|
||||
Imaginons maintenant le modèle de relation entre <literal>Customer</literal>,
|
||||
<literal>Order</literal>, <literal>LineItem</literal> et <literal>Product</literal>.
|
||||
Il y a une association un-vers-plusieurs entre <literal>Customer</literal> et
|
||||
<literal>Order</literal>, mais comment devrions nous représenter <literal>Order</literal> /
|
||||
<literal>Order</literal>, mais comment devrions nous représenter <literal>Order</literal> /
|
||||
<literal>LineItem</literal> / <literal>Product</literal>? J'ai choisi de mapper
|
||||
<literal>LineItem</literal> comme une classe d'association représentant l'association
|
||||
<literal>LineItem</literal> comme une classe d'association représentant l'association
|
||||
plusieurs-vers-plusieurs entre <literal>Order</literal> et <literal>Product</literal>. Dans
|
||||
Hibernate, on appelle cela un élément composite.
|
||||
Hibernate, on appelle cela un élément composite.
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
|
@ -323,8 +310,8 @@ alter table author_work
|
|||
|
||||
<para>
|
||||
<literal>customers</literal>, <literal>orders</literal>, <literal>line_items</literal> et
|
||||
<literal>products</literal> contiennent les données de customer, order, order line item et product.
|
||||
<literal>line_items</literal> est aussi la table d'association liant orders à products.
|
||||
<literal>products</literal> contiennent les données de customer, order, order line item et product.
|
||||
<literal>line_items</literal> est aussi la table d'association liant orders à products.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[create table customers (
|
||||
|
@ -404,7 +391,7 @@ alter table line_items
|
|||
</sect2>
|
||||
|
||||
<sect2 id="example-mappings-composite-key">
|
||||
<title>Exemple de clef composée</title>
|
||||
<title>Exemple de clef composée</title>
|
||||
<programlisting><![CDATA[<class name="Customer">
|
||||
|
||||
<id name="customerId"
|
||||
|
@ -521,7 +508,7 @@ alter table line_items
|
|||
</sect2>
|
||||
|
||||
<sect2 id="example-mappings-composite-key-manytomany">
|
||||
<title>Many-to-many avec une clef composée partagée</title>
|
||||
<title>Many-to-many avec une clef composée partagée</title>
|
||||
<programlisting><![CDATA[<class name="User" table="`User`">
|
||||
<composite-id>
|
||||
<key-property name="name"/>
|
||||
|
@ -560,7 +547,7 @@ alter table line_items
|
|||
</sect2>
|
||||
|
||||
<sect2 id="example-mappings-content-discrimination">
|
||||
<title>Contenu basé sur une discrimination</title>
|
||||
<title>Contenu basé sur une discrimination</title>
|
||||
<programlisting><![CDATA[<class name="Person"
|
||||
discriminator-value="P">
|
||||
|
||||
|
@ -614,7 +601,7 @@ alter table line_items
|
|||
</sect2>
|
||||
|
||||
<sect2 id="example-mappings-association-alternatekeys" revision="2">
|
||||
<title>Associations sur des clefs alternées</title>
|
||||
<title>Associations sur des clefs alternées</title>
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
|
||||
<id name="id">
|
||||
|
|
|
@ -1,61 +1,63 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="example-parentchild">
|
||||
<title>Exemple : Père/Fils</title>
|
||||
<title>Exemple : Père/Fils</title>
|
||||
|
||||
<para>
|
||||
L'une des premières choses que les nouveaux utilisateurs essaient de faire avec Hibernate est de modéliser
|
||||
une relation père/fils. Il y a deux approches différentes pour cela. Pour un certain nombre de raisons, la méthode la
|
||||
plus courante, en particulier pour les nouveaux utilisateurs, est de modéliser les deux relations <literal>Père</literal>
|
||||
et <literal>Fils</literal> comme des classes entités liées par une association <literal><one-to-many></literal> du
|
||||
<literal>Père</literal> vers le <literal>Fils</literal> (l'autre approche est de déclarer le <literal>Fils</literal>
|
||||
comme un <literal><composite-element></literal>). Il est évident que le sens de l'association un vers plusieurs
|
||||
(dans Hibernate) est bien moins proche du sens habituel d'une relation père/fils que ne l'est celui d'un
|
||||
élément cmposite. Nous allons vous expliquer comment utiliser une association <emphasis>un vers plusieurs bidirectionnelle
|
||||
avec cascade</emphasis> afin de modéliser efficacement et élégamment une relation père/fils, ce n'est vraiment
|
||||
L'une des premières choses que les nouveaux utilisateurs essaient de faire avec Hibernate est de modéliser
|
||||
une relation père/fils. Il y a deux approches différentes pour cela. Pour un certain nombre de raisons, la méthode la
|
||||
plus courante, en particulier pour les nouveaux utilisateurs, est de modéliser les deux relations <literal>Père</literal>
|
||||
et <literal>Fils</literal> comme des classes entités liées par une association <literal><one-to-many></literal> du
|
||||
<literal>Père</literal> vers le <literal>Fils</literal> (l'autre approche est de déclarer le <literal>Fils</literal>
|
||||
comme un <literal><composite-element></literal>). Il est évident que le sens de l'association un vers plusieurs
|
||||
(dans Hibernate) est bien moins proche du sens habituel d'une relation père/fils que ne l'est celui d'un
|
||||
élément cmposite. Nous allons vous expliquer comment utiliser une association <emphasis>un vers plusieurs bidirectionnelle
|
||||
avec cascade</emphasis> afin de modéliser efficacement et élégamment une relation père/fils, ce n'est vraiment
|
||||
pas difficile !
|
||||
</para>
|
||||
|
||||
<sect1 id="example-parentchild-collections">
|
||||
<title>Une note à propos des collections</title>
|
||||
<title>Une note à propos des collections</title>
|
||||
|
||||
<para>
|
||||
Les collections Hibernate sont considérées comme étant une partie logique
|
||||
de l'entité dans laquelle elles sont contenues ; jamais des entités qu'elle
|
||||
contient. C'est une distinction crutiale ! Les conséquences sont les suivantes :
|
||||
Les collections Hibernate sont considérées comme étant une partie logique
|
||||
de l'entité dans laquelle elles sont contenues ; jamais des entités qu'elle
|
||||
contient. C'est une distinction crutiale ! Les conséquences sont les suivantes :
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Quand nous ajoutons / retirons un objet d'une collection, le numéro de version du
|
||||
propriétaire de la collection est incrémenté.
|
||||
Quand nous ajoutons / retirons un objet d'une collection, le numéro de version du
|
||||
propriétaire de la collection est incrémenté.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Si un objet qui a été enlevé d'une collection est une instance de type valeur (ex :
|
||||
élément composite), cet objet cessera d'être persistant et son état sera complètement effacé
|
||||
de la base de données. Par ailleurs, ajouter une instance de type valeur dans une collection
|
||||
aura pour conséquence que son état sera immédiatement persistant.
|
||||
Si un objet qui a été enlevé d'une collection est une instance de type valeur (ex :
|
||||
élément composite), cet objet cessera d'être persistant et son état sera complètement effacé
|
||||
de la base de données. Par ailleurs, ajouter une instance de type valeur dans une collection
|
||||
aura pour conséquence que son état sera immédiatement persistant.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Si une entité est enlevée d'une collection (association un-vers-plusieurs
|
||||
ou plusieurs-vers-plusieurs), par défaut, elle ne sera pas effacée. Ce comportement
|
||||
est complètement logique - une modification de l'un des états internes d'une entité
|
||||
ne doit pas causer la disparition de l'entité associée !
|
||||
De même, l'ajout d'une entité dans une collection n'engendre pas,
|
||||
par défaut, la persistance de cette entité.
|
||||
Si une entité est enlevée d'une collection (association un-vers-plusieurs
|
||||
ou plusieurs-vers-plusieurs), par défaut, elle ne sera pas effacée. Ce comportement
|
||||
est complètement logique - une modification de l'un des états internes d'une entité
|
||||
ne doit pas causer la disparition de l'entité associée !
|
||||
De même, l'ajout d'une entité dans une collection n'engendre pas,
|
||||
par défaut, la persistance de cette entité.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Le comportement par défaut est donc que l'ajout d'une entité dans une collection créé
|
||||
simplement le lien entre les deux entités, et qu'effacer une entité supprime ce lien.
|
||||
C'est le comportement le plus approprié dans la plupart des cas. Ce comportement n'est
|
||||
cependant pas approprié lorsque la vie du fils est liée au cycle de vie du père.
|
||||
Le comportement par défaut est donc que l'ajout d'une entité dans une collection créé
|
||||
simplement le lien entre les deux entités, et qu'effacer une entité supprime ce lien.
|
||||
C'est le comportement le plus approprié dans la plupart des cas. Ce comportement n'est
|
||||
cependant pas approprié lorsque la vie du fils est liée au cycle de vie du père.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
@ -84,16 +86,16 @@ session.save(c);
|
|||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Hibernate exécuterait deux ordres SQL:
|
||||
Hibernate exécuterait deux ordres SQL:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>un <literal>INSERT</literal> pour créer l'enregistrement pour <literal>c</literal></para>
|
||||
<para>un <literal>INSERT</literal> pour créer l'enregistrement pour <literal>c</literal></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
un <literal>UPDATE</literal> pour créer le lien de <literal>p</literal> vers
|
||||
un <literal>UPDATE</literal> pour créer le lien de <literal>p</literal> vers
|
||||
<literal>c</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
|
@ -101,8 +103,8 @@ session.flush();]]></programlisting>
|
|||
|
||||
<para>
|
||||
Ceci est non seuleument inefficace, mais viole aussi toute contrainte <literal>NOT NULL</literal> sur
|
||||
la colonne <literal>parent_id</literal>. Nous pouvons réparer la contrainte de nullité
|
||||
en spécifiant <literal>not-null="true"</literal> dans le mapping de la collection :
|
||||
la colonne <literal>parent_id</literal>. Nous pouvons réparer la contrainte de nullité
|
||||
en spécifiant <literal>not-null="true"</literal> dans le mapping de la collection :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="children">
|
||||
|
@ -111,25 +113,25 @@ session.flush();]]></programlisting>
|
|||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Cependant ce n'est pas la solution recommandée.
|
||||
Cependant ce n'est pas la solution recommandée.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
La cause sous jacente à ce comportement est que le lien (la clé étrangère <literal>parent_id</literal>) de
|
||||
<literal>p</literal> vers <literal>c</literal> n'est pas considérée comme faisant partie de l'état
|
||||
de l'objet <literal>Child</literal> et n'est donc pas créé par l'<literal>INSERT</literal>.
|
||||
La cause sous jacente à ce comportement est que le lien (la clé étrangère <literal>parent_id</literal>) de
|
||||
<literal>p</literal> vers <literal>c</literal> n'est pas considérée comme faisant partie de l'état
|
||||
de l'objet <literal>Child</literal> et n'est donc pas créé par l'<literal>INSERT</literal>.
|
||||
La solution est donc que ce lien fasse partie du mapping de <literal>Child</literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<many-to-one name="parent" column="parent_id" not-null="true"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
(Nous avons aussi besoin d'ajouter la propriété <literal>parent</literal> dans la classe <literal>Child</literal>).
|
||||
(Nous avons aussi besoin d'ajouter la propriété <literal>parent</literal> dans la classe <literal>Child</literal>).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Maintenant que l'état du lien est géré par l'entité <literal>Child</literal>, nous spécifions à la
|
||||
collection de ne pas mettre à jour le lien. Nous utilisons l'attribut <literal>inverse</literal>.
|
||||
Maintenant que l'état du lien est géré par l'entité <literal>Child</literal>, nous spécifions à la
|
||||
collection de ne pas mettre à jour le lien. Nous utilisons l'attribut <literal>inverse</literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="children" inverse="true">
|
||||
|
@ -138,7 +140,7 @@ session.flush();]]></programlisting>
|
|||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Le code suivant serait utilisé pour ajouter un nouveau <literal>Child</literal>
|
||||
Le code suivant serait utilisé pour ajouter un nouveau <literal>Child</literal>
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
|
||||
|
@ -149,11 +151,11 @@ session.save(c);
|
|||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Maintenant, seul un <literal>INSERT</literal> SQL est nécessaire !
|
||||
Maintenant, seul un <literal>INSERT</literal> SQL est nécessaire !
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Pour alléger encore un peu les choses, nous devrions créer une méthode <literal>addChild()</literal>
|
||||
Pour alléger encore un peu les choses, nous devrions créer une méthode <literal>addChild()</literal>
|
||||
dans <literal>Parent</literal>.
|
||||
</para>
|
||||
|
||||
|
@ -188,7 +190,7 @@ session.flush();]]></programlisting>
|
|||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Simplifie le code précédent en
|
||||
Simplifie le code précédent en
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
|
||||
|
@ -197,9 +199,9 @@ p.addChild(c);
|
|||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
De la même manière, nous n'avons pas à itérer sur les fils lorsque nous sauvons
|
||||
De la même manière, nous n'avons pas à itérer sur les fils lorsque nous sauvons
|
||||
ou effacons un <literal>Parent</literal>. Le code suivant efface <literal>p</literal>
|
||||
et tous ses fils de la base de données.
|
||||
et tous ses fils de la base de données.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
|
||||
|
@ -217,7 +219,7 @@ c.setParent(null);
|
|||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
n'effacera pas <literal>c</literal> de la base de données, il enlèvera seulement
|
||||
n'effacera pas <literal>c</literal> de la base de données, il enlèvera seulement
|
||||
le lien vers <literal>p</literal> (et causera une violation de contrainte
|
||||
<literal>NOT NULL</literal>, dans ce cas).
|
||||
Vous devez explicitement utiliser <literal>delete()</literal> sur <literal>Child</literal>.
|
||||
|
@ -230,8 +232,8 @@ session.delete(c);
|
|||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Dans notre cas, un <literal>Child</literal> ne peut pas vraiment exister sans son père. Si nous
|
||||
effacons un <literal>Child</literal> de la collection, nous voulons vraiment qu'il soit effacé.
|
||||
Dans notre cas, un <literal>Child</literal> ne peut pas vraiment exister sans son père. Si nous
|
||||
effacons un <literal>Child</literal> de la collection, nous voulons vraiment qu'il soit effacé.
|
||||
Pour cela, nous devons utiliser <literal>cascade="all-delete-orphan"</literal>.
|
||||
</para>
|
||||
|
||||
|
@ -241,9 +243,9 @@ session.flush();]]></programlisting>
|
|||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
A noter : même si le mapping de la collection spécifie <literal>inverse="true"</literal>, les cascades
|
||||
sont toujours assurées par l'itération sur les éléments de la collection. Donc, si vous avez besoin
|
||||
qu'un objet soit enregistré, effacé ou mis à jour par cascade, vous devez l'ajouter dans la colleciton.
|
||||
A noter : même si le mapping de la collection spécifie <literal>inverse="true"</literal>, les cascades
|
||||
sont toujours assurées par l'itération sur les éléments de la collection. Donc, si vous avez besoin
|
||||
qu'un objet soit enregistré, effacé ou mis à jour par cascade, vous devez l'ajouter dans la colleciton.
|
||||
Il ne suffit pas d'appeler explicitement <literal>setParent()</literal>.
|
||||
</para>
|
||||
|
||||
|
@ -253,26 +255,26 @@ session.flush();]]></programlisting>
|
|||
<title>Cascades et <literal>unsaved-value</literal></title>
|
||||
|
||||
<para>
|
||||
Supposons que nous ayons chargé un <literal>Parent</literal> dans une <literal>Session</literal>,
|
||||
que nous l'ayons ensuite modifié et que voulions persiter ces modifications dans une nouvelle session
|
||||
Supposons que nous ayons chargé un <literal>Parent</literal> dans une <literal>Session</literal>,
|
||||
que nous l'ayons ensuite modifié et que voulions persiter ces modifications dans une nouvelle session
|
||||
en appelant <literal>update()</literal>.
|
||||
Le <literal>Parent</literal> contiendra une collection de fils et, puisque la cascade est activée,
|
||||
Hibernate a besoin de savoir quels fils viennent d'être instanciés et quels fils proviennent de la base
|
||||
de données. Supposons aussi que <literal>Parent</literal> et <literal>Child</literal> ont tous deux
|
||||
Le <literal>Parent</literal> contiendra une collection de fils et, puisque la cascade est activée,
|
||||
Hibernate a besoin de savoir quels fils viennent d'être instanciés et quels fils proviennent de la base
|
||||
de données. Supposons aussi que <literal>Parent</literal> et <literal>Child</literal> ont tous deux
|
||||
des identifiants du type <literal>Long</literal>.
|
||||
Hibernate utilisera la propriété de l'identifiant et la propriété de la version/horodatage pour déterminer quels fils sont nouveaux
|
||||
(vous pouvez aussi utiliser la propriété version ou timestamp, voir
|
||||
Hibernate utilisera la propriété de l'identifiant et la propriété de la version/horodatage pour déterminer quels fils sont nouveaux
|
||||
(vous pouvez aussi utiliser la propriété version ou timestamp, voir
|
||||
<xref linkend="manipulatingdata-updating-detached"/>).
|
||||
<emphasis>Dans Hibernate3, il n'est plus nécessaire de spécifier
|
||||
<emphasis>Dans Hibernate3, il n'est plus nécessaire de spécifier
|
||||
une <literal>unsaved-value</literal> explicitement.</emphasis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Le code suivant mettra à jour <literal>parent</literal> et <literal>child</literal>
|
||||
et insérera <literal>newChild</literal>.
|
||||
Le code suivant mettra à jour <literal>parent</literal> et <literal>child</literal>
|
||||
et insérera <literal>newChild</literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[//parent et child ont été chargés dans une session précédente
|
||||
<programlisting><![CDATA[//parent et child ont été chargés dans une session précédente
|
||||
parent.addChild(child);
|
||||
Child newChild = new Child();
|
||||
parent.addChild(newChild);
|
||||
|
@ -280,12 +282,12 @@ session.update(parent);
|
|||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Ceci est très bien pour des identifiants générés, mais qu'en est-il des identifiants assignés et des
|
||||
identifiants composés ? C'est plus difficile,
|
||||
puisqu'Hibernate ne peut pas utiliser la propriété de l'identifiant pour distinguer un objet
|
||||
nouvellement instancié (avec un identifiant assigné par l'utilisateur) d'un objet chargé dans une session précédente.
|
||||
Dans ce cas, Hibernate utilisera soit la propriété de version ou d'horodatage, soit effectuera vraiment une requête au cache
|
||||
de second niveau, soit, dans le pire des cas, à la base de données, pour voir si la ligne existe.
|
||||
Ceci est très bien pour des identifiants générés, mais qu'en est-il des identifiants assignés et des
|
||||
identifiants composés ? C'est plus difficile,
|
||||
puisqu'Hibernate ne peut pas utiliser la propriété de l'identifiant pour distinguer un objet
|
||||
nouvellement instancié (avec un identifiant assigné par l'utilisateur) d'un objet chargé dans une session précédente.
|
||||
Dans ce cas, Hibernate utilisera soit la propriété de version ou d'horodatage, soit effectuera vraiment une requête au cache
|
||||
de second niveau, soit, dans le pire des cas, à la base de données, pour voir si la ligne existe.
|
||||
</para>
|
||||
|
||||
<!-- undocumenting
|
||||
|
@ -354,17 +356,17 @@ public boolean onSave(Object entity,
|
|||
<title>Conclusion</title>
|
||||
|
||||
<para>
|
||||
Il y a quelques principes à maîtriser dans ce chapitre et tout cela peut paraître déroutant la première fois.
|
||||
Il y a quelques principes à maîtriser dans ce chapitre et tout cela peut paraître déroutant la première fois.
|
||||
Cependant, dans la pratique, tout fonctionne parfaitement. La plupart des applications Hibernate utilisent
|
||||
le pattern père / fils.
|
||||
le pattern père / fils.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Nous avons évoqué une alternative dans le premier paragraphe. Aucun des points traités précédemment n'existe
|
||||
dans le cas d'un mapping <literal><composite-element></literal> qui possède exactement la sémantique
|
||||
d'une relation père / fils. Malheureusement, il y a deux grandes limitations pour les classes éléments
|
||||
composites : les éléments composites ne peuvent contenir de collections, et ils ne peuvent être les fils
|
||||
d'entités autres que l'unique parent.
|
||||
Nous avons évoqué une alternative dans le premier paragraphe. Aucun des points traités précédemment n'existe
|
||||
dans le cas d'un mapping <literal><composite-element></literal> qui possède exactement la sémantique
|
||||
d'une relation père / fils. Malheureusement, il y a deux grandes limitations pour les classes éléments
|
||||
composites : les éléments composites ne peuvent contenir de collections, et ils ne peuvent être les fils
|
||||
d'entités autres que l'unique parent.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="example-weblog">
|
||||
<title>Exemple : application Weblog</title>
|
||||
|
||||
|
@ -6,9 +8,9 @@
|
|||
<title>Classes persistantes</title>
|
||||
|
||||
<para>
|
||||
Les classes persistantes representent un weblog, et un article posté
|
||||
dans un weblog. Il seront modélisés comme une relation père/fils
|
||||
standard, mais nous allons utiliser un "bag" trié au lieu d'un set.
|
||||
Les classes persistantes representent un weblog, et un article posté
|
||||
dans un weblog. Il seront modélisés comme une relation père/fils
|
||||
standard, mais nous allons utiliser un "bag" trié au lieu d'un set.
|
||||
|
||||
</para>
|
||||
|
||||
|
@ -91,7 +93,7 @@ public class BlogItem {
|
|||
<title>Mappings Hibernate</title>
|
||||
|
||||
<para>
|
||||
Le mapping XML doit maintenant être relativement simple à vos yeux.
|
||||
Le mapping XML doit maintenant être relativement simple à vos yeux.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<?xml version="1.0"?>
|
||||
|
|
|
@ -1,32 +1,34 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="filters">
|
||||
<title>Filtrer les données</title>
|
||||
<title>Filtrer les données</title>
|
||||
|
||||
<para>
|
||||
Hibernate3 fournit une nouvelle approche innovatrice pour gérer des données
|
||||
avec des règles de "visibilité". Un <emphasis>filtre Hibernate</emphasis> est un filtre
|
||||
global, nommé, paramétré qui peut être activé ou désactivé pour une session Hibernate
|
||||
particulière.
|
||||
Hibernate3 fournit une nouvelle approche innovatrice pour gérer des données
|
||||
avec des règles de "visibilité". Un <emphasis>filtre Hibernate</emphasis> est un filtre
|
||||
global, nommé, paramétré qui peut être activé ou désactivé pour une session Hibernate
|
||||
particulière.
|
||||
</para>
|
||||
|
||||
<sect1 id="objectstate-filters">
|
||||
<title>Filtres Hibernate</title>
|
||||
|
||||
<para>
|
||||
Hibernate3 ajoute la capacité de prédéfinir des critères de filtre et d'attacher ces
|
||||
filtres à une classe ou à une collection. Un critère de filtre est la faculté de définir
|
||||
une clause de restriction très similaire à l'attribut "where" existant disponible sur
|
||||
une classe et divers éléments d'une collection. Mis à part que ces conditions de filtre
|
||||
peuvent être paramétrées. L'application peut alors prendre la décision à l'exécution
|
||||
si des filtres donnés devraient être activés et quels devraient être leurs paramètres.
|
||||
Des filtres peuvent être utilisés comme des vues de base de données, mais paramétrées
|
||||
Hibernate3 ajoute la capacité de prédéfinir des critères de filtre et d'attacher ces
|
||||
filtres à une classe ou à une collection. Un critère de filtre est la faculté de définir
|
||||
une clause de restriction très similaire à l'attribut "where" existant disponible sur
|
||||
une classe et divers éléments d'une collection. Mis à part que ces conditions de filtre
|
||||
peuvent être paramétrées. L'application peut alors prendre la décision à l'exécution
|
||||
si des filtres donnés devraient être activés et quels devraient être leurs paramètres.
|
||||
Des filtres peuvent être utilisés comme des vues de base de données, mais paramétrées
|
||||
dans l'application.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Afin d'utiliser des filtres, ils doivent d'abord être définis, puis attachés aux éléments
|
||||
de mapping appropriés. Pour définir un filtre, utilisez l'élément <literal><filter-def/></literal>
|
||||
dans un élément <literal><hibernate-mapping/></literal> :
|
||||
Afin d'utiliser des filtres, ils doivent d'abord être définis, puis attachés aux éléments
|
||||
de mapping appropriés. Pour définir un filtre, utilisez l'élément <literal><filter-def/></literal>
|
||||
dans un élément <literal><hibernate-mapping/></literal> :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<filter-def name="myFilter">
|
||||
|
@ -34,7 +36,7 @@
|
|||
</filter-def>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Puis, ce filtre peut être attaché à une classe :
|
||||
Puis, ce filtre peut être attaché à une classe :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="myClass" ...>
|
||||
|
@ -43,7 +45,7 @@
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
ou à une collection :
|
||||
ou à une collection :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set ...>
|
||||
|
@ -51,27 +53,27 @@
|
|||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
ou même aux deux (ou à plusieurs de chaque) en même temps.
|
||||
ou même aux deux (ou à plusieurs de chaque) en même temps.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Les méthodes sur <literal>Session</literal> sont : <literal>enableFilter(String filterName)</literal>,
|
||||
Les méthodes sur <literal>Session</literal> sont : <literal>enableFilter(String filterName)</literal>,
|
||||
<literal>getEnabledFilter(String filterName)</literal>, et <literal>disableFilter(String filterName)</literal>.
|
||||
Par défaut, les filtres <emphasis>ne sont pas</emphasis> activés pour une session donnée ;
|
||||
ils doivent être explicitement activés en appelant la méthode
|
||||
Par défaut, les filtres <emphasis>ne sont pas</emphasis> activés pour une session donnée ;
|
||||
ils doivent être explicitement activés en appelant la méthode
|
||||
<literal>Session.enabledFilter()</literal>, laquelle retourne une instance de l'interface
|
||||
<literal>Filter</literal>. Utiliser le simple filtre défini au-dessus ressemblerait à :
|
||||
<literal>Filter</literal>. Utiliser le simple filtre défini au-dessus ressemblerait à :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");]]></programlisting>
|
||||
|
||||
<para>
|
||||
Notez que des méthodes sur l'interface org.hibernate.Filter autorisent le chaînage de beaucoup
|
||||
de méthodes communes d'Hibernate.
|
||||
Notez que des méthodes sur l'interface org.hibernate.Filter autorisent le chaînage de beaucoup
|
||||
de méthodes communes d'Hibernate.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Un exemple complet, utilisant des données temporelles avec une structure de date
|
||||
Un exemple complet, utilisant des données temporelles avec une structure de date
|
||||
d'enregistrement effectif :
|
||||
</para>
|
||||
|
||||
|
@ -104,9 +106,9 @@
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Puis, afin de s'assurer que vous pouvez toujours récupérer les enregistrements actuellement
|
||||
effectifs, activez simplement le filtre sur la session avant de récupérer des données des
|
||||
employés :
|
||||
Puis, afin de s'assurer que vous pouvez toujours récupérer les enregistrements actuellement
|
||||
effectifs, activez simplement le filtre sur la session avant de récupérer des données des
|
||||
employés :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = ...;
|
||||
|
@ -117,16 +119,16 @@ List results = session.createQuery("from Employee as e where e.salary > :targetS
|
|||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
Dans le HQL ci-dessus, bien que nous ayons seulement mentionné une contrainte de
|
||||
salaire sur les resultats, à cause du filtre activé, la requête retournera seulement
|
||||
les employés actuellement actifs qui ont un salaire supérieur à un million de dollars.
|
||||
Dans le HQL ci-dessus, bien que nous ayons seulement mentionné une contrainte de
|
||||
salaire sur les resultats, à cause du filtre activé, la requête retournera seulement
|
||||
les employés actuellement actifs qui ont un salaire supérieur à un million de dollars.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A noter : si vous prévoyez d'utiliser des filtres avec des jointures externes (soit
|
||||
à travers HQL, soit par le chargement) faites attention à la direction de l'expression
|
||||
de condition. Il est plus sûr de la positionner pour les jointures externes à gauche ;
|
||||
en général, placez le paramètre d'abord, suivi du(des) nom(s) de colonne après l'opérateur.
|
||||
A noter : si vous prévoyez d'utiliser des filtres avec des jointures externes (soit
|
||||
à travers HQL, soit par le chargement) faites attention à la direction de l'expression
|
||||
de condition. Il est plus sûr de la positionner pour les jointures externes à gauche ;
|
||||
en général, placez le paramètre d'abord, suivi du(des) nom(s) de colonne après l'opérateur.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="inheritance">
|
||||
<title>Mapping d'héritage de classe</title>
|
||||
<title>Mapping d'héritage de classe</title>
|
||||
|
||||
<sect1 id="inheritance-strategies" revision="3">
|
||||
<title>Les trois stratégies</title>
|
||||
<title>Les trois stratégies</title>
|
||||
|
||||
<para>
|
||||
Hibernate supporte les trois stratégies d'héritage de base :
|
||||
Hibernate supporte les trois stratégies d'héritage de base :
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
une table par hiérarchie de classe (table per class hierarchy)
|
||||
une table par hiérarchie de classe (table per class hierarchy)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
|
@ -22,13 +24,13 @@
|
|||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
une table par classe concrète (table per concrete class)
|
||||
une table par classe concrète (table per concrete class)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Hibernate supporte en plus une quatrièmestratégie, légèrement différente, qui supporte le polymorphisme :
|
||||
Hibernate supporte en plus une quatrièmestratégie, légèrement différente, qui supporte le polymorphisme :
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
|
@ -40,26 +42,26 @@
|
|||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Il est possible d'utiliser différentes stratégies de mapping pour différentes branches d'une même
|
||||
hiérarchie d'héritage, et alors d'employer le polymorphisme implicite pour réaliser le
|
||||
polymorphisme à travers toute la hiérarchie. Pourtant, Hibernate ne supporte pas de mélanger
|
||||
Il est possible d'utiliser différentes stratégies de mapping pour différentes branches d'une même
|
||||
hiérarchie d'héritage, et alors d'employer le polymorphisme implicite pour réaliser le
|
||||
polymorphisme à travers toute la hiérarchie. Pourtant, Hibernate ne supporte pas de mélanger
|
||||
des mappings <literal><subclass></literal> et
|
||||
<literal><joined-subclass></literal> et <literal><union-subclass></literal>
|
||||
pour le même élément <literal><class></literal> racine.
|
||||
Il est possible de mélanger ensemble les stratégies d'une table par hiérarchie et d'une
|
||||
table par sous-classe, pour le même élément <literal><class></literal>, en combinant
|
||||
les éléments <literal><subclass></literal> et <literal><join></literal> (voir dessous).
|
||||
pour le même élément <literal><class></literal> racine.
|
||||
Il est possible de mélanger ensemble les stratégies d'une table par hiérarchie et d'une
|
||||
table par sous-classe, pour le même élément <literal><class></literal>, en combinant
|
||||
les éléments <literal><subclass></literal> et <literal><join></literal> (voir dessous).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Il est possible de définir des mappings de <literal>subclass</literal>, <literal>union-subclass</literal>,
|
||||
et <literal>joined-subclass</literal> dans des documents de mapping séparés, directement sous
|
||||
<literal>hibernate-mapping</literal>. Ceci vous permet d'étendre une hiérarchie de classe juste en
|
||||
ajoutant un nouveau fichier de mapping. Vous devez spécifier un attribut <literal>extends</literal>
|
||||
dans le mapping de la sous-classe, en nommant une super-classe précédemment mappée. Note :
|
||||
précédemment cette foncionnalité rendait l'ordre des documents de mapping important. Depuis
|
||||
Il est possible de définir des mappings de <literal>subclass</literal>, <literal>union-subclass</literal>,
|
||||
et <literal>joined-subclass</literal> dans des documents de mapping séparés, directement sous
|
||||
<literal>hibernate-mapping</literal>. Ceci vous permet d'étendre une hiérarchie de classe juste en
|
||||
ajoutant un nouveau fichier de mapping. Vous devez spécifier un attribut <literal>extends</literal>
|
||||
dans le mapping de la sous-classe, en nommant une super-classe précédemment mappée. Note :
|
||||
précédemment cette foncionnalité rendait l'ordre des documents de mapping important. Depuis
|
||||
Hibernate3, l'ordre des fichier de mapping n'importe plus lors de l'utilisation du mot-clef "extends".
|
||||
L'ordre à l'intérieur d'un simple fichier de mapping impose encore de définir les classes mères
|
||||
L'ordre à l'intérieur d'un simple fichier de mapping impose encore de définir les classes mères
|
||||
avant les classes filles.
|
||||
</para>
|
||||
|
||||
|
@ -72,12 +74,12 @@
|
|||
|
||||
|
||||
<sect2 id="inheritance-tableperclass" >
|
||||
<title>Une table par hiérarchie de classe</title>
|
||||
<title>Une table par hiérarchie de classe</title>
|
||||
|
||||
<para>
|
||||
Supposons que nous ayons une interface <literal>Payment</literal>, implémentée
|
||||
Supposons que nous ayons une interface <literal>Payment</literal>, implémentée
|
||||
par <literal>CreditCardPayment</literal>, <literal>CashPayment</literal>,
|
||||
<literal>ChequePayment</literal>. La stratégie une table par hiérarchie serait :
|
||||
<literal>ChequePayment</literal>. La stratégie une table par hiérarchie serait :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
||||
|
@ -101,7 +103,7 @@
|
|||
|
||||
<para>
|
||||
Une seule table est requise. Une grande limitation de cette
|
||||
stratégie est que les colonnes déclarées par les classes filles, telles que <literal>CCTYPE</literal>,
|
||||
stratégie est que les colonnes déclarées par les classes filles, telles que <literal>CCTYPE</literal>,
|
||||
ne peuvent avoir de contrainte <literal>NOT NULL</literal>.
|
||||
</para>
|
||||
|
||||
|
@ -111,7 +113,7 @@
|
|||
<title>Une table par classe fille</title>
|
||||
|
||||
<para>
|
||||
La stratégie une table par classe fille serait :
|
||||
La stratégie une table par classe fille serait :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
||||
|
@ -137,7 +139,7 @@
|
|||
|
||||
<para>
|
||||
Quatre tables sont requises. Les trois tables des classes filles ont
|
||||
une clé primaire associée à la table classe mère (le modèle relationnel
|
||||
une clé primaire associée à la table classe mère (le modèle relationnel
|
||||
est une association un-vers-un).
|
||||
</para>
|
||||
|
||||
|
@ -147,14 +149,14 @@
|
|||
<title>Une table par classe fille, en utilisant un discriminant</title>
|
||||
|
||||
<para>
|
||||
Notez que l'implémentation Hibernate de la stratégie un table par
|
||||
classe fille ne nécessite pas de colonne discriminante dans la table
|
||||
classe mère. D'autres implémentations de mappers Objet/Relationnel utilisent
|
||||
une autre implémentation de la stratégie une table par classe fille qui nécessite
|
||||
une colonne de type discriminant dans la table de la classe mère. L'approche
|
||||
prise par Hibernate est plus difficile à implémenter mais plus correcte
|
||||
Notez que l'implémentation Hibernate de la stratégie un table par
|
||||
classe fille ne nécessite pas de colonne discriminante dans la table
|
||||
classe mère. D'autres implémentations de mappers Objet/Relationnel utilisent
|
||||
une autre implémentation de la stratégie une table par classe fille qui nécessite
|
||||
une colonne de type discriminant dans la table de la classe mère. L'approche
|
||||
prise par Hibernate est plus difficile à implémenter mais plus correcte
|
||||
d'une point de vue relationnel. Si vous aimeriez utiliser
|
||||
une colonne discriminante avec la stratégie d'une table par classe fille, vous pourriez combiner
|
||||
une colonne discriminante avec la stratégie d'une table par classe fille, vous pourriez combiner
|
||||
l'utilisation de <literal><subclass></literal> et
|
||||
<literal><join></literal>, comme suit :
|
||||
</para>
|
||||
|
@ -188,17 +190,17 @@
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
La déclaration optionnelle <literal>fetch="select"</literal> indique à Hibernate
|
||||
de ne pas récupérer les données de la classe fille <literal>ChequePayment</literal> par une jointure externe lors des requêtes sur la classe mère.
|
||||
La déclaration optionnelle <literal>fetch="select"</literal> indique à Hibernate
|
||||
de ne pas récupérer les données de la classe fille <literal>ChequePayment</literal> par une jointure externe lors des requêtes sur la classe mère.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="inheritance-mixing-tableperclass-tablepersubclass">
|
||||
<title>Mélange d'une table par hiérarchie de classe avec une table par classe fille</title>
|
||||
<title>Mélange d'une table par hiérarchie de classe avec une table par classe fille</title>
|
||||
|
||||
<para>
|
||||
Vous pouvez même mélanger les stratégies d'une table par hiérarchie de classe et d'une table par classe fille en utilisant cette approche :
|
||||
Vous pouvez même mélanger les stratégies d'une table par hiérarchie de classe et d'une table par classe fille en utilisant cette approche :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
||||
|
@ -223,8 +225,8 @@
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Pour importe laquelle de ces stratégies, une association polymorphique vers la classe racine
|
||||
<literal>Payment</literal> est mappée en utilisant <literal><many-to-one></literal>.
|
||||
Pour importe laquelle de ces stratégies, une association polymorphique vers la classe racine
|
||||
<literal>Payment</literal> est mappée en utilisant <literal><many-to-one></literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
|
||||
|
@ -232,10 +234,10 @@
|
|||
</sect2>
|
||||
|
||||
<sect2 id="inheritance-tableperconcrete" revision="2">
|
||||
<title>Une table par classe concrète</title>
|
||||
<title>Une table par classe concrète</title>
|
||||
|
||||
<para>
|
||||
Il y a deux manières d'utiliser la stratégie d'une table par classe concrète. La première
|
||||
Il y a deux manières d'utiliser la stratégie d'une table par classe concrète. La première
|
||||
est d'employer <literal><union-subclass></literal>.
|
||||
</para>
|
||||
|
||||
|
@ -258,30 +260,30 @@
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Trois tables sont nécessaires pour les classes filles. Chaque table définit des colonnes
|
||||
pour toutes les propriétés de la classe, incluant les propriétés héritéés.
|
||||
Trois tables sont nécessaires pour les classes filles. Chaque table définit des colonnes
|
||||
pour toutes les propriétés de la classe, incluant les propriétés héritéés.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
La limitation de cette approche est que si une propriété est mappée sur la classe mère, le nom
|
||||
de la colonne doit être le même pour toutes les classes filles. (Nous pourrions être plus souple
|
||||
La limitation de cette approche est que si une propriété est mappée sur la classe mère, le nom
|
||||
de la colonne doit être le même pour toutes les classes filles. (Nous pourrions être plus souple
|
||||
dans une future version d'Hibernate).
|
||||
La stratégie du générateur d'identifiant n'est pas permise dans l'héritage de classes filles par
|
||||
La stratégie du générateur d'identifiant n'est pas permise dans l'héritage de classes filles par
|
||||
union, en effet la valeur (NdT : seed) de la clef primaire
|
||||
doit être partagée par toutes les classes filles "union" d'une hiérarchie.
|
||||
doit être partagée par toutes les classes filles "union" d'une hiérarchie.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Si votre classe mère est abstraite, mappez la avec <literal>abstract="true"</literal>.
|
||||
Bien sûr, si elle n'est pas abstraite, une table supplémentaire (par défaut,
|
||||
Si votre classe mère est abstraite, mappez la avec <literal>abstract="true"</literal>.
|
||||
Bien sûr, si elle n'est pas abstraite, une table supplémentaire (par défaut,
|
||||
<literal>PAYMENT</literal> dans l'exemple ci-dessus) est requise pour contenir des instances
|
||||
de la classe mère.
|
||||
de la classe mère.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="inheritance-tableperconcreate-polymorphism">
|
||||
<title>Une table par classe concrète, en utilisant le polymorphisme implicite</title>
|
||||
<title>Une table par classe concrète, en utilisant le polymorphisme implicite</title>
|
||||
|
||||
<para>
|
||||
Une approche alternative est l'emploi du polymorphisme implicite :
|
||||
|
@ -313,20 +315,20 @@
|
|||
|
||||
<para>
|
||||
Notez que nulle part nous ne mentionnons l'interface <literal>Payment</literal> explicitement.
|
||||
Notez aussi que des propriétés de <literal>Payment</literal> sont mappées dans
|
||||
chaque classe fille. Si vous voulez éviter des duplications, considérez l'utilisation des
|
||||
entités XML (cf. <literal>[ <!ENTITY allproperties SYSTEM "allproperties.xml"> ]</literal>
|
||||
dans la déclaration du <literal>DOCTYPE</literal> et <literal>&allproperties;</literal> dans le mapping).
|
||||
Notez aussi que des propriétés de <literal>Payment</literal> sont mappées dans
|
||||
chaque classe fille. Si vous voulez éviter des duplications, considérez l'utilisation des
|
||||
entités XML (cf. <literal>[ <!ENTITY allproperties SYSTEM "allproperties.xml"> ]</literal>
|
||||
dans la déclaration du <literal>DOCTYPE</literal> et <literal>&allproperties;</literal> dans le mapping).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
L'inconvénient de cette approche est qu'Hibernate ne génère pas d'<literal>UNION</literal>s SQL
|
||||
lors de l'exécution des requêtes polymorphiques.
|
||||
L'inconvénient de cette approche est qu'Hibernate ne génère pas d'<literal>UNION</literal>s SQL
|
||||
lors de l'exécution des requêtes polymorphiques.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Pour cette stratégie de mapping, une association polymorphique pour <literal>Payment</literal>
|
||||
est habituellement mappée en utilisant <literal><any></literal>.
|
||||
Pour cette stratégie de mapping, une association polymorphique pour <literal>Payment</literal>
|
||||
est habituellement mappée en utilisant <literal><any></literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<any name="payment" meta-type="string" id-type="long">
|
||||
|
@ -340,14 +342,14 @@
|
|||
</sect2>
|
||||
|
||||
<sect2 id="inheritace-mixingpolymorphism">
|
||||
<title>Mélange du polymorphisme implicite avec d'autres mappings d'héritage</title>
|
||||
<title>Mélange du polymorphisme implicite avec d'autres mappings d'héritage</title>
|
||||
|
||||
<para>
|
||||
Il y a une chose supplémentaire à noter à propos de ce mapping. Puisque les classes filles sont
|
||||
chacune mappées avec leur propre élément <literal><class></literal> (et puisque
|
||||
Il y a une chose supplémentaire à noter à propos de ce mapping. Puisque les classes filles sont
|
||||
chacune mappées avec leur propre élément <literal><class></literal> (et puisque
|
||||
<literal>Payment</literal> est juste une interface), chaque classe fille pourrait
|
||||
facilement faire partie d'une autre hiérarchie
|
||||
d'héritage ! (Et vous pouvez encore faire des requêtes polymorphiques pour l'interface <literal>Payment</literal>).
|
||||
facilement faire partie d'une autre hiérarchie
|
||||
d'héritage ! (Et vous pouvez encore faire des requêtes polymorphiques pour l'interface <literal>Payment</literal>).
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
|
||||
|
@ -380,10 +382,10 @@
|
|||
|
||||
<para>
|
||||
Encore une fois, nous ne mentionnons pas explicitement <literal>Payment</literal>.
|
||||
Si nous exécutons une requête sur l'interface <literal>Payment</literal> - par
|
||||
Si nous exécutons une requête sur l'interface <literal>Payment</literal> - par
|
||||
exemple, <literal>from Payment</literal> - Hibernate retournera
|
||||
automatiquement les instances de <literal>CreditCardPayment</literal>
|
||||
(et ses classes filles puisqu'elles implémentent aussi <literal>Payment</literal>),
|
||||
(et ses classes filles puisqu'elles implémentent aussi <literal>Payment</literal>),
|
||||
<literal>CashPayment</literal> et <literal>ChequePayment</literal> mais pas
|
||||
les instances de <literal>NonelectronicTransaction</literal>.
|
||||
</para>
|
||||
|
@ -396,17 +398,17 @@
|
|||
<title>Limitations</title>
|
||||
|
||||
<para>
|
||||
Il y a certaines limitations à l'approche du "polymorphisme implicite"
|
||||
pour la stratégie de mapping d'une table par classe concrète.
|
||||
Il y a plutôt moins de limitations restrictives aux mappings <literal><union-subclass></literal>.
|
||||
Il y a certaines limitations à l'approche du "polymorphisme implicite"
|
||||
pour la stratégie de mapping d'une table par classe concrète.
|
||||
Il y a plutôt moins de limitations restrictives aux mappings <literal><union-subclass></literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
La table suivante montre les limitations des mappings d'une table par classe concrète, et du polymorphisme implicite, dans Hibernate.
|
||||
La table suivante montre les limitations des mappings d'une table par classe concrète, et du polymorphisme implicite, dans Hibernate.
|
||||
</para>
|
||||
|
||||
<table frame="topbot">
|
||||
<title>Caractéristiques du mapping d'héritage</title>
|
||||
<title>Caractéristiques du mapping d'héritage</title>
|
||||
<tgroup cols='8' align='left' colsep='1' rowsep='1'>
|
||||
<colspec colname='c1' colwidth="1*"/>
|
||||
<colspec colname='c2' colwidth="1*"/>
|
||||
|
@ -418,20 +420,20 @@
|
|||
<colspec colname='c8' colwidth="1*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Stratégie d'héritage</entry>
|
||||
<entry>Stratégie d'héritage</entry>
|
||||
<entry>many-to-one polymorphique</entry>
|
||||
<entry>one-to-one polymorphique</entry>
|
||||
<entry>one-to-many polymorphique</entry>
|
||||
<entry>many-to-many polymorphique</entry>
|
||||
<entry><literal>load()/get()</literal> polymorphique</entry>
|
||||
<entry>Requêtes polymorphiques</entry>
|
||||
<entry>Requêtes polymorphiques</entry>
|
||||
<entry>Jointures polymorphiques</entry>
|
||||
<entry>Récupération par jointure externe</entry>
|
||||
<entry>Récupération par jointure externe</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>une table par hiérarchie de classe</entry>
|
||||
<entry>une table par hiérarchie de classe</entry>
|
||||
<entry><literal><many-to-one></literal></entry>
|
||||
<entry><literal><one-to-one></literal></entry>
|
||||
<entry><literal><one-to-many></literal></entry>
|
||||
|
@ -439,7 +441,7 @@
|
|||
<entry><literal>s.get(Payment.class, id)</literal></entry>
|
||||
<entry><literal>from Payment p</literal></entry>
|
||||
<entry><literal>from Order o join o.payment p</literal></entry>
|
||||
<entry><emphasis>supportée</emphasis></entry>
|
||||
<entry><emphasis>supportée</emphasis></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>une table par classe fille</entry>
|
||||
|
@ -450,10 +452,10 @@
|
|||
<entry><literal>s.get(Payment.class, id)</literal></entry>
|
||||
<entry><literal>from Payment p</literal></entry>
|
||||
<entry><literal>from Order o join o.payment p</literal></entry>
|
||||
<entry><emphasis>supportée</emphasis></entry>
|
||||
<entry><emphasis>supportée</emphasis></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>une table par classe concrète (union-subclass)</entry>
|
||||
<entry>une table par classe concrète (union-subclass)</entry>
|
||||
<entry><literal><many-to-one></literal></entry>
|
||||
<entry><literal><one-to-one></literal></entry>
|
||||
<entry><literal><one-to-many></literal> (pour <literal>inverse="true"</literal> seulement)</entry>
|
||||
|
@ -461,18 +463,18 @@
|
|||
<entry><literal>s.get(Payment.class, id)</literal></entry>
|
||||
<entry><literal>from Payment p</literal></entry>
|
||||
<entry><literal>from Order o join o.payment p</literal></entry>
|
||||
<entry><emphasis>supportée</emphasis></entry>
|
||||
<entry><emphasis>supportée</emphasis></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>une table par classe concrète (polymorphisme implicite)</entry>
|
||||
<entry>une table par classe concrète (polymorphisme implicite)</entry>
|
||||
<entry><literal><any></literal></entry>
|
||||
<entry><emphasis>non supporté</emphasis></entry>
|
||||
<entry><emphasis>non supporté</emphasis></entry>
|
||||
<entry><emphasis>non supporté</emphasis></entry>
|
||||
<entry><emphasis>non supporté</emphasis></entry>
|
||||
<entry><literal><many-to-any></literal></entry>
|
||||
<entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
|
||||
<entry><literal>from Payment p</literal></entry>
|
||||
<entry><emphasis>non supportées</emphasis></entry>
|
||||
<entry><emphasis>non supportée</emphasis></entry>
|
||||
<entry><emphasis>non supportées</emphasis></entry>
|
||||
<entry><emphasis>non supportée</emphasis></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,20 +1,22 @@
|
|||
<?xml version='1.0' encoding="iso-8859-1"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="persistent-classes" revision="2">
|
||||
<title>Classes persistantes</title>
|
||||
|
||||
<para>
|
||||
Les classes persistantes sont les classes d'une application qui implémentent
|
||||
les entités d'un problème métier (ex. Client et Commande dans une application
|
||||
de commerce électronique).
|
||||
Toutes les instances d'une classe persistante ne sont pas forcément
|
||||
dans l'état persistant - au lieu de cela, une instance peut être éphémère (NdT : transient) ou détachée.
|
||||
Les classes persistantes sont les classes d'une application qui implémentent
|
||||
les entités d'un problème métier (ex. Client et Commande dans une application
|
||||
de commerce électronique).
|
||||
Toutes les instances d'une classe persistante ne sont pas forcément
|
||||
dans l'état persistant - au lieu de cela, une instance peut être éphémère (NdT : transient) ou détachée.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate fonctionne de manière optimale lorsque ces classes suivent quelques règles
|
||||
simples, aussi connues comme le modèle de programmation Plain Old Java Object
|
||||
(POJO). Cependant, aucune de ces règles ne sont des besoins absolus. En effet, Hibernate3 suppose très peu de choses à propos
|
||||
de la nature de vos objets persistants. Vous pouvez exprimer un modèle de domaine par d'autres moyens : utiliser des arbres
|
||||
Hibernate fonctionne de manière optimale lorsque ces classes suivent quelques règles
|
||||
simples, aussi connues comme le modèle de programmation Plain Old Java Object
|
||||
(POJO). Cependant, aucune de ces règles ne sont des besoins absolus. En effet, Hibernate3 suppose très peu de choses à propos
|
||||
de la nature de vos objets persistants. Vous pouvez exprimer un modèle de domaine par d'autres moyens : utiliser des arbres
|
||||
d'instances de <literal>Map</literal>, par exemple.
|
||||
</para>
|
||||
|
||||
|
@ -22,8 +24,8 @@
|
|||
<title>Un exemple simple de POJO</title>
|
||||
|
||||
<para>
|
||||
Toute bonne application Java nécessite une classe persistante
|
||||
représentant les félins.
|
||||
Toute bonne application Java nécessite une classe persistante
|
||||
représentant les félins.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
|
@ -106,49 +108,49 @@ public class Cat {
|
|||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
Il y a quatre règles à suivre ici :
|
||||
Il y a quatre règles à suivre ici :
|
||||
</para>
|
||||
|
||||
|
||||
<sect2 id="persistent-classes-pojo-constructor" revision="1">
|
||||
<title>Implémenter un constructeur sans argument</title>
|
||||
<title>Implémenter un constructeur sans argument</title>
|
||||
|
||||
<para>
|
||||
<literal>Cat</literal> a un constructeur sans argument. Toutes les classes persistantes doivent avoir un
|
||||
constructeur par défaut (lequel peut ne pas être public) pour qu'Hibernate puissent les instancier en utilisant
|
||||
<literal>Constructor.newInstance()</literal>. Nous recommandons fortement d'avoir un constructeur par défaut avec
|
||||
au moins une visibilité <emphasis>paquet</emphasis> pour la génération du proxy à l'exécution dans Hibernate.
|
||||
constructeur par défaut (lequel peut ne pas être public) pour qu'Hibernate puissent les instancier en utilisant
|
||||
<literal>Constructor.newInstance()</literal>. Nous recommandons fortement d'avoir un constructeur par défaut avec
|
||||
au moins une visibilité <emphasis>paquet</emphasis> pour la génération du proxy à l'exécution dans Hibernate.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="persistent-classes-pojo-identifier" revision="2">
|
||||
<title>Fournir une propriété d'indentifiant (optionnel)</title>
|
||||
<title>Fournir une propriété d'indentifiant (optionnel)</title>
|
||||
|
||||
<para>
|
||||
<literal>Cat</literal> possède une propriété appelée <literal>id</literal>.
|
||||
Cette propriété mappe la valeur de la colonne de clé primaire de la table
|
||||
d'une base de données.La propriété aurait pu s'appeler complètement autrement,
|
||||
et son type aurait pu être n'importe quel type primitif, n'importe quel "encapsuleur"
|
||||
<literal>Cat</literal> possède une propriété appelée <literal>id</literal>.
|
||||
Cette propriété mappe la valeur de la colonne de clé primaire de la table
|
||||
d'une base de données.La propriété aurait pu s'appeler complètement autrement,
|
||||
et son type aurait pu être n'importe quel type primitif, n'importe quel "encapsuleur"
|
||||
de type primitif, <literal>java.lang.String</literal> ou <literal>java.util.Date</literal>.
|
||||
(Si votre base de données héritée possède des clés composites, elles peuvent être mappées
|
||||
en utilisant une classe définie par l'utilisateur et possédant les propriétés associées aux
|
||||
types de la clé composite - voir la section concernant les identifiants composites plus tard).
|
||||
(Si votre base de données héritée possède des clés composites, elles peuvent être mappées
|
||||
en utilisant une classe définie par l'utilisateur et possédant les propriétés associées aux
|
||||
types de la clé composite - voir la section concernant les identifiants composites plus tard).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
La propriété d'identifiant est strictement optionnelle. Vous pouver l'oublier et laisser Hibernate
|
||||
La propriété d'identifiant est strictement optionnelle. Vous pouver l'oublier et laisser Hibernate
|
||||
s'occuper des identifiants de l'objet en interne. Toutefois, nous ne le recommandons pas.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
En fait, quelques fonctionnalités ne sont disponibles que pour les classes
|
||||
déclarant un identifiant de propriété :
|
||||
En fait, quelques fonctionnalités ne sont disponibles que pour les classes
|
||||
déclarant un identifiant de propriété :
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
Les réattachements transitifs pour les objets détachés (mise à jour en cascade ou fusion en cascade) -
|
||||
Les réattachements transitifs pour les objets détachés (mise à jour en cascade ou fusion en cascade) -
|
||||
voir <xref linkend="objectstate-transitive"/>
|
||||
</para>
|
||||
</listitem>
|
||||
|
@ -165,8 +167,8 @@ public class Cat {
|
|||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Nous recommandons que vous déclariez les propriétés d'identifiant de manière
|
||||
uniforme. Nous recommandons également que vous utilisiez un type nullable
|
||||
Nous recommandons que vous déclariez les propriétés d'identifiant de manière
|
||||
uniforme. Nous recommandons également que vous utilisiez un type nullable
|
||||
(ie. non primitif).
|
||||
</para>
|
||||
</sect2>
|
||||
|
@ -174,39 +176,39 @@ public class Cat {
|
|||
<sect2 id="persistent-classes-pojo-final">
|
||||
<title>Favoriser les classes non finales (optionnel)</title>
|
||||
<para>
|
||||
Une fonctionnalité clef d'Hibernate, les <emphasis>proxies</emphasis>, nécessitent
|
||||
que la classe persistente soit non finale ou qu'elle soit l'implémentation d'une
|
||||
interface qui déclare toutes les méthodes publiques.
|
||||
Une fonctionnalité clef d'Hibernate, les <emphasis>proxies</emphasis>, nécessitent
|
||||
que la classe persistente soit non finale ou qu'elle soit l'implémentation d'une
|
||||
interface qui déclare toutes les méthodes publiques.
|
||||
</para>
|
||||
<para>
|
||||
Vous pouvez persister, grâce à Hibernate, les classes <literal>final</literal>
|
||||
qui n'implémentent pas d'interface, mais vous ne pourrez pas utiliser les proxies pour les chargements d'associations paresseuses
|
||||
- ce qui limitera vos possibilités d'ajustement des performances.
|
||||
Vous pouvez persister, grâce à Hibernate, les classes <literal>final</literal>
|
||||
qui n'implémentent pas d'interface, mais vous ne pourrez pas utiliser les proxies pour les chargements d'associations paresseuses
|
||||
- ce qui limitera vos possibilités d'ajustement des performances.
|
||||
</para>
|
||||
<para>
|
||||
Vous devriez aussi éviter de déclarer des méthodes <literal>public final</literal> sur des classes
|
||||
non-finales. Si vous voulez utiliser une classe avec une méthode <literal>public final</literal>, vous devez
|
||||
explicitement désactiver les proxies en paramétrant
|
||||
Vous devriez aussi éviter de déclarer des méthodes <literal>public final</literal> sur des classes
|
||||
non-finales. Si vous voulez utiliser une classe avec une méthode <literal>public final</literal>, vous devez
|
||||
explicitement désactiver les proxies en paramétrant
|
||||
<literal>lazy="false"</literal>.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="persistent-classes-pojo-accessors" revision="2">
|
||||
<title>Déclarer les accesseurs et mutateurs des attributs persistants (optionnel)</title>
|
||||
<title>Déclarer les accesseurs et mutateurs des attributs persistants (optionnel)</title>
|
||||
|
||||
<para>
|
||||
<literal>Cat</literal> déclare des mutateurs pour toutes ses champs persistants. Beaucoup d'autres
|
||||
<literal>Cat</literal> déclare des mutateurs pour toutes ses champs persistants. Beaucoup d'autres
|
||||
solutions de mapping Objet/relationnel persistent directement les variables d'instance. Nous pensons
|
||||
qu'il est bien mieux de fournir une indirection entre le schéma relationnel et les structures de données internes de la classe.
|
||||
Par défaut, Hibernate persiste les propriétés suivant le style JavaBean, et reconnaît les noms de méthodes de la forme <literal>
|
||||
qu'il est bien mieux de fournir une indirection entre le schéma relationnel et les structures de données internes de la classe.
|
||||
Par défaut, Hibernate persiste les propriétés suivant le style JavaBean, et reconnaît les noms de méthodes de la forme <literal>
|
||||
getFoo</literal>, <literal>isFoo</literal> et
|
||||
<literal>setFoo</literal>. Nous pouvons changer pour un accès direct aux champs pour des propriétés particulières, si besoin est.
|
||||
<literal>setFoo</literal>. Nous pouvons changer pour un accès direct aux champs pour des propriétés particulières, si besoin est.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Les propriétés <emphasis>n'ont pas</emphasis> à être déclarées publiques -
|
||||
Hibernate peut persister une propriété avec un paire de getter/setter de
|
||||
visibilité par défault, <literal>protected</literal> ou <literal>
|
||||
Les propriétés <emphasis>n'ont pas</emphasis> à être déclarées publiques -
|
||||
Hibernate peut persister une propriété avec un paire de getter/setter de
|
||||
visibilité par défault, <literal>protected</literal> ou <literal>
|
||||
private</literal>.
|
||||
</para>
|
||||
|
||||
|
@ -215,11 +217,11 @@ public class Cat {
|
|||
</sect1>
|
||||
|
||||
<sect1 id="persistent-classes-inheritance">
|
||||
<title>Implémenter l'héritage</title>
|
||||
<title>Implémenter l'héritage</title>
|
||||
|
||||
<para>
|
||||
Une sous-classe doit également suivre la première et la seconde règle.
|
||||
Elle hérite sa propriété d'identifiant de <literal>Cat</literal>.
|
||||
Une sous-classe doit également suivre la première et la seconde règle.
|
||||
Elle hérite sa propriété d'identifiant de <literal>Cat</literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
|
@ -237,55 +239,55 @@ public class DomesticCat extends Cat {
|
|||
</sect1>
|
||||
|
||||
<sect1 id="persistent-classes-equalshashcode" revision="1">
|
||||
<title>Implémenter <literal>equals()</literal> et <literal>hashCode()</literal></title>
|
||||
<title>Implémenter <literal>equals()</literal> et <literal>hashCode()</literal></title>
|
||||
|
||||
<para>
|
||||
Vous devez surcharger les méthodes <literal>equals()</literal> et
|
||||
Vous devez surcharger les méthodes <literal>equals()</literal> et
|
||||
<literal>hashCode()</literal> si vous
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
avez l'intention de mettre des instances de classes persistantes dans un <literal>Set</literal>
|
||||
(la manière recommandée pour représenter des associations pluri-valuées)
|
||||
(la manière recommandée pour représenter des associations pluri-valuées)
|
||||
<emphasis>et</emphasis>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
avez l'intention d'utiliser le réattachement d'instances détachées
|
||||
avez l'intention d'utiliser le réattachement d'instances détachées
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Hibernate garantit l'équivalence de l'identité persistante (ligne de base de données) et l'identité Java seulement
|
||||
à l'intérieur de la portée d'une session particulière. Donc dès que nous mélangeons des instances venant de différentes
|
||||
sessions, nous devons implémenter <literal>equals()</literal> et
|
||||
<literal>hashCode()</literal> si nous souhaitons avoir une sémantique correcte pour les <literal>Set</literal>s.
|
||||
Hibernate garantit l'équivalence de l'identité persistante (ligne de base de données) et l'identité Java seulement
|
||||
à l'intérieur de la portée d'une session particulière. Donc dès que nous mélangeons des instances venant de différentes
|
||||
sessions, nous devons implémenter <literal>equals()</literal> et
|
||||
<literal>hashCode()</literal> si nous souhaitons avoir une sémantique correcte pour les <literal>Set</literal>s.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
La manière la plus évidente est d'implémenter <literal>equals()</literal>/<literal>hashCode()</literal>
|
||||
La manière la plus évidente est d'implémenter <literal>equals()</literal>/<literal>hashCode()</literal>
|
||||
en comparant la valeur de l'identifiant des deux objets. Si cette valeur est identique, les deux
|
||||
doivent représenter la même ligne de base de données, ils sont donc égaux (si les deux sont
|
||||
ajoutés à un <literal>Set</literal>, nous n'aurons qu'un seul élément dans le
|
||||
doivent représenter la même ligne de base de données, ils sont donc égaux (si les deux sont
|
||||
ajoutés à un <literal>Set</literal>, nous n'aurons qu'un seul élément dans le
|
||||
<literal>Set</literal>). Malheureusement, nous ne pouvons pas utiliser cette approche avec
|
||||
des identifiants générés ! Hibernate n'assignera de
|
||||
valeur d'identifiant qu'aux objets qui sont persistants, une instance nouvellement créée n'aura
|
||||
donc pas de valeur d'identifiant ! De plus, si une instance est non sauvegardée et actuellement dans un <literal>Set</literal>,
|
||||
le sauvegarder assignera une valeur d'identifiant à l'objet. Si <literal>equals()</literal> et <literal>hashCode()</literal>
|
||||
sont basées sur la valeur de l'identifiant, le code de hachage devrait changer, rompant le contrat du <literal>Set</literal>.
|
||||
Regardez sur le site web d'Hibernate pour une discussion complète de ce problème.
|
||||
Notez que ceci n'est pas un problème d'Hibernate, mais la sémantique normale de Java pour l'identité d'un objet et l'égalité.
|
||||
des identifiants générés ! Hibernate n'assignera de
|
||||
valeur d'identifiant qu'aux objets qui sont persistants, une instance nouvellement créée n'aura
|
||||
donc pas de valeur d'identifiant ! De plus, si une instance est non sauvegardée et actuellement dans un <literal>Set</literal>,
|
||||
le sauvegarder assignera une valeur d'identifiant à l'objet. Si <literal>equals()</literal> et <literal>hashCode()</literal>
|
||||
sont basées sur la valeur de l'identifiant, le code de hachage devrait changer, rompant le contrat du <literal>Set</literal>.
|
||||
Regardez sur le site web d'Hibernate pour une discussion complète de ce problème.
|
||||
Notez que ceci n'est pas un problème d'Hibernate, mais la sémantique normale de Java pour l'identité d'un objet et l'égalité.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Nous recommandons donc d'implémenter
|
||||
Nous recommandons donc d'implémenter
|
||||
<literal>equals()</literal> et <literal>hashCode()</literal> en utilisant <emphasis>
|
||||
l'égalité par clé métier</emphasis>.L'égalité par clé métier signifie que la méthode <literal>equals()</literal>
|
||||
compare uniquement les propriétés qui forment une clé métier, une clé qui
|
||||
identifierait notre instance dans le monde réel (une clé candidate
|
||||
l'égalité par clé métier</emphasis>.L'égalité par clé métier signifie que la méthode <literal>equals()</literal>
|
||||
compare uniquement les propriétés qui forment une clé métier, une clé qui
|
||||
identifierait notre instance dans le monde réel (une clé candidate
|
||||
<emphasis>naturelle</emphasis>) :
|
||||
</para>
|
||||
|
||||
|
@ -314,39 +316,39 @@ public class DomesticCat extends Cat {
|
|||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
Notez qu'une clef métier ne doit pas être solide comme une clef primaire de base de données
|
||||
(voir <xref linkend="transactions-basics-identity"/>). Les propriétés
|
||||
immuables ou uniques sont généralement de bonnes candidates pour une clef métier.
|
||||
Notez qu'une clef métier ne doit pas être solide comme une clef primaire de base de données
|
||||
(voir <xref linkend="transactions-basics-identity"/>). Les propriétés
|
||||
immuables ou uniques sont généralement de bonnes candidates pour une clef métier.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="persistent-classes-dynamicmodels">
|
||||
<title>Modèles dynamiques</title>
|
||||
<title>Modèles dynamiques</title>
|
||||
|
||||
<para>
|
||||
<emphasis>Notez que la fonctionnalités suivantes sont actuellement considérées
|
||||
comme expérimentales et peuvent changer dans un futur proche.</emphasis>
|
||||
<emphasis>Notez que la fonctionnalités suivantes sont actuellement considérées
|
||||
comme expérimentales et peuvent changer dans un futur proche.</emphasis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Les entités persistantes ne doivent pas nécessairement être représentées comme
|
||||
des classes POJO ou des objets JavaBean à l'exécution. Hibernate supporte aussi les
|
||||
modèles dynamiques (en utilisant des <literal>Map</literal>s de <literal>Map</literal>s
|
||||
à l'exécution) et la représentation des entités comme des arbres DOM4J. Avec cette
|
||||
approche, vous n'écrivez pas de classes persistantes, seulement des fichiers de mapping.
|
||||
Les entités persistantes ne doivent pas nécessairement être représentées comme
|
||||
des classes POJO ou des objets JavaBean à l'exécution. Hibernate supporte aussi les
|
||||
modèles dynamiques (en utilisant des <literal>Map</literal>s de <literal>Map</literal>s
|
||||
à l'exécution) et la représentation des entités comme des arbres DOM4J. Avec cette
|
||||
approche, vous n'écrivez pas de classes persistantes, seulement des fichiers de mapping.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Par défaut, Hibernate fonctionne en mode POJO normal. Vous pouvez paramétrer
|
||||
un mode de représentation d'entité par défaut pour une <literal>SessionFactory</literal>
|
||||
particulière en utilisant l'option de configuration <literal>default_entity_mode</literal>
|
||||
Par défaut, Hibernate fonctionne en mode POJO normal. Vous pouvez paramétrer
|
||||
un mode de représentation d'entité par défaut pour une <literal>SessionFactory</literal>
|
||||
particulière en utilisant l'option de configuration <literal>default_entity_mode</literal>
|
||||
(voir <xref linkend="configuration-optional-properties"/>).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Les exemples suivants démontrent la représentation utilisant des <literal>Map</literal>s.
|
||||
D'abord, dans le fichier de mapping, un <literal>entity-name</literal> doit être déclaré
|
||||
Les exemples suivants démontrent la représentation utilisant des <literal>Map</literal>s.
|
||||
D'abord, dans le fichier de mapping, un <literal>entity-name</literal> doit être déclaré
|
||||
au lieu (ou en plus) d'un nom de classe :
|
||||
</para>
|
||||
|
||||
|
@ -385,13 +387,13 @@ public class DomesticCat extends Cat {
|
|||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Notez que même si des associations sont déclarées en utilisant des noms de classe cible,
|
||||
le type de cible d'une association peut aussi être une entité dynamique au lieu d'un POJO.
|
||||
Notez que même si des associations sont déclarées en utilisant des noms de classe cible,
|
||||
le type de cible d'une association peut aussi être une entité dynamique au lieu d'un POJO.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Après avoir configuré le mode d'entité par défaut à <literal>dynamic-map</literal>
|
||||
pour la <literal>SessionFactory</literal>, nous pouvons lors de l'exécution fonctionner
|
||||
Après avoir configuré le mode d'entité par défaut à <literal>dynamic-map</literal>
|
||||
pour la <literal>SessionFactory</literal>, nous pouvons lors de l'exécution fonctionner
|
||||
avec des <literal>Map</literal>s de <literal>Map</literal>s :
|
||||
</para>
|
||||
|
||||
|
@ -419,15 +421,15 @@ s.close();]]></programlisting>
|
|||
|
||||
<para>
|
||||
Les avantages d'un mapping dynamique sont un gain de temps pour le prototypage
|
||||
sans la nécessité d'implémenter les classes d'entité. Pourtant, vous perdez la
|
||||
vérification du typage au moment de la compilation et aurez plus d'exceptions à
|
||||
gérer lors de l'exécution. Grâce au mapping d'Hibernate, le schéma de la base de
|
||||
données peut facilement être normalisé et solidifié, permettant de rajouter une
|
||||
implémentation propre du modèle de domaine plus tard.
|
||||
sans la nécessité d'implémenter les classes d'entité. Pourtant, vous perdez la
|
||||
vérification du typage au moment de la compilation et aurez plus d'exceptions à
|
||||
gérer lors de l'exécution. Grâce au mapping d'Hibernate, le schéma de la base de
|
||||
données peut facilement être normalisé et solidifié, permettant de rajouter une
|
||||
implémentation propre du modèle de domaine plus tard.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Les modes de représentation d'une entité peut aussi être configuré par <literal>Session</literal> :
|
||||
Les modes de représentation d'une entité peut aussi être configuré par <literal>Session</literal> :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
|
||||
|
@ -445,17 +447,17 @@ dynamicSession.close()
|
|||
|
||||
|
||||
<para>
|
||||
Veuillez noter que l'appel à <literal>getSession()</literal> en utilisant un
|
||||
Veuillez noter que l'appel à <literal>getSession()</literal> en utilisant un
|
||||
<literal>EntityMode</literal> se fait sur l'API <literal>Session</literal>, pas
|
||||
<literal>SessionFactory</literal>. De cette manière, la nouvelle <literal>Session</literal>
|
||||
<literal>SessionFactory</literal>. De cette manière, la nouvelle <literal>Session</literal>
|
||||
partage les connexions JDBC, transactions et autres informations de contexte sous-jacentes.
|
||||
Cela signifie que vous n'avez pas à appeler <literal>flush()</literal> et <literal>close()</literal>
|
||||
Cela signifie que vous n'avez pas à appeler <literal>flush()</literal> et <literal>close()</literal>
|
||||
sur la <literal>Session</literal> secondaire, et laissez aussi la gestion de la transaction
|
||||
et de la connexion à l'unité de travail primaire.
|
||||
et de la connexion à l'unité de travail primaire.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Plus d'informations à propos de la représentation XML peuvent être trouvées dans
|
||||
Plus d'informations à propos de la représentation XML peuvent être trouvées dans
|
||||
<xref linkend="xml"/>.
|
||||
</para>
|
||||
|
||||
|
@ -466,27 +468,27 @@ dynamicSession.close()
|
|||
|
||||
<para>
|
||||
<literal>org.hibernate.tuple.Tuplizer</literal>, et ses sous-interfaces, sont responsables
|
||||
de la gestion d'une représentation particulière d'un morceau de données, en fonction du
|
||||
<literal>org.hibernate.EntityMode</literal> de réprésentation. Si un morceau donné de données
|
||||
est pensé comme une structure de données, alors un tuplizer est la chose qui sait comment
|
||||
créer une telle structure de données, comment extraire des valeurs et injecter des valeurs dans
|
||||
une telle structure de données. Par exemple, pour le mode d'entité POJO, le tuplizer correspondant
|
||||
sait comment créer le POJO à travers son constructeur et comment accéder aux propriétés du POJO
|
||||
utilisant les accesseurs de la propriété définie. Il y a deux types de Tuplizers haut niveau,
|
||||
représenté par les interfaces <literal>org.hibernate.tuple.EntityTuplizer</literal> et
|
||||
de la gestion d'une représentation particulière d'un morceau de données, en fonction du
|
||||
<literal>org.hibernate.EntityMode</literal> de réprésentation. Si un morceau donné de données
|
||||
est pensé comme une structure de données, alors un tuplizer est la chose qui sait comment
|
||||
créer une telle structure de données, comment extraire des valeurs et injecter des valeurs dans
|
||||
une telle structure de données. Par exemple, pour le mode d'entité POJO, le tuplizer correspondant
|
||||
sait comment créer le POJO à travers son constructeur et comment accéder aux propriétés du POJO
|
||||
utilisant les accesseurs de la propriété définie. Il y a deux types de Tuplizers haut niveau,
|
||||
représenté par les interfaces <literal>org.hibernate.tuple.EntityTuplizer</literal> et
|
||||
<literal>org.hibernate.tuple.ComponentTuplizer</literal>. Les <literal>EntityTuplizer</literal>s
|
||||
sont responsables de la gestion des contrats mentionnés ci-dessus pour les entités, alors que
|
||||
sont responsables de la gestion des contrats mentionnés ci-dessus pour les entités, alors que
|
||||
les <literal>ComponentTuplizer</literal>s s'occupent des composants.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Les utilisateurs peuvent aussi brancher leurs propres tuplizers. Peut-être vous est-il nécessaire qu'une
|
||||
implémentation de <literal>java.util.Map</literal> autre que <literal>java.util.HashMap</literal>
|
||||
soit utilisée dans le mode d'entité dynamic-map ; ou peut-être avez-vous besoin de définir une
|
||||
statégie de génération de proxy différente de celle utilisée par défaut. Les deux devraient être
|
||||
effectuées en définissant une implémentation de tuplizer utilisateur. Les définitions de tuplizers
|
||||
sont attachées au mapping de l'entité ou du composant qu'ils sont censés gérer. Retour à l'exemple de
|
||||
notre entité utilisateur :
|
||||
Les utilisateurs peuvent aussi brancher leurs propres tuplizers. Peut-être vous est-il nécessaire qu'une
|
||||
implémentation de <literal>java.util.Map</literal> autre que <literal>java.util.HashMap</literal>
|
||||
soit utilisée dans le mode d'entité dynamic-map ; ou peut-être avez-vous besoin de définir une
|
||||
statégie de génération de proxy différente de celle utilisée par défaut. Les deux devraient être
|
||||
effectuées en définissant une implémentation de tuplizer utilisateur. Les définitions de tuplizers
|
||||
sont attachées au mapping de l'entité ou du composant qu'ils sont censés gérer. Retour à l'exemple de
|
||||
notre entité utilisateur :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<?xml version='1.0'?>
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<preface id="preface">
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="querycriteria">
|
||||
<title>Requêtes par critères</title>
|
||||
<title>Requêtes par critères</title>
|
||||
|
||||
<para>
|
||||
Hibernate offre une API d'interrogation par critères intuitive et extensible.
|
||||
Hibernate offre une API d'interrogation par critères intuitive et extensible.
|
||||
</para>
|
||||
|
||||
<sect1 id="querycriteria-creating">
|
||||
<title>Créer une instance de <literal>Criteria</literal></title>
|
||||
<title>Créer une instance de <literal>Criteria</literal></title>
|
||||
|
||||
<para>
|
||||
L'interface <literal>net.sf.hibernate.Criteria</literal> représente une requête sur une
|
||||
classe persistente donnée. La <literal>Session</literal> fournit les instances de
|
||||
L'interface <literal>net.sf.hibernate.Criteria</literal> représente une requête sur une
|
||||
classe persistente donnée. La <literal>Session</literal> fournit les instances de
|
||||
<literal>Criteria</literal>.
|
||||
</para>
|
||||
|
||||
|
@ -22,14 +24,14 @@ List cats = crit.list();]]></programlisting>
|
|||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-narrowing">
|
||||
<title>Restriction du résultat</title>
|
||||
<title>Restriction du résultat</title>
|
||||
|
||||
<para>
|
||||
Un criterion (critère de recherche) est une instance de l'interface
|
||||
Un criterion (critère de recherche) est une instance de l'interface
|
||||
<literal>org.hibernate.criterion.Criterion</literal>. La classe
|
||||
<literal>org.hibernate.criterion.Restrictions</literal> définit
|
||||
des méthodes pour obtenir des types de <literal>Criterion</literal>
|
||||
pré-définis.
|
||||
<literal>org.hibernate.criterion.Restrictions</literal> définit
|
||||
des méthodes pour obtenir des types de <literal>Criterion</literal>
|
||||
pré-définis.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
|
@ -38,7 +40,7 @@ List cats = crit.list();]]></programlisting>
|
|||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Les restrictions peuvent être goupées de manière logique.
|
||||
Les restrictions peuvent être goupées de manière logique.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
|
@ -60,8 +62,8 @@ List cats = crit.list();]]></programlisting>
|
|||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Il y a plusieurs types de criterion pré-définis (sous classes de <literal>Restriction</literal>),
|
||||
mais l'une d'entre elle particulièrement utile vous permet de spécifier directement
|
||||
Il y a plusieurs types de criterion pré-définis (sous classes de <literal>Restriction</literal>),
|
||||
mais l'une d'entre elle particulièrement utile vous permet de spécifier directement
|
||||
du SQL.
|
||||
</para>
|
||||
|
||||
|
@ -70,13 +72,13 @@ List cats = crit.list();]]></programlisting>
|
|||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
La zone <literal>{alias}</literal> sera remplacée par l'alias de colonne de l'entité
|
||||
que l'on souhaite intérroger.
|
||||
La zone <literal>{alias}</literal> sera remplacée par l'alias de colonne de l'entité
|
||||
que l'on souhaite intérroger.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Une autre approche pour obtenir un criterion est de le récupérer d'une instance de <literal>Property</literal>.
|
||||
Vous pouvez créer une <literal>Property</literal> en appelant <literal>Property.forName()</literal>.
|
||||
Une autre approche pour obtenir un criterion est de le récupérer d'une instance de <literal>Property</literal>.
|
||||
Vous pouvez créer une <literal>Property</literal> en appelant <literal>Property.forName()</literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
|
@ -94,10 +96,10 @@ List cats = sess.createCriteria(Cat.class)
|
|||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-ordering">
|
||||
<title>Trier les résultats</title>
|
||||
<title>Trier les résultats</title>
|
||||
|
||||
<para>
|
||||
Vous pouvez trier les résultats en utilisant <literal>org.hibernate.criterion.Order</literal>.
|
||||
Vous pouvez trier les résultats en utilisant <literal>org.hibernate.criterion.Order</literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
|
@ -120,7 +122,7 @@ List cats = sess.createCriteria(Cat.class)
|
|||
<title>Associations</title>
|
||||
|
||||
<para>
|
||||
Vous pouvez facilement spécifier des contraintes sur des entités liées,
|
||||
Vous pouvez facilement spécifier des contraintes sur des entités liées,
|
||||
par des associations en utilisant <literal>createCriteria()</literal>.
|
||||
</para>
|
||||
|
||||
|
@ -132,7 +134,7 @@ List cats = sess.createCriteria(Cat.class)
|
|||
|
||||
<para>
|
||||
Notez que la seconde <literal>createCriteria()</literal> retourne une nouvelle
|
||||
instance de <literal>Criteria</literal>, qui se rapporte aux éléments de la
|
||||
instance de <literal>Criteria</literal>, qui se rapporte aux éléments de la
|
||||
collection <literal>kittens</literal>.
|
||||
</para>
|
||||
|
||||
|
@ -147,14 +149,14 @@ List cats = sess.createCriteria(Cat.class)
|
|||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
(<literal>createAlias()</literal> ne crée pas de nouvelle instance de
|
||||
(<literal>createAlias()</literal> ne crée pas de nouvelle instance de
|
||||
<literal>Criteria</literal>.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Notez que les collections kittens contenues dans les instances de <literal>Cat</literal>
|
||||
retournées par les deux précédentes requêtes ne sont <emphasis>pas</emphasis> pré-filtrées
|
||||
par les critères ! Si vous souhaitez récupérer uniquement les kittens qui correspondent à la
|
||||
retournées par les deux précédentes requêtes ne sont <emphasis>pas</emphasis> pré-filtrées
|
||||
par les critères ! Si vous souhaitez récupérer uniquement les kittens qui correspondent à la
|
||||
criteria, vous devez utiliser <literal>ResultTransformer</literal>.
|
||||
</para>
|
||||
|
||||
|
@ -173,11 +175,11 @@ while ( iter.hasNext() ) {
|
|||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-dynamicfetching" revision="1">
|
||||
<title>Peuplement d'associations de manière dynamique</title>
|
||||
<title>Peuplement d'associations de manière dynamique</title>
|
||||
|
||||
<para>
|
||||
Vous pouvez spéficier au moment de l'exécution le peuplement d'une association en utilisant
|
||||
<literal>setFetchMode()</literal> (c'est-à-dire le chargement de celle-ci).
|
||||
Vous pouvez spéficier au moment de l'exécution le peuplement d'une association en utilisant
|
||||
<literal>setFetchMode()</literal> (c'est-à-dire le chargement de celle-ci).
|
||||
Cela permet de surcharger les valeurs
|
||||
"lazy" et "outer-join" du mapping.
|
||||
</para>
|
||||
|
@ -189,18 +191,18 @@ while ( iter.hasNext() ) {
|
|||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Cette requête recherchera <literal>mate</literal> et <literal>kittens</literal>
|
||||
Cette requête recherchera <literal>mate</literal> et <literal>kittens</literal>
|
||||
via les jointures externes. Voir <xref linkend="performance-fetching"/> pour plus d'informations.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-examples">
|
||||
<title>Requêtes par l'exemple</title>
|
||||
<title>Requêtes par l'exemple</title>
|
||||
|
||||
<para>
|
||||
La classe <literal>org.hibernate.criterion.Example</literal> vous permet de
|
||||
construire un critère suivant une instance d'objet donnée.
|
||||
construire un critère suivant une instance d'objet donnée.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Cat cat = new Cat();
|
||||
|
@ -211,12 +213,12 @@ List results = session.createCriteria(Cat.class)
|
|||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Les propriétés de type version, identifiant et association sont ignorées.
|
||||
Par défaut, les valeurs null sont exclues.
|
||||
Les propriétés de type version, identifiant et association sont ignorées.
|
||||
Par défaut, les valeurs null sont exclues.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Vous pouvez ajuster la stratégie d'utilisation de valeurs de
|
||||
Vous pouvez ajuster la stratégie d'utilisation de valeurs de
|
||||
l'<literal>Exemple</literal>.
|
||||
</para>
|
||||
|
||||
|
@ -230,7 +232,7 @@ List results = session.createCriteria(Cat.class)
|
|||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Vous pouvez utiliser les "exemples" pour des critères sur les objets associés.
|
||||
Vous pouvez utiliser les "exemples" pour des critères sur les objets associés.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
|
@ -242,11 +244,11 @@ List results = session.createCriteria(Cat.class)
|
|||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-projection">
|
||||
<title>Projections, agrégation et regroupement</title>
|
||||
<title>Projections, agrégation et regroupement</title>
|
||||
<para>
|
||||
La classe <literal>org.hibernate.criterion.Projections</literal> est une
|
||||
fabrique d'instances de <literal>Projection</literal>. Nous appliquons une
|
||||
projection sur une requête en appelant <literal>setProjection()</literal>.
|
||||
projection sur une requête en appelant <literal>setProjection()</literal>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
|
@ -264,16 +266,16 @@ List results = session.createCriteria(Cat.class)
|
|||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Il n'y a pas besoin de "group by" explicite dans une requête par critère.
|
||||
Certains types de projection sont définis pour être des <emphasis>projections
|
||||
Il n'y a pas besoin de "group by" explicite dans une requête par critère.
|
||||
Certains types de projection sont définis pour être des <emphasis>projections
|
||||
de regroupement</emphasis>, lesquels apparaissent aussi dans la clause
|
||||
<literal>group by</literal> SQL.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Un alias peut optionnellement être assigné à une projection, ainsi la valeur
|
||||
projetée peut être référencée dans des restrictions ou des tris. Voici deux façons
|
||||
différentes de faire ça :
|
||||
Un alias peut optionnellement être assigné à une projection, ainsi la valeur
|
||||
projetée peut être référencée dans des restrictions ou des tris. Voici deux façons
|
||||
différentes de faire ça :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
|
@ -287,9 +289,9 @@ List results = session.createCriteria(Cat.class)
|
|||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Les méthodes <literal>alias()</literal> et <literal>as()</literal> enveloppe simplement
|
||||
une instance de projection dans une autre instance (aliasée) de <literal>Projection</literal>.
|
||||
Comme un raccourci, vous pouvez assignez un alias lorsque vous ajoutez la projection à la
|
||||
Les méthodes <literal>alias()</literal> et <literal>as()</literal> enveloppe simplement
|
||||
une instance de projection dans une autre instance (aliasée) de <literal>Projection</literal>.
|
||||
Comme un raccourci, vous pouvez assignez un alias lorsque vous ajoutez la projection à la
|
||||
liste de projections :
|
||||
</para>
|
||||
|
||||
|
@ -337,10 +339,10 @@ List results = session.createCriteria(Cat.class)
|
|||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-detachedqueries">
|
||||
<title>Requêtes et sous-requêtes détachées</title>
|
||||
<title>Requêtes et sous-requêtes détachées</title>
|
||||
<para>
|
||||
La classe <literal>DetachedCriteria</literal> vous laisse créer une requête en dehors de la
|
||||
portée de la session, et puis l'exécuter plus tard en utilisant n'importe quelle <literal>Session</literal>
|
||||
La classe <literal>DetachedCriteria</literal> vous laisse créer une requête en dehors de la
|
||||
portée de la session, et puis l'exécuter plus tard en utilisant n'importe quelle <literal>Session</literal>
|
||||
arbitraire.
|
||||
</para>
|
||||
|
||||
|
@ -354,8 +356,8 @@ txn.commit();
|
|||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Une <literal>DetachedCriteria</literal> peut aussi être utilisée pour exprimer une
|
||||
sous-requête. Des instances de criterion impliquant des sous-requêtes peuvent être
|
||||
Une <literal>DetachedCriteria</literal> peut aussi être utilisée pour exprimer une
|
||||
sous-requête. Des instances de criterion impliquant des sous-requêtes peuvent être
|
||||
obtenues via <literal>Subqueries</literal> ou <literal>Property</literal>.
|
||||
</para>
|
||||
|
||||
|
@ -372,7 +374,7 @@ session.createCriteria(Cat.class)
|
|||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Même des requêtes corrélées sont possibles :
|
||||
Même des requêtes corrélées sont possibles :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
|
||||
|
@ -389,19 +391,19 @@ session.createCriteria(Cat.class, "cat")
|
|||
could also be explained. -->
|
||||
|
||||
<sect1 id="query-criteria-naturalid">
|
||||
<title>Requêtes par identifiant naturel</title>
|
||||
<title>Requêtes par identifiant naturel</title>
|
||||
|
||||
<para>
|
||||
Pour la plupart des requêtes, incluant les requêtes par critère, le cache de requêtes
|
||||
n'est pas très efficace, parce que l'invalidation du cache de requêtes arrive trop
|
||||
souvent. Cependant, il y a une sorte spéciale de requête où nous pouvons optimiser
|
||||
Pour la plupart des requêtes, incluant les requêtes par critère, le cache de requêtes
|
||||
n'est pas très efficace, parce que l'invalidation du cache de requêtes arrive trop
|
||||
souvent. Cependant, il y a une sorte spéciale de requête où nous pouvons optimiser
|
||||
l'algorithme d'invalidation du cache : les recherches sur une clef naturelle constante.
|
||||
Dans certaines applications, cette sorte de requête se produit fréquemment. L'API de
|
||||
critère fournit une provision spéciale pour ce cas d'utilisation.
|
||||
Dans certaines applications, cette sorte de requête se produit fréquemment. L'API de
|
||||
critère fournit une provision spéciale pour ce cas d'utilisation.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
D'abord vous devriez mapper la clef naturelle de votre entité en utilisant
|
||||
D'abord vous devriez mapper la clef naturelle de votre entité en utilisant
|
||||
<literal><natural-id></literal>, et activer l'utilisation du cache de second niveau.
|
||||
</para>
|
||||
|
||||
|
@ -418,12 +420,12 @@ session.createCriteria(Cat.class, "cat")
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Notez que cette fonctionnalité n'est pas prévue pour l'utilisation avec des
|
||||
entités avec des clefs naturelles <emphasis>mutables</emphasis>.
|
||||
Notez que cette fonctionnalité n'est pas prévue pour l'utilisation avec des
|
||||
entités avec des clefs naturelles <emphasis>mutables</emphasis>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Ensuite, activez le cache de requête d'Hibernate.
|
||||
Ensuite, activez le cache de requête d'Hibernate.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,46 +1,48 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="querysql" revision="2">
|
||||
<title>SQL natif</title>
|
||||
|
||||
<para>
|
||||
Vous pouvez aussi écrire vos requêtes dans le dialecte SQL natif de votre base de données.
|
||||
Ceci est utile si vous souhaitez utiliser les fonctionnalités spécifiques de votre base de
|
||||
données comme le mot clé <literal>CONNECT</literal> d'Oracle. Cette fonctionnalité offre par ailleurs un moyen
|
||||
de migration plus propre et doux d'une application basée sur SQL/JDBC vers
|
||||
Vous pouvez aussi écrire vos requêtes dans le dialecte SQL natif de votre base de données.
|
||||
Ceci est utile si vous souhaitez utiliser les fonctionnalités spécifiques de votre base de
|
||||
données comme le mot clé <literal>CONNECT</literal> d'Oracle. Cette fonctionnalité offre par ailleurs un moyen
|
||||
de migration plus propre et doux d'une application basée sur SQL/JDBC vers
|
||||
une application Hibernate.
|
||||
</para>
|
||||
|
||||
<para>Hibernate3 vous permet de spécifier du SQL écrit à la main (incluant les procédures stockées)
|
||||
pour toutes les opérations de création, mise à jour, suppression et chargement.</para>
|
||||
<para>Hibernate3 vous permet de spécifier du SQL écrit à la main (incluant les procédures stockées)
|
||||
pour toutes les opérations de création, mise à jour, suppression et chargement.</para>
|
||||
|
||||
<sect1 id="querysql-creating" revision="3">
|
||||
<title>Utiliser une <literal>SQLQuery</literal></title>
|
||||
|
||||
<para>L'exécution des requêtes en SQL natif est contrôlée par l'interface <literal>SQLQuery</literal>,
|
||||
<para>L'exécution des requêtes en SQL natif est contrôlée par l'interface <literal>SQLQuery</literal>,
|
||||
laquelle est obtenue en appelant <literal>Session.createSQLQuery()</literal>.
|
||||
Dans des cas extrêmement simples, nous pouvons utiliser la forme suivante :
|
||||
Dans des cas extrêmement simples, nous pouvons utiliser la forme suivante :
|
||||
</para>
|
||||
|
||||
<programlisting>List cats = sess.createSQLQuery("select * from cats")
|
||||
.addEntity(Cat.class)
|
||||
.list();</programlisting>
|
||||
|
||||
<para>Cette requête a spécifié :</para>
|
||||
<para>Cette requête a spécifié :</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>la requête SQL</para>
|
||||
<para>la requête SQL</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>l'entité retournée par la requête</para>
|
||||
<para>l'entité retournée par la requête</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Ici, les noms de colonne des résultats sont supposés être les mêmes que les noms de colonne spécifiés dans le
|
||||
document de mapping. Cela peut être problématique pour des requêtes SQL qui joignent de multiple tables, puisque
|
||||
les mêmes noms de colonne peuvent apparaître dans plus d'une table. La forme suivante n'est pas vulnérable à la
|
||||
Ici, les noms de colonne des résultats sont supposés être les mêmes que les noms de colonne spécifiés dans le
|
||||
document de mapping. Cela peut être problématique pour des requêtes SQL qui joignent de multiple tables, puisque
|
||||
les mêmes noms de colonne peuvent apparaître dans plus d'une table. La forme suivante n'est pas vulnérable à la
|
||||
duplication des noms de colonne :
|
||||
</para>
|
||||
|
||||
|
@ -48,26 +50,26 @@
|
|||
.addEntity("cat", Cat.class)
|
||||
.list();</programlisting>
|
||||
|
||||
<para>Cette requête a spécifié :</para>
|
||||
<para>Cette requête a spécifié :</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>la requête SQL, avec un paramètre fictif pour Hibernate pour injecter les alias de colonne</para>
|
||||
<para>la requête SQL, avec un paramètre fictif pour Hibernate pour injecter les alias de colonne</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>l'entité retournée par la requête, et son alias de table SQL</para>
|
||||
<para>l'entité retournée par la requête, et son alias de table SQL</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
La méthode <literal>addEntity()</literal> associe l'alias de la table SQL
|
||||
avec la classe de l'entité retournée, et détermine la forme de l'ensemble des résultats de la requête.
|
||||
La méthode <literal>addEntity()</literal> associe l'alias de la table SQL
|
||||
avec la classe de l'entité retournée, et détermine la forme de l'ensemble des résultats de la requête.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
La méthode <literal>addJoin()</literal> peut être utilisée pour charger des associations vers d'autres
|
||||
entités et collections.
|
||||
La méthode <literal>addJoin()</literal> peut être utilisée pour charger des associations vers d'autres
|
||||
entités et collections.
|
||||
</para>
|
||||
|
||||
<programlisting>List cats = sess.createSQLQuery(
|
||||
|
@ -78,15 +80,15 @@
|
|||
.list();</programlisting>
|
||||
|
||||
<para>
|
||||
Une requête SQL native pourrait retourner une simple valeur scalaire ou une combinaison de scalaires et d'entités.
|
||||
Une requête SQL native pourrait retourner une simple valeur scalaire ou une combinaison de scalaires et d'entités.
|
||||
</para>
|
||||
|
||||
<programlisting>Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")
|
||||
.addScalar("maxWeight", Hibernate.DOUBLE);
|
||||
.uniqueResult();</programlisting>
|
||||
|
||||
<para>Vous pouvez alternativement décrire les informations de mapping des résultats dans vos fichiers hbm
|
||||
et les utiliser pour vos requêtes.</para>
|
||||
<para>Vous pouvez alternativement décrire les informations de mapping des résultats dans vos fichiers hbm
|
||||
et les utiliser pour vos requêtes.</para>
|
||||
|
||||
<programlisting>List cats = sess.createSQLQuery(
|
||||
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
|
||||
|
@ -96,20 +98,20 @@
|
|||
</sect1>
|
||||
|
||||
<sect1 id="querysql-aliasreferences">
|
||||
<title>Alias et références de propriété</title>
|
||||
<title>Alias et références de propriété</title>
|
||||
|
||||
<para>
|
||||
La notation <literal>{cat.*}</literal> utilisée au-dessus est un raccourci pour "toutes les propriétés".
|
||||
Alternativement, vous pouvez lister explicitement les colonnes, mais même ce cas que nous laissons à Hibernate
|
||||
injecte des alias de colonne SQL pour chaque propriété. Le remplaçant pour un alias de colonne
|
||||
est juste le nom de la propriété qualifié par l'alias de la table.
|
||||
Dans l'exemple suivant, nous récupérons des <literal>Cat</literal>s à partir d'une table différente
|
||||
(<literal>cat_log</literal>) de celle déclarée dans les méta-données de mapping.
|
||||
Notez que nous pouvons même utiliser les alias de propriété dans la clause "where" si nous le souhaitons.
|
||||
La notation <literal>{cat.*}</literal> utilisée au-dessus est un raccourci pour "toutes les propriétés".
|
||||
Alternativement, vous pouvez lister explicitement les colonnes, mais même ce cas que nous laissons à Hibernate
|
||||
injecte des alias de colonne SQL pour chaque propriété. Le remplaçant pour un alias de colonne
|
||||
est juste le nom de la propriété qualifié par l'alias de la table.
|
||||
Dans l'exemple suivant, nous récupérons des <literal>Cat</literal>s à partir d'une table différente
|
||||
(<literal>cat_log</literal>) de celle déclarée dans les méta-données de mapping.
|
||||
Notez que nous pouvons même utiliser les alias de propriété dans la clause "where" si nous le souhaitons.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
La syntaxe <literal>{}</literal> <emphasis>n'est pas</emphasis> requise pour le requêtes nommées. Voir
|
||||
La syntaxe <literal>{}</literal> <emphasis>n'est pas</emphasis> requise pour le requêtes nommées. Voir
|
||||
<xref linkend="querysql-namedqueries" />.
|
||||
</para>
|
||||
|
||||
|
@ -124,13 +126,13 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
.list();</programlisting>
|
||||
|
||||
<para>
|
||||
<emphasis>À noter :</emphasis> si vous listez chaque propriété explicitement, vous devez inclure
|
||||
toutes les propriétés de la classe <emphasis>et ses sous-classes</emphasis> !
|
||||
<emphasis>À noter :</emphasis> si vous listez chaque propriété explicitement, vous devez inclure
|
||||
toutes les propriétés de la classe <emphasis>et ses sous-classes</emphasis> !
|
||||
</para>
|
||||
|
||||
<para>
|
||||
La table suivante montre les différentes possibilités d'utilisation de l'injection d'alias. À noter : les noms
|
||||
des alias dans le résultat sont des exemples, chaque alias aura un nom unique et probablement différent lors de l'utilisation.
|
||||
La table suivante montre les différentes possibilités d'utilisation de l'injection d'alias. À noter : les noms
|
||||
des alias dans le résultat sont des exemples, chaque alias aura un nom unique et probablement différent lors de l'utilisation.
|
||||
</para>
|
||||
|
||||
<table frame="topbot" id="aliasinjection-summary">
|
||||
|
@ -155,7 +157,7 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Une simple propriété</entry>
|
||||
<entry>Une simple propriété</entry>
|
||||
|
||||
<entry><literal>{[aliasname].[propertyname]}</literal></entry>
|
||||
|
||||
|
@ -163,7 +165,7 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Une propriété composée</entry>
|
||||
<entry>Une propriété composée</entry>
|
||||
|
||||
<entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
|
||||
|
||||
|
@ -172,7 +174,7 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Discriminant d'une entité</entry>
|
||||
<entry>Discriminant d'une entité</entry>
|
||||
|
||||
<entry><literal>{[aliasname].class}</literal></entry>
|
||||
|
||||
|
@ -180,7 +182,7 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Toutes les propriétés d'une entité</entry>
|
||||
<entry>Toutes les propriétés d'une entité</entry>
|
||||
|
||||
<entry><literal>{[aliasname].*}</literal></entry>
|
||||
|
||||
|
@ -204,7 +206,7 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
</row>
|
||||
|
||||
<row>
|
||||
<entry>L'élément d'une collection</entry>
|
||||
<entry>L'élément d'une collection</entry>
|
||||
|
||||
<entry><literal>{[aliasname].element}</literal></entry>
|
||||
|
||||
|
@ -214,7 +216,7 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Propriété de l'élément dans la collection</entry>
|
||||
<entry>Propriété de l'élément dans la collection</entry>
|
||||
|
||||
<entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
|
||||
|
||||
|
@ -222,7 +224,7 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Toutes les propriétés de l'élément dans la collection</entry>
|
||||
<entry>Toutes les propriétés de l'élément dans la collection</entry>
|
||||
|
||||
<entry><literal>{[aliasname].element.*}</literal></entry>
|
||||
|
||||
|
@ -230,7 +232,7 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Toutes les propriétés de la collection</entry>
|
||||
<entry>Toutes les propriétés de la collection</entry>
|
||||
|
||||
<entry><literal>{[aliasname].*}</literal></entry>
|
||||
|
||||
|
@ -242,11 +244,11 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
</sect1>
|
||||
|
||||
<sect1 id="querysql-namedqueries" revision="3">
|
||||
<title>Requêtes SQL nommées</title>
|
||||
<title>Requêtes SQL nommées</title>
|
||||
|
||||
<para>
|
||||
Les requêtes SQL nommées peuvent être définies dans le document de mapping
|
||||
et appelées exactement de la même manière qu'un requête HQL nommée. Dans ce
|
||||
Les requêtes SQL nommées peuvent être définies dans le document de mapping
|
||||
et appelées exactement de la même manière qu'un requête HQL nommée. Dans ce
|
||||
cas, nous <emphasis>n'avons pas besoin</emphasis> d'appeler <literal>addEntity()</literal>.
|
||||
</para>
|
||||
|
||||
|
@ -265,9 +267,9 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
.list();</programlisting>
|
||||
|
||||
<para>
|
||||
Les éléments <literal><return-join></literal> et
|
||||
<literal><load-collection></literal> sont respectivement utilisés pour lier
|
||||
des associations et définir des requêtes qui initialisent des collections.
|
||||
Les éléments <literal><return-join></literal> et
|
||||
<literal><load-collection></literal> sont respectivement utilisés pour lier
|
||||
des associations et définir des requêtes qui initialisent des collections.
|
||||
</para>
|
||||
|
||||
<programlisting><sql-query name="personsWith">
|
||||
|
@ -287,8 +289,8 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
</sql-query></programlisting>
|
||||
|
||||
<para>
|
||||
Une requête SQL nommée peut retourner une valeur scalaire. Vous devez
|
||||
spécifier l'alias de colonne et le type Hibernate utilisant l'élément
|
||||
Une requête SQL nommée peut retourner une valeur scalaire. Vous devez
|
||||
spécifier l'alias de colonne et le type Hibernate utilisant l'élément
|
||||
<literal><return-scalar></literal> :</para>
|
||||
|
||||
<programlisting><sql-query name="mySqlQuery">
|
||||
|
@ -300,9 +302,9 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
</sql-query></programlisting>
|
||||
|
||||
<para>
|
||||
Vous pouvez externaliser les informations de mapping des résultats dans un
|
||||
élément <literal><resultset></literal> pour soit les réutiliser
|
||||
dans différentes requêtes nommées, soit à travers l'API
|
||||
Vous pouvez externaliser les informations de mapping des résultats dans un
|
||||
élément <literal><resultset></literal> pour soit les réutiliser
|
||||
dans différentes requêtes nommées, soit à travers l'API
|
||||
<literal>setResultSetMapping()</literal>.
|
||||
</para>
|
||||
|
||||
|
@ -326,11 +328,11 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
</sql-query></programlisting>
|
||||
|
||||
<sect2 id="propertyresults">
|
||||
<title>Utilisation de return-property pour spécifier explicitement les noms des colonnes/alias</title>
|
||||
<title>Utilisation de return-property pour spécifier explicitement les noms des colonnes/alias</title>
|
||||
|
||||
<para>
|
||||
Avec <literal><return-property></literal> vous pouvez explicitement dire
|
||||
à Hibernate quels alias de colonne utiliser, plutot que d'employer la syntaxe
|
||||
à Hibernate quels alias de colonne utiliser, plutot que d'employer la syntaxe
|
||||
<literal>{}</literal> pour laisser Hibernate injecter ses propres alias.
|
||||
</para>
|
||||
|
||||
|
@ -349,8 +351,8 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
|
||||
<para>
|
||||
<literal><return-property></literal> fonctionne aussi avec de
|
||||
multiple colonnes. Cela résout une limitation de la syntaxe <literal>{}</literal>
|
||||
qui ne peut pas permettre une bonne granularité des propriétés multi-colonnes.
|
||||
multiple colonnes. Cela résout une limitation de la syntaxe <literal>{}</literal>
|
||||
qui ne peut pas permettre une bonne granularité des propriétés multi-colonnes.
|
||||
</para>
|
||||
|
||||
<programlisting><sql-query name="organizationCurrentEmployments">
|
||||
|
@ -370,28 +372,28 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
</sql-query></programlisting>
|
||||
|
||||
<para>
|
||||
Notez que dans cet exemple nous avons utilisé <literal><return-property></literal>
|
||||
Notez que dans cet exemple nous avons utilisé <literal><return-property></literal>
|
||||
en combinaison avec la syntaxe <literal>{}</literal> pour l'injection. Cela autorise les
|
||||
utilisateurs à choisir comment ils veulent référencer les colonnes et les propriétés.
|
||||
utilisateurs à choisir comment ils veulent référencer les colonnes et les propriétés.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Si votre mapping a un discriminant vous devez utiliser
|
||||
<literal><return-discriminator></literal> pour spécifier la colonne
|
||||
<literal><return-discriminator></literal> pour spécifier la colonne
|
||||
discriminante.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="sp_query" revision="1">
|
||||
<title>Utilisation de procédures stockées pour les requêtes</title>
|
||||
<title>Utilisation de procédures stockées pour les requêtes</title>
|
||||
|
||||
<para>
|
||||
Hibernate 3 introduit le support des requêtes via procédures stockées et les fonctions.
|
||||
Hibernate 3 introduit le support des requêtes via procédures stockées et les fonctions.
|
||||
La documentation suivante est valable pour les deux.
|
||||
Les procédures stockées/fonctions doivent retourner l'ensemble de résultats en tant que
|
||||
premier paramètre sortant (NdT: "out-parameter") pour être capable de fonctionner
|
||||
avec Hibernate. Un exemple d'une telle procédure stockée en Oracle 9 et
|
||||
version supérieure :
|
||||
Les procédures stockées/fonctions doivent retourner l'ensemble de résultats en tant que
|
||||
premier paramètre sortant (NdT: "out-parameter") pour être capable de fonctionner
|
||||
avec Hibernate. Un exemple d'une telle procédure stockée en Oracle 9 et
|
||||
version supérieure :
|
||||
</para>
|
||||
|
||||
<programlisting>CREATE OR REPLACE FUNCTION selectAllEmployments
|
||||
|
@ -407,7 +409,7 @@ BEGIN
|
|||
RETURN st_cursor;
|
||||
END;</programlisting>
|
||||
|
||||
<para>Pour utiliser cette requête dans Hibernate vous avez besoin de la mapper via une requête nommée.</para>
|
||||
<para>Pour utiliser cette requête dans Hibernate vous avez besoin de la mapper via une requête nommée.</para>
|
||||
|
||||
<programlisting><sql-query name="selectAllEmployees_SP" callable="true">
|
||||
<return alias="emp" class="Employment">
|
||||
|
@ -426,52 +428,52 @@ BEGIN
|
|||
</sql-query></programlisting>
|
||||
|
||||
<para>
|
||||
Notez que les procédures stockées retournent, pour le moment, seulement des
|
||||
scalaires et des entités. <literal><return-join></literal> et
|
||||
<literal><load-collection></literal> ne sont pas supportés.
|
||||
Notez que les procédures stockées retournent, pour le moment, seulement des
|
||||
scalaires et des entités. <literal><return-join></literal> et
|
||||
<literal><load-collection></literal> ne sont pas supportés.
|
||||
</para>
|
||||
|
||||
<sect3 id="querysql-limits-storedprocedures" revision="1">
|
||||
<title>Règles/limitations lors de l'utilisation des procédures stockées</title>
|
||||
<title>Règles/limitations lors de l'utilisation des procédures stockées</title>
|
||||
|
||||
<para>
|
||||
Pur utiliser des procédures stockées avec Hibernate, les procédures doivent
|
||||
suivre certaines règles. Si elles ne suivent pas ces règles, elles ne sont pas
|
||||
utilisables avec Hibernate. Si vous voulez encore utiliser ces procédures vous
|
||||
devez les exécuter via <literal>session.connection()</literal>. Les règles
|
||||
sont différentes pour chaque base de données, puisque les vendeurs de base
|
||||
de données ont des sémantiques/syntaxes différentes pour les procédures stockées.
|
||||
Pur utiliser des procédures stockées avec Hibernate, les procédures doivent
|
||||
suivre certaines règles. Si elles ne suivent pas ces règles, elles ne sont pas
|
||||
utilisables avec Hibernate. Si vous voulez encore utiliser ces procédures vous
|
||||
devez les exécuter via <literal>session.connection()</literal>. Les règles
|
||||
sont différentes pour chaque base de données, puisque les vendeurs de base
|
||||
de données ont des sémantiques/syntaxes différentes pour les procédures stockées.
|
||||
</para>
|
||||
|
||||
<para>Les requêtes de procédures stockées ne peuvent pas être paginées avec
|
||||
<para>Les requêtes de procédures stockées ne peuvent pas être paginées avec
|
||||
<literal>setFirstResult()/setMaxResults()</literal>.</para>
|
||||
|
||||
<para>Pour Oracle les règles suivantes s'appliquent :</para>
|
||||
<para>Pour Oracle les règles suivantes s'appliquent :</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
La procédure doit retourner un ensemble de résultats. Le
|
||||
prmeier paramètre d'une procédure doit être un <literal>OUT</literal>
|
||||
qui retourne un ensemble de résultats. Ceci est fait en
|
||||
La procédure doit retourner un ensemble de résultats. Le
|
||||
prmeier paramètre d'une procédure doit être un <literal>OUT</literal>
|
||||
qui retourne un ensemble de résultats. Ceci est fait en
|
||||
retournant un <literal>SYS_REFCURSOR</literal> dans Oracle 9 ou 10. Dans
|
||||
Oracle vous avez besoin de définir un type <literal>REF CURSOR</literal>.</para>
|
||||
Oracle vous avez besoin de définir un type <literal>REF CURSOR</literal>.</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
<para>Pour Sybase ou MS SQL server les règles suivantes s'appliquent :</para>
|
||||
<para>Pour Sybase ou MS SQL server les règles suivantes s'appliquent :</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>La procédure doit retourner un ensemble de résultats. Notez que comme
|
||||
ces serveurs peuvent retourner de multiples ensembles de résultats et mettre à jour
|
||||
des compteurs, Hibernate itérera les résultats et prendra le premier résultat qui est
|
||||
un ensemble de résultat comme valeur de retour. Tout le reste sera ignoré.</para>
|
||||
<para>La procédure doit retourner un ensemble de résultats. Notez que comme
|
||||
ces serveurs peuvent retourner de multiples ensembles de résultats et mettre à jour
|
||||
des compteurs, Hibernate itérera les résultats et prendra le premier résultat qui est
|
||||
un ensemble de résultat comme valeur de retour. Tout le reste sera ignoré.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Si vous pouvez activer <literal>SET NOCOUNT ON</literal> dans votre procédure,
|
||||
<para>Si vous pouvez activer <literal>SET NOCOUNT ON</literal> dans votre procédure,
|
||||
elle sera probablement plus efficace, mais ce n'est pas une obligation.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
@ -480,16 +482,16 @@ BEGIN
|
|||
</sect1>
|
||||
|
||||
<sect1 id="querysql-cud">
|
||||
<title>SQL personnalisé pour créer, mettre à jour et effacer</title>
|
||||
<title>SQL personnalisé pour créer, mettre à jour et effacer</title>
|
||||
|
||||
<para>
|
||||
Hibernate3 peut utiliser des expression SQL personnalisées pour des opérations de création,
|
||||
de mise à jour, et de suppression. Les objets persistants les classes et les collections
|
||||
dans Hibernate contiennent déjà un ensemble de chaînes de caractères générées lors de la
|
||||
Hibernate3 peut utiliser des expression SQL personnalisées pour des opérations de création,
|
||||
de mise à jour, et de suppression. Les objets persistants les classes et les collections
|
||||
dans Hibernate contiennent déjà un ensemble de chaînes de caractères générées lors de la
|
||||
configuration (insertsql, deletesql, updatesql, etc). Les tages de mapping
|
||||
<literal><sql-insert></literal>,
|
||||
<literal><sql-delete></literal>, et
|
||||
<literal><sql-update></literal> surchargent ces chaînes de caractères :</para>
|
||||
<literal><sql-update></literal> surchargent ces chaînes de caractères :</para>
|
||||
|
||||
<programlisting><class name="Person">
|
||||
<id name="id">
|
||||
|
@ -501,11 +503,11 @@ BEGIN
|
|||
<sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
|
||||
</class></programlisting>
|
||||
|
||||
<para>Le SQL est directement exécuté dans votre base de données, donc vous êtes libre d'utiliser
|
||||
le dialecte que vous souhaitez. Cela réduira bien sûr la portabilité de votre mapping si vous
|
||||
utilisez du SQL spécifique à votre base de données.</para>
|
||||
<para>Le SQL est directement exécuté dans votre base de données, donc vous êtes libre d'utiliser
|
||||
le dialecte que vous souhaitez. Cela réduira bien sûr la portabilité de votre mapping si vous
|
||||
utilisez du SQL spécifique à votre base de données.</para>
|
||||
|
||||
<para>Les procédures stockées sont supportées si l'attribut <literal>callable</literal> est paramétré :</para>
|
||||
<para>Les procédures stockées sont supportées si l'attribut <literal>callable</literal> est paramétré :</para>
|
||||
|
||||
<programlisting><class name="Person">
|
||||
<id name="id">
|
||||
|
@ -517,22 +519,22 @@ BEGIN
|
|||
<sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
|
||||
</class></programlisting>
|
||||
|
||||
<para>L'ordre des paramètres positionnels est actuellement vital, car ils doivent être dans la
|
||||
même séquence qu'Hibernate les attend.</para>
|
||||
<para>L'ordre des paramètres positionnels est actuellement vital, car ils doivent être dans la
|
||||
même séquence qu'Hibernate les attend.</para>
|
||||
|
||||
<para>
|
||||
Vous pouvez voir l'ordre attendu en activant les journaux de debug pour le
|
||||
niveau <literal>org.hibernate.persister.entity</literal> level. Avec ce niveau activé,
|
||||
Hibernate imprimera le SQL statique qui est utilisé pour créer, mettre à jour,
|
||||
supprimer, etc. des entités. (Pour voir la séquence attendue, rappelez-vous de ne pas
|
||||
inclure votre SQL personnalisé dans les fichiers de mapping de manière à surcharger le
|
||||
SQL statique généré par Hibernate.)</para>
|
||||
niveau <literal>org.hibernate.persister.entity</literal> level. Avec ce niveau activé,
|
||||
Hibernate imprimera le SQL statique qui est utilisé pour créer, mettre à jour,
|
||||
supprimer, etc. des entités. (Pour voir la séquence attendue, rappelez-vous de ne pas
|
||||
inclure votre SQL personnalisé dans les fichiers de mapping de manière à surcharger le
|
||||
SQL statique généré par Hibernate.)</para>
|
||||
|
||||
<para>Les procédures stockées sont dans la plupart des cas (lire : il vaut mieux le faire)
|
||||
requises pour retourner le nombre de lignes insérées/mises à jour/supprimées, puisque
|
||||
Hibernate fait quelques vérifications de succès lors de l'exécution de l'expression.
|
||||
Hibernate inscrit toujours la première expression comme un paramètre de sortie numérique pour les
|
||||
opérations CUD :</para>
|
||||
<para>Les procédures stockées sont dans la plupart des cas (lire : il vaut mieux le faire)
|
||||
requises pour retourner le nombre de lignes insérées/mises à jour/supprimées, puisque
|
||||
Hibernate fait quelques vérifications de succès lors de l'exécution de l'expression.
|
||||
Hibernate inscrit toujours la première expression comme un paramètre de sortie numérique pour les
|
||||
opérations CUD :</para>
|
||||
|
||||
<programlisting>CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
|
||||
RETURN NUMBER IS
|
||||
|
@ -550,9 +552,9 @@ END updatePerson;</programlisting>
|
|||
</sect1>
|
||||
|
||||
<sect1 id="querysql-load">
|
||||
<title>SQL personnalisé pour le chargement</title>
|
||||
<title>SQL personnalisé pour le chargement</title>
|
||||
|
||||
<para>Vous pouvez aussi déclarer vos propres requêtes SQL (ou HQL) pour le chargement d'entité :</para>
|
||||
<para>Vous pouvez aussi déclarer vos propres requêtes SQL (ou HQL) pour le chargement d'entité :</para>
|
||||
|
||||
<programlisting><sql-query name="person">
|
||||
<return alias="pers" class="Person" lock-mode="upgrade"/>
|
||||
|
@ -562,8 +564,8 @@ END updatePerson;</programlisting>
|
|||
FOR UPDATE
|
||||
</sql-query></programlisting>
|
||||
|
||||
<para>Ceci est juste une déclaration de requête nommée, comme vu plus tôt. Vous pouvez référencer
|
||||
cette requête nommée dans un mapping de classe :</para>
|
||||
<para>Ceci est juste une déclaration de requête nommée, comme vu plus tôt. Vous pouvez référencer
|
||||
cette requête nommée dans un mapping de classe :</para>
|
||||
|
||||
<programlisting><class name="Person">
|
||||
<id name="id">
|
||||
|
@ -573,9 +575,9 @@ END updatePerson;</programlisting>
|
|||
<loader query-ref="person"/>
|
||||
</class></programlisting>
|
||||
|
||||
<para>Ceci fonctionne même avec des procédures stockées.</para>
|
||||
<para>Ceci fonctionne même avec des procédures stockées.</para>
|
||||
|
||||
<para>Vous pouvez même définir une requête pour le chargement d'une collection :</para>
|
||||
<para>Vous pouvez même définir une requête pour le chargement d'une collection :</para>
|
||||
|
||||
<programlisting><set name="employments" inverse="true">
|
||||
<key/>
|
||||
|
@ -591,7 +593,7 @@ END updatePerson;</programlisting>
|
|||
ORDER BY STARTDATE ASC, EMPLOYEE ASC
|
||||
</sql-query></programlisting>
|
||||
|
||||
<para>Vous pourriez même définir un chargeur d'entité qui charge une collection par jointure :</para>
|
||||
<para>Vous pourriez même définir un chargeur d'entité qui charge une collection par jointure :</para>
|
||||
|
||||
<programlisting><sql-query name="person">
|
||||
<return alias="pers" class="Person"/>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,85 +1,87 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="toolsetguide" revision="2">
|
||||
<title>Guide des outils</title>
|
||||
|
||||
<para>
|
||||
Des outils en ligne de commande, des plugins Eclipse ainsu que des tâches Ant permettent de gérer de cycles de développement complet
|
||||
Des outils en ligne de commande, des plugins Eclipse ainsu que des tâches Ant permettent de gérer de cycles de développement complet
|
||||
de projets utilisant Hibernate.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Les <emphasis>outils Hibernate</emphasis> actuels incluent des plugins pour l'IDE Eclipse ainsi que des tâches Ant pour l'ingénierie
|
||||
inverse de bases de données existantes :
|
||||
Les <emphasis>outils Hibernate</emphasis> actuels incluent des plugins pour l'IDE Eclipse ainsi que des tâches Ant pour l'ingénierie
|
||||
inverse de bases de données existantes :
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<emphasis>Mapping Editor :</emphasis> un éditeur pour les fichiers de mapping XML Hibernate, supportant l'auto-complétion et la mise en valeur de la syntaxe.
|
||||
Il supporte aussi l'auto-complétion automatique pour les noms de classes et les noms de propriété/champ,
|
||||
le rendant beaucoup plus polyvalent qu'un éditeurXML normal.
|
||||
<emphasis>Mapping Editor :</emphasis> un éditeur pour les fichiers de mapping XML Hibernate, supportant l'auto-complétion et la mise en valeur de la syntaxe.
|
||||
Il supporte aussi l'auto-complétion automatique pour les noms de classes et les noms de propriété/champ,
|
||||
le rendant beaucoup plus polyvalent qu'un éditeurXML normal.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<emphasis>Console :</emphasis> la console est une nouvelle vue d'Eclipse. En plus de la vue d'ensemble
|
||||
arborescente de vos configurations de console, vous obtenez aussi une vue interactive de vos classes persistantes et de leurs relations.
|
||||
La console vous permet d'exécuter des requête HQL dans votre base de données et de parcourir les résultats directement dans Eclipse.
|
||||
La console vous permet d'exécuter des requête HQL dans votre base de données et de parcourir les résultats directement dans Eclipse.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<emphasis>Development Wizards :</emphasis> plusieurs assistants sont fournis avec les outils d'Hibernate
|
||||
pour Eclipse ; vous pouvez utiliser un assistant pour générer rapidement les fichiers de configuration d'Hibernate (cfg.xml),
|
||||
ou vous pouvez même complètement générer les fichiers de mapping Hibernate et les sources des POJOs à partir d'un schéma de base de données existant.
|
||||
L'assistant d'ingénierie inverse supporte les modèles utilisateur.
|
||||
pour Eclipse ; vous pouvez utiliser un assistant pour générer rapidement les fichiers de configuration d'Hibernate (cfg.xml),
|
||||
ou vous pouvez même complètement générer les fichiers de mapping Hibernate et les sources des POJOs à partir d'un schéma de base de données existant.
|
||||
L'assistant d'ingénierie inverse supporte les modèles utilisateur.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<emphasis>Tâches Ant :</emphasis>
|
||||
<emphasis>Tâches Ant :</emphasis>
|
||||
</para></listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Veuillez-vous référer au paquet <emphasis>outils Hibernate</emphasis> et sa documentation pour plus d'informations.
|
||||
Veuillez-vous référer au paquet <emphasis>outils Hibernate</emphasis> et sa documentation pour plus d'informations.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Pourtant, le paquet principal d'Hibernate arrive avec un lot d'outils intégrés (il peut même être utilisé de "l'intérieur" d'Hibernate à la volée) :
|
||||
Pourtant, le paquet principal d'Hibernate arrive avec un lot d'outils intégrés (il peut même être utilisé de "l'intérieur" d'Hibernate à la volée) :
|
||||
<emphasis>SchemaExport</emphasis> aussi connu comme
|
||||
<literal>hbm2ddl</literal>.
|
||||
</para>
|
||||
|
||||
<sect1 id="toolsetguide-s1" revision="2">
|
||||
<title>Génération automatique du schéma</title>
|
||||
<title>Génération automatique du schéma</title>
|
||||
|
||||
<para>
|
||||
La DDL peut être générée à partir de vos fichiers de mapping par un utilitaire d'Hibernate. Le schéma généré
|
||||
inclut les contraintes d'intégrité référentielle (clefs primaires et étrangères) pour les tables d'entités
|
||||
et de collections. Les tables et les séquences sont aussi créées pour les générateurs d'identifiant mappés.
|
||||
La DDL peut être générée à partir de vos fichiers de mapping par un utilitaire d'Hibernate. Le schéma généré
|
||||
inclut les contraintes d'intégrité référentielle (clefs primaires et étrangères) pour les tables d'entités
|
||||
et de collections. Les tables et les séquences sont aussi créées pour les générateurs d'identifiant mappés.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Vous <emphasis>devez</emphasis> spécifier un <literal>Dialect</literal> SQL via la propriété
|
||||
Vous <emphasis>devez</emphasis> spécifier un <literal>Dialect</literal> SQL via la propriété
|
||||
<literal>hibernate.dialect</literal> lors de l'utilisation de cet outils, puisque la DDL est
|
||||
fortement dépendante de la base de données.
|
||||
fortement dépendante de la base de données.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
D'abord, personnalisez vos fichiers de mapping pour améliorer le schéma généré.
|
||||
D'abord, personnalisez vos fichiers de mapping pour améliorer le schéma généré.
|
||||
</para>
|
||||
|
||||
<sect2 id="toolsetguide-s1-2" revision="3">
|
||||
<title>Personnaliser le schéma</title>
|
||||
<title>Personnaliser le schéma</title>
|
||||
|
||||
<para>
|
||||
Plusieurs éléments du mapping hibernate définissent des attributs optionnels
|
||||
nommés <literal>length</literal>, <literal>precision</literal> et <literal>scale</literal>.
|
||||
Vous pouvez paramétrer la longueur, la précision,... d'une colonne avec ces attributs.
|
||||
Plusieurs éléments du mapping hibernate définissent des attributs optionnels
|
||||
nommés <literal>length</literal>, <literal>precision</literal> et <literal>scale</literal>.
|
||||
Vous pouvez paramétrer la longueur, la précision,... d'une colonne avec ces attributs.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<property name="zip" length="5"/>]]></programlisting>
|
||||
<programlisting><![CDATA[<property name="balance" precision="12" scale="2"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Certains éléments acceptent aussi un attribut <literal>not-null</literal>
|
||||
(utilisé pour générer les contraintes de colonnes <literal>NOT NULL</literal>) et
|
||||
un attribut <literal>unique</literal> (pour générer une contrainte de colonne
|
||||
Certains éléments acceptent aussi un attribut <literal>not-null</literal>
|
||||
(utilisé pour générer les contraintes de colonnes <literal>NOT NULL</literal>) et
|
||||
un attribut <literal>unique</literal> (pour générer une contrainte de colonne
|
||||
<literal>UNIQUE</literal>).
|
||||
</para>
|
||||
|
||||
|
@ -87,10 +89,10 @@
|
|||
<programlisting><![CDATA[<element column="serialNumber" type="long" not-null="true" unique="true"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Un attribut <literal>unique-key</literal> peut être utilisé pour grouper les colonnes
|
||||
en une seule contrainte d'unicité. Actuellement, la valeur spécifiée par
|
||||
l'attribut <literal>unique-key</literal> n'est <emphasis>pas</emphasis> utilisée pour
|
||||
nommer la contrainte dans le DDL généré, elle sert juste à grouper les colonnes
|
||||
Un attribut <literal>unique-key</literal> peut être utilisé pour grouper les colonnes
|
||||
en une seule contrainte d'unicité. Actuellement, la valeur spécifiée par
|
||||
l'attribut <literal>unique-key</literal> n'est <emphasis>pas</emphasis> utilisée pour
|
||||
nommer la contrainte dans le DDL généré, elle sert juste à grouper les colonnes
|
||||
dans le fichier de mapping.
|
||||
</para>
|
||||
<programlisting><![CDATA[<many-to-one name="org" column="orgId" unique-key="OrgEmployeeId"/>
|
||||
|
@ -98,8 +100,8 @@
|
|||
|
||||
<para>
|
||||
Un attribut <literal>index</literal> indique le nom d'un index qui sera
|
||||
créé en utilisant la ou les colonnes mappées. Plusieurs colonnes
|
||||
peuvent être groupées dans un même index, en spécifiant le même
|
||||
créé en utilisant la ou les colonnes mappées. Plusieurs colonnes
|
||||
peuvent être groupées dans un même index, en spécifiant le même
|
||||
nom d'index.
|
||||
</para>
|
||||
|
||||
|
@ -107,14 +109,14 @@
|
|||
<property name="firstName" index="CustName"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Un attribut <literal>foreign-key</literal> peut être utilisé pour surcharger le nom
|
||||
des clés étrangères générées.
|
||||
Un attribut <literal>foreign-key</literal> peut être utilisé pour surcharger le nom
|
||||
des clés étrangères générées.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<many-to-one name="bar" column="barId" foreign-key="FKFooBar"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Plusieurs éléments de mapping acceptent aussi un élément fils <literal><column></literal>.
|
||||
Plusieurs éléments de mapping acceptent aussi un élément fils <literal><column></literal>.
|
||||
Ceci est utile pour les type multi-colonnes:
|
||||
</para>
|
||||
|
||||
|
@ -125,9 +127,9 @@
|
|||
</property>]]></programlisting>
|
||||
|
||||
<para>
|
||||
L'attribut <literal>default</literal> vous laisse spécifier une valeur par défaut pour
|
||||
une colonnes (vous devriez assigner la même valeur à la propriété mappée avant de sauvegarder une nouvelle instance
|
||||
de la classe mappée).
|
||||
L'attribut <literal>default</literal> vous laisse spécifier une valeur par défaut pour
|
||||
une colonnes (vous devriez assigner la même valeur à la propriété mappée avant de sauvegarder une nouvelle instance
|
||||
de la classe mappée).
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<property name="credits" type="integer" insert="false">
|
||||
|
@ -140,7 +142,7 @@
|
|||
|
||||
<para>
|
||||
L'attribut <literal>sql-type</literal> laisse l'utilisateur surcharger le mapping
|
||||
par défaut du type Hibernate vers un type SQL.
|
||||
par défaut du type Hibernate vers un type SQL.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<property name="balance" type="float">
|
||||
|
@ -149,7 +151,7 @@
|
|||
|
||||
|
||||
<para>
|
||||
L'attribut <literal>check</literal> permet de spécifier une contrainte de vérification.
|
||||
L'attribut <literal>check</literal> permet de spécifier une contrainte de vérification.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<property name="foo" type="integer">
|
||||
|
@ -172,53 +174,53 @@
|
|||
<row>
|
||||
<entry>Attribut</entry>
|
||||
<entry>Valeur</entry>
|
||||
<entry>Interprétation</entry>
|
||||
<entry>Interprétation</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>length</literal></entry>
|
||||
<entry>numérique</entry>
|
||||
<entry>numérique</entry>
|
||||
<entry>taille d'une colonne</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>precision</literal></entry>
|
||||
<entry>numérique</entry>
|
||||
<entry>précision décimale de la colonne</entry>
|
||||
<entry>numérique</entry>
|
||||
<entry>précision décimale de la colonne</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>scale</literal></entry>
|
||||
<entry>numérique</entry>
|
||||
<entry>scale décimale de la colonne</entry>
|
||||
<entry>numérique</entry>
|
||||
<entry>scale décimale de la colonne</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>not-null</literal></entry>
|
||||
<entry><literal>true|false</literal></entry>
|
||||
<entry>spécifie que la colonne doit être non-nulle</entry>
|
||||
<entry>spécifie que la colonne doit être non-nulle</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>unique</literal></entry>
|
||||
<entry><literal>true|false</literal></entry>
|
||||
<entry>spécifie que la colonne doit avoir une contrainte d'unicité</entry>
|
||||
<entry>spécifie que la colonne doit avoir une contrainte d'unicité</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>index</literal></entry>
|
||||
<entry><literal>index_name</literal></entry>
|
||||
<entry>spécifie le nom d'un index (multi-colonnes)</entry>
|
||||
<entry>spécifie le nom d'un index (multi-colonnes)</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>unique-key</literal></entry>
|
||||
<entry><literal>unique_key_name</literal></entry>
|
||||
<entry>spécifie le nom d'une contrainte d'unicité multi-colonnes</entry>
|
||||
<entry>spécifie le nom d'une contrainte d'unicité multi-colonnes</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>foreign-key</literal></entry>
|
||||
<entry><literal>foreign_key_name</literal></entry>
|
||||
<entry>
|
||||
spécifie le nom d'une contrainte de clé étrangère générée pour
|
||||
une association, utilisez-la avec les éléments de mapping
|
||||
spécifie le nom d'une contrainte de clé étrangère générée pour
|
||||
une association, utilisez-la avec les éléments de mapping
|
||||
<one-to-one>, <many-to-one>, <key>, et <many-to-many>
|
||||
Notez que les extrêmités <literal>inverse="true"</literal>
|
||||
Notez que les extrêmités <literal>inverse="true"</literal>
|
||||
se seront pas prises en compte par <literal>SchemaExport</literal>.
|
||||
</entry>
|
||||
</row>
|
||||
|
@ -226,22 +228,22 @@
|
|||
<entry><literal>sql-type</literal></entry>
|
||||
<entry><literal>SQL column_type</literal></entry>
|
||||
<entry>
|
||||
surcharge le type par défaut (attribut de
|
||||
l'élément <literal><column></literal> uniquement)
|
||||
surcharge le type par défaut (attribut de
|
||||
l'élément <literal><column></literal> uniquement)
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>default</literal></entry>
|
||||
<entry>expression SQL</entry>
|
||||
<entry>
|
||||
spécifie une valeur par défaut pour la colonne
|
||||
spécifie une valeur par défaut pour la colonne
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>check</literal></entry>
|
||||
<entry>SQL expression</entry>
|
||||
<entry>
|
||||
crée une contrainte de vérification sur la table ou la colonne
|
||||
crée une contrainte de vérification sur la table ou la colonne
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
|
@ -249,7 +251,7 @@
|
|||
</table>
|
||||
|
||||
<para>
|
||||
L'élément <literal><comment></literal> vous permet de spécifier un commentaire pour le schéma généré.
|
||||
L'élément <literal><comment></literal> vous permet de spécifier un commentaire pour le schéma généré.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Customer" table="CurCust">
|
||||
|
@ -264,19 +266,19 @@
|
|||
</property>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Ceci a pour résultat une expression
|
||||
Ceci a pour résultat une expression
|
||||
<literal>comment on table</literal> ou
|
||||
<literal>comment on column</literal> dans la DDL générée (où supportée).
|
||||
<literal>comment on column</literal> dans la DDL générée (où supportée).
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="toolsetguide-s1-3" revision="2">
|
||||
<title>Exécuter l'outil</title>
|
||||
<title>Exécuter l'outil</title>
|
||||
|
||||
<para>
|
||||
L'outil <literal>SchemaExport</literal> génère un script DDL vers
|
||||
la sortie standard et/ou exécute les ordres DDL.
|
||||
L'outil <literal>SchemaExport</literal> génère un script DDL vers
|
||||
la sortie standard et/ou exécute les ordres DDL.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -298,7 +300,7 @@
|
|||
<tbody>
|
||||
<row>
|
||||
<entry><literal>--quiet</literal></entry>
|
||||
<entry>ne pas écrire le script vers la sortie standard</entry>
|
||||
<entry>ne pas écrire le script vers la sortie standard</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--drop</literal></entry>
|
||||
|
@ -306,42 +308,42 @@
|
|||
</row>
|
||||
<row>
|
||||
<entry><literal>--create</literal></entry>
|
||||
<entry>ne créé que les tables</entry>
|
||||
<entry>ne créé que les tables</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--text</literal></entry>
|
||||
<entry>ne pas exécuter sur la base de données</entry>
|
||||
<entry>ne pas exécuter sur la base de données</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--output=my_schema.ddl</literal></entry>
|
||||
<entry>écrit le script ddl vers un fichier</entry>
|
||||
<entry>écrit le script ddl vers un fichier</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
|
||||
<entry>sélectionne une <literal>NamingStrategy</literal></entry>
|
||||
<entry>sélectionne une <literal>NamingStrategy</literal></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--config=hibernate.cfg.xml</literal></entry>
|
||||
<entry>lit la configuration Hibernate à partir d'un fichier XML</entry>
|
||||
<entry>lit la configuration Hibernate à partir d'un fichier XML</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--properties=hibernate.properties</literal></entry>
|
||||
<entry>lit les propriétés de la base de données à partir d'un fichier</entry>
|
||||
<entry>lit les propriétés de la base de données à partir d'un fichier</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--format</literal></entry>
|
||||
<entry>formatte proprement le SQL généré dans le script</entry>
|
||||
<entry>formatte proprement le SQL généré dans le script</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--delimiter=x</literal></entry>
|
||||
<entry>paramètre un délimiteur de fin de ligne pour le script</entry>
|
||||
<entry>paramètre un délimiteur de fin de ligne pour le script</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>
|
||||
Vous pouvez même intégrer <literal>SchemaExport</literal> dans votre application :
|
||||
Vous pouvez même intégrer <literal>SchemaExport</literal> dans votre application :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Configuration cfg = ....;
|
||||
|
@ -350,26 +352,26 @@ new SchemaExport(cfg).create(false, true);]]></programlisting>
|
|||
</sect2>
|
||||
|
||||
<sect2 id="toolsetguide-s1-4">
|
||||
<title>Propriétés</title>
|
||||
<title>Propriétés</title>
|
||||
|
||||
<para>
|
||||
Les propriétés de la base de données peuvent être spécifiées
|
||||
Les propriétés de la base de données peuvent être spécifiées
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>comme propriétés système avec <literal>-D</literal><emphasis><property></emphasis></para>
|
||||
<para>comme propriétés système avec <literal>-D</literal><emphasis><property></emphasis></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>dans <literal>hibernate.properties</literal></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>dans un fichier de propriétés déclaré avec <literal>--properties</literal></para>
|
||||
<para>dans un fichier de propriétés déclaré avec <literal>--properties</literal></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Les propriétés nécessaires sont :
|
||||
Les propriétés nécessaires sont :
|
||||
</para>
|
||||
|
||||
<table frame="topbot">
|
||||
|
@ -379,7 +381,7 @@ new SchemaExport(cfg).create(false, true);]]></programlisting>
|
|||
<colspec colwidth="2*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Nom de la propriété</entry>
|
||||
<entry>Nom de la propriété</entry>
|
||||
<entry>Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
@ -394,7 +396,7 @@ new SchemaExport(cfg).create(false, true);]]></programlisting>
|
|||
</row>
|
||||
<row>
|
||||
<entry><literal>hibernate.connection.username</literal></entry>
|
||||
<entry>utilisateur de la base de données</entry>
|
||||
<entry>utilisateur de la base de données</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>hibernate.connection.password</literal></entry>
|
||||
|
@ -439,12 +441,12 @@ new SchemaExport(cfg).create(false, true);]]></programlisting>
|
|||
</sect2>
|
||||
|
||||
<sect2 id="toolsetguide-s1-6" revision="2">
|
||||
<title>Mises à jour incrémentales du schéma</title>
|
||||
<title>Mises à jour incrémentales du schéma</title>
|
||||
|
||||
<para>
|
||||
L'outil <literal>SchemaUpdate</literal> mettra à jour un schéma existant
|
||||
en effectuant les changement par "incrément".
|
||||
Notez que <literal>SchemaUpdate</literal> dépends beaucoup de l'API JDBC
|
||||
L'outil <literal>SchemaUpdate</literal> mettra à jour un schéma existant
|
||||
en effectuant les changement par "incrément".
|
||||
Notez que <literal>SchemaUpdate</literal> dépends beaucoup de l'API JDBC
|
||||
metadata, il ne fonctionnera donc pas avec tous les drivers JDBC.
|
||||
</para>
|
||||
|
||||
|
@ -467,11 +469,11 @@ new SchemaExport(cfg).create(false, true);]]></programlisting>
|
|||
<tbody>
|
||||
<row>
|
||||
<entry><literal>--quiet</literal></entry>
|
||||
<entry>ne pas écrire vers la sortie standard</entry>
|
||||
<entry>ne pas écrire vers la sortie standard</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--text</literal></entry>
|
||||
<entry>ne pas exporter vers la base de données</entry>
|
||||
<entry>ne pas exporter vers la base de données</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
|
||||
|
@ -479,14 +481,14 @@ new SchemaExport(cfg).create(false, true);]]></programlisting>
|
|||
</row>
|
||||
<row>
|
||||
<entry><literal>--properties=hibernate.properties</literal></entry>
|
||||
<entry>lire les propriétés de la base de données à partir d'un fichier</entry>
|
||||
<entry>lire les propriétés de la base de données à partir d'un fichier</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>
|
||||
Vous pouvez intégrer <literal>SchemaUpdate</literal> dans votre application :
|
||||
Vous pouvez intégrer <literal>SchemaUpdate</literal> dans votre application :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Configuration cfg = ....;
|
||||
|
@ -495,7 +497,7 @@ new SchemaUpdate(cfg).execute(false);]]></programlisting>
|
|||
</sect2>
|
||||
|
||||
<sect2 id="toolsetguide-s1-7">
|
||||
<title>Utiliser Ant pour des mises à jour de schéma par incrément</title>
|
||||
<title>Utiliser Ant pour des mises à jour de schéma par incrément</title>
|
||||
|
||||
<para>
|
||||
Vous pouvez appeler <literal>SchemaUpdate</literal> depuis le script Ant :
|
||||
|
@ -516,12 +518,12 @@ new SchemaUpdate(cfg).execute(false);]]></programlisting>
|
|||
</target>]]></programlisting>
|
||||
|
||||
<sect2 id="toolsetguide-s1-8" revision="1">
|
||||
<title>Validation du schéma</title>
|
||||
<title>Validation du schéma</title>
|
||||
|
||||
<para>
|
||||
L'outil <literal>SchemaValidator</literal> validera que le schéma existant correspond à vos documents de mapping.
|
||||
Notez que le <literal>SchemaValidator</literal> dépends de l'API metadata de JDBC, il ne fonctionnera
|
||||
donc pas avec tous les drivers JDBC. Cet outil est extrêmement utile pour tester.
|
||||
L'outil <literal>SchemaValidator</literal> validera que le schéma existant correspond à vos documents de mapping.
|
||||
Notez que le <literal>SchemaValidator</literal> dépends de l'API metadata de JDBC, il ne fonctionnera
|
||||
donc pas avec tous les drivers JDBC. Cet outil est extrêmement utile pour tester.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -547,7 +549,7 @@ new SchemaUpdate(cfg).execute(false);]]></programlisting>
|
|||
</row>
|
||||
<row>
|
||||
<entry><literal>--properties=hibernate.properties</literal></entry>
|
||||
<entry>lit les propriétés dela base de données depuis un fichier de propriétés</entry>
|
||||
<entry>lit les propriétés dela base de données depuis un fichier de propriétés</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--config=hibernate.cfg.xml</literal></entry>
|
||||
|
@ -568,7 +570,7 @@ new SchemaValidator(cfg).validate();]]></programlisting>
|
|||
|
||||
</sect2>
|
||||
<sect2 id="toolsetguide-s1-9">
|
||||
<title>Utiliser Ant pour la validation du Schéma</title>
|
||||
<title>Utiliser Ant pour la validation du Schéma</title>
|
||||
|
||||
<para>
|
||||
Vous pouvez appeler <literal>SchemaValidator</literal> depuis le script Ant:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,50 +1,52 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="xml">
|
||||
<title>Mapping XML</title>
|
||||
|
||||
<para><emphasis>
|
||||
Notez que cette fonctionnalité est expérimentale dans Hibernate 3.0 et
|
||||
est en développement extrêmement actif.
|
||||
Notez que cette fonctionnalité est expérimentale dans Hibernate 3.0 et
|
||||
est en développement extrêmement actif.
|
||||
</emphasis></para>
|
||||
|
||||
<sect1 id="xml-intro" revision="1">
|
||||
<title>Travailler avec des données XML</title>
|
||||
<title>Travailler avec des données XML</title>
|
||||
|
||||
<para>
|
||||
Hibernate vous laisse travailler avec des données XML persistantes de la
|
||||
même manière que vous travaillez avec des POJOs persistants. Un arbre XML
|
||||
peut être vu comme une autre manière de représenter les données relationnelles
|
||||
au niveau objet, à la place des POJOs.
|
||||
Hibernate vous laisse travailler avec des données XML persistantes de la
|
||||
même manière que vous travaillez avec des POJOs persistants. Un arbre XML
|
||||
peut être vu comme une autre manière de représenter les données relationnelles
|
||||
au niveau objet, à la place des POJOs.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate supporte dom4j en tant qu'API pour la manipulation des arbres XML.
|
||||
Vous pouvez écrire des requêtes qui récupèrent des arbres dom4j à partie de la
|
||||
base de données, et avoir toutes les modifications que vous faites sur l'arbre
|
||||
automatiquement synchronisées dans la base de données. Vous pouvez même prendre
|
||||
un document XML, l'analyser en utilisant dom4j, et l'écrire dans la base de
|
||||
données via les opérations basiques d'Hibernate :
|
||||
Vous pouvez écrire des requêtes qui récupèrent des arbres dom4j à partie de la
|
||||
base de données, et avoir toutes les modifications que vous faites sur l'arbre
|
||||
automatiquement synchronisées dans la base de données. Vous pouvez même prendre
|
||||
un document XML, l'analyser en utilisant dom4j, et l'écrire dans la base de
|
||||
données via les opérations basiques d'Hibernate :
|
||||
<literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal>
|
||||
(merge() n'est pas encore supporté).
|
||||
(merge() n'est pas encore supporté).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Cette fonctionnalité a plusieurs applications dont l'import/export de données,
|
||||
l'externalisation d'entités via JMS ou SOAP et les rapports XSLT.
|
||||
Cette fonctionnalité a plusieurs applications dont l'import/export de données,
|
||||
l'externalisation d'entités via JMS ou SOAP et les rapports XSLT.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Un simple mapping peut être utilisé pour simultanément mapper les propriétés
|
||||
d'une classe et les noeuds d'un document XML vers la base de données, ou,
|
||||
si il n'y a pas de classe à mapper, il peut être utilisé juste pour mapper
|
||||
Un simple mapping peut être utilisé pour simultanément mapper les propriétés
|
||||
d'une classe et les noeuds d'un document XML vers la base de données, ou,
|
||||
si il n'y a pas de classe à mapper, il peut être utilisé juste pour mapper
|
||||
le XML.
|
||||
</para>
|
||||
|
||||
<sect2 id="xml-intro-mapping">
|
||||
<title>Spécifier le mapping XML et le mapping d'une classe ensemble</title>
|
||||
<title>Spécifier le mapping XML et le mapping d'une classe ensemble</title>
|
||||
|
||||
<para>
|
||||
Voici un exemple de mapping d'un POJO et du XML simultanément :
|
||||
Voici un exemple de mapping d'un POJO et du XML simultanément :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Account"
|
||||
|
@ -70,7 +72,7 @@
|
|||
</sect2>
|
||||
|
||||
<sect2 id="xml-onlyxml">
|
||||
<title>Spécifier seulement un mapping XML</title>
|
||||
<title>Spécifier seulement un mapping XML</title>
|
||||
|
||||
<para>
|
||||
Voici un exemple dans lequel il n'y a pas de class POJO :
|
||||
|
@ -101,10 +103,10 @@
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Ce mapping vous permet d'accéder aux données comme un arbre dom4j, ou comme
|
||||
un graphe de paire nom de propriété/valeur (<literal>Map</literal>s java). Les
|
||||
noms des propriétés sont des constructions purement logiques qui peuvent être
|
||||
référées des dans requêtes HQL.
|
||||
Ce mapping vous permet d'accéder aux données comme un arbre dom4j, ou comme
|
||||
un graphe de paire nom de propriété/valeur (<literal>Map</literal>s java). Les
|
||||
noms des propriétés sont des constructions purement logiques qui peuvent être
|
||||
référées des dans requêtes HQL.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
@ -112,45 +114,45 @@
|
|||
</sect1>
|
||||
|
||||
<sect1 id="xml-mapping" revision="1">
|
||||
<title>Métadonnées du mapping XML</title>
|
||||
<title>Métadonnées du mapping XML</title>
|
||||
|
||||
<para>
|
||||
Plusieurs éléments du mapping Hibernate acceptent l'attribut <literal>node</literal>.
|
||||
Ceci vous permet de spécifier le nom d'un attribut XML ou d'un élément qui
|
||||
contient la propriété ou les données de l'entité. Le format de l'attribut
|
||||
<literal>node</literal> doit être un des suivants :
|
||||
Plusieurs éléments du mapping Hibernate acceptent l'attribut <literal>node</literal>.
|
||||
Ceci vous permet de spécifier le nom d'un attribut XML ou d'un élément qui
|
||||
contient la propriété ou les données de l'entité. Le format de l'attribut
|
||||
<literal>node</literal> doit être un des suivants :
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para><literal>"element-name"</literal> - mappe vers l'élément XML nommé</para>
|
||||
<para><literal>"element-name"</literal> - mappe vers l'élément XML nommé</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>"@attribute-name"</literal> - mappe vers l'attribut XML nommé</para>
|
||||
<para><literal>"@attribute-name"</literal> - mappe vers l'attribut XML nommé</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>"."</literal> - mappe vers le parent de l'élément</para>
|
||||
<para><literal>"."</literal> - mappe vers le parent de l'élément</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>"element-name/@attribute-name"</literal> -
|
||||
mappe vers l'élément nommé de l'attribut nommé
|
||||
mappe vers l'élément nommé de l'attribut nommé
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Pour des collections et de simples associations valuées, il y a un attribut
|
||||
<literal>embed-xml</literal> supplémentaire. Si <literal>embed-xml="true"</literal>,
|
||||
qui est la valeur par défaut, l'arbre XML pour l'entité associée (ou la collection
|
||||
des types de valeurs) sera embarquée directement dans l'arbre XML pour l'entité qui
|
||||
possède l'association. Sinon, si <literal>embed-xml="false"</literal>, alors
|
||||
seule la valeur de l'identifiant référencé apparaîtra dans le XML pour de simples
|
||||
associations de points, et les collections n'appraîtront simplement pas.
|
||||
Pour des collections et de simples associations valuées, il y a un attribut
|
||||
<literal>embed-xml</literal> supplémentaire. Si <literal>embed-xml="true"</literal>,
|
||||
qui est la valeur par défaut, l'arbre XML pour l'entité associée (ou la collection
|
||||
des types de valeurs) sera embarquée directement dans l'arbre XML pour l'entité qui
|
||||
possède l'association. Sinon, si <literal>embed-xml="false"</literal>, alors
|
||||
seule la valeur de l'identifiant référencé apparaîtra dans le XML pour de simples
|
||||
associations de points, et les collections n'appraîtront simplement pas.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Vous devriez faire attention à ne pas laisser <literal>embed-xml="true"</literal>
|
||||
Vous devriez faire attention à ne pas laisser <literal>embed-xml="true"</literal>
|
||||
pour trop d'associations, puisque XML ne traite pas bien les liens circurlaires.
|
||||
</para>
|
||||
|
||||
|
@ -190,14 +192,14 @@
|
|||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
dans ce cas, nous avons décidé d'embarquer la collection d'identifiants de compte,
|
||||
mais pas les données actuelles du compte. La requête HQL suivante :
|
||||
dans ce cas, nous avons décidé d'embarquer la collection d'identifiants de compte,
|
||||
mais pas les données actuelles du compte. La requête HQL suivante :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
|
||||
|
||||
<para>
|
||||
devrait retourner l'ensemble de données suivant :
|
||||
devrait retourner l'ensemble de données suivant :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<customer id="123456789">
|
||||
|
@ -213,8 +215,8 @@
|
|||
|
||||
<para>
|
||||
Si vous positionnez <literal>embed-xml="true"</literal> sur le mapping
|
||||
<literal><one-to-many></literal>, les données pourraient
|
||||
ressembler plus à ça :
|
||||
<literal><one-to-many></literal>, les données pourraient
|
||||
ressembler plus à ça :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<customer id="123456789">
|
||||
|
@ -238,11 +240,11 @@
|
|||
|
||||
|
||||
<sect1 id="xml-manipulation" revision="1">
|
||||
<title>Manipuler des données XML</title>
|
||||
<title>Manipuler des données XML</title>
|
||||
|
||||
<para>
|
||||
Relisons et mettons à jour des documents XML dans l'application. Nous faisons
|
||||
ça en obtenant une session dom4j :
|
||||
Relisons et mettons à jour des documents XML dans l'application. Nous faisons
|
||||
ça en obtenant une session dom4j :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Document doc = ....;
|
||||
|
@ -281,9 +283,9 @@ tx.commit();
|
|||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Il est extrêmement utile de combiner cette fonctionnalité avec l'opération
|
||||
<literal>replicate()</literal> d'Hibernate pour implémenter des imports/exports
|
||||
de données XML.
|
||||
Il est extrêmement utile de combiner cette fonctionnalité avec l'opération
|
||||
<literal>replicate()</literal> d'Hibernate pour implémenter des imports/exports
|
||||
de données XML.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version='1.0'?>
|
||||
<?xml version='1.0' encoding="UTF-8"?>
|
||||
<!DOCTYPE legalnotice PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<!--
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
<?xml version='1.0'?>
|
||||
|
||||
<!DOCTYPE authorgroup PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<authorgroup id="AuthorGroup">
|
||||
<othercredit class="translator">
|
||||
<firstname>Vincent</firstname>
|
||||
<surname>Ricard</surname>
|
||||
</othercredit>
|
||||
<othercredit class="translator">
|
||||
<firstname>Sebastien</firstname>
|
||||
<surname>Cesbron</surname>
|
||||
</othercredit>
|
||||
<othercredit class="translator">
|
||||
<firstname>Michael</firstname>
|
||||
<surname>Courcy</surname>
|
||||
</othercredit>
|
||||
<othercredit class="translator">
|
||||
<firstname>Vincent</firstname>
|
||||
<surname>Giguère</surname>
|
||||
</othercredit>
|
||||
<othercredit class="translator">
|
||||
<firstname>Baptiste</firstname>
|
||||
<surname>Mathus</surname>
|
||||
</othercredit>
|
||||
<othercredit class="translator">
|
||||
<firstname>Emmanuel</firstname>
|
||||
<surname>Bernard</surname>
|
||||
</othercredit>
|
||||
<othercredit class="translator">
|
||||
<firstname>Anthony</firstname>
|
||||
<surname>Patricio</surname>
|
||||
</othercredit>
|
||||
</authorgroup>
|
Loading…
Reference in New Issue