hibernate-orm/doc/reference/fr/modules/xml.xml

293 lines
9.7 KiB
XML

<?xml version="1.0" encoding="iso-8859-1"?>
<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.
</emphasis></para>
<sect1 id="xml-intro" revision="1">
<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.
</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 :
<literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal>
(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.
</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
le XML.
</para>
<sect2 id="xml-intro-mapping">
<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 :
</para>
<programlisting><![CDATA[<class name="Account"
table="ACCOUNTS"
node="account">
<id name="accountId"
column="ACCOUNT_ID"
node="@id"/>
<many-to-one name="customer"
column="CUSTOMER_ID"
node="customer/@id"
embed-xml="false"/>
<property name="balance"
column="BALANCE"
node="balance"/>
...
</class>]]></programlisting>
</sect2>
<sect2 id="xml-onlyxml">
<title>Spécifier seulement un mapping XML</title>
<para>
Voici un exemple dans lequel il n'y a pas de class POJO :
</para>
<programlisting><![CDATA[<class entity-name="Account"
table="ACCOUNTS"
node="account">
<id name="id"
column="ACCOUNT_ID"
node="@id"
type="string"/>
<many-to-one name="customerId"
column="CUSTOMER_ID"
node="customer/@id"
embed-xml="false"
entity-name="Customer"/>
<property name="balance"
column="BALANCE"
node="balance"
type="big_decimal"/>
...
</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.
</para>
</sect2>
</sect1>
<sect1 id="xml-mapping" revision="1">
<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 :
</para>
<itemizedlist spacing="compact">
<listitem>
<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>
</listitem>
<listitem>
<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é
</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.
</para>
<para>
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>
<programlisting><![CDATA[<class name="Customer"
table="CUSTOMER"
node="customer">
<id name="id"
column="CUST_ID"
node="@id"/>
<map name="accounts"
node="."
embed-xml="true">
<key column="CUSTOMER_ID"
not-null="true"/>
<map-key column="SHORT_DESC"
node="@short-desc"
type="string"/>
<one-to-many entity-name="Account"
embed-xml="false"
node="account"/>
</map>
<component name="name"
node="name">
<property name="firstName"
node="first-name"/>
<property name="initial"
node="initial"/>
<property name="lastName"
node="last-name"/>
</component>
...
</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 :
</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 :
</para>
<programlisting><![CDATA[<customer id="123456789">
<account short-desc="Savings">987632567</account>
<account short-desc="Credit Card">985612323</account>
<name>
<first-name>Gavin</first-name>
<initial>A</initial>
<last-name>King</last-name>
</name>
...
</customer>]]></programlisting>
<para>
Si vous positionnez <literal>embed-xml="true"</literal> sur le mapping
<literal>&lt;one-to-many&gt;</literal>, les données pourraient
ressembler plus à ça :
</para>
<programlisting><![CDATA[<customer id="123456789">
<account id="987632567" short-desc="Savings">
<customer id="123456789"/>
<balance>100.29</balance>
</account>
<account id="985612323" short-desc="Credit Card">
<customer id="123456789"/>
<balance>-2370.34</balance>
</account>
<name>
<first-name>Gavin</first-name>
<initial>A</initial>
<last-name>King</last-name>
</name>
...
</customer>]]></programlisting>
</sect1>
<sect1 id="xml-manipulation" revision="1">
<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 :
</para>
<programlisting><![CDATA[Document doc = ....;
Session session = factory.openSession();
Session dom4jSession = session.getSession(EntityMode.DOM4J);
Transaction tx = session.beginTransaction();
List results = dom4jSession
.createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName")
.list();
for ( int i=0; i<results.size(); i++ ) {
//add the customer data to the XML document
Element customer = (Element) results.get(i);
doc.add(customer);
}
tx.commit();
session.close();]]></programlisting>
<programlisting><![CDATA[Session session = factory.openSession();
Session dom4jSession = session.getSession(EntityMode.DOM4J);
Transaction tx = session.beginTransaction();
Element cust = (Element) dom4jSession.get("Customer", customerId);
for ( int i=0; i<results.size(); i++ ) {
Element customer = (Element) results.get(i);
//change the customer name in the XML and database
Element name = customer.element("name");
name.element("first-name").setText(firstName);
name.element("initial").setText(initial);
name.element("last-name").setText(lastName);
}
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.
</para>
</sect1>
</chapter>