293 lines
9.7 KiB
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<69> est exp<78>rimentale dans Hibernate 3.0 et
|
|||
|
est en d<>veloppement extr<74>mement actif.
|
|||
|
</emphasis></para>
|
|||
|
|
|||
|
<sect1 id="xml-intro" revision="1">
|
|||
|
<title>Travailler avec des donn<6E>es XML</title>
|
|||
|
|
|||
|
<para>
|
|||
|
Hibernate vous laisse travailler avec des donn<6E>es XML persistantes de la
|
|||
|
m<>me mani<6E>re que vous travaillez avec des POJOs persistants. Un arbre XML
|
|||
|
peut <20>tre vu comme une autre mani<6E>re de repr<70>senter les donn<6E>es relationnelles
|
|||
|
au niveau objet, <20> la place des POJOs.
|
|||
|
</para>
|
|||
|
|
|||
|
<para>
|
|||
|
Hibernate supporte dom4j en tant qu'API pour la manipulation des arbres XML.
|
|||
|
Vous pouvez <20>crire des requ<71>tes qui r<>cup<75>rent des arbres dom4j <20> partie de la
|
|||
|
base de donn<6E>es, et avoir toutes les modifications que vous faites sur l'arbre
|
|||
|
automatiquement synchronis<69>es dans la base de donn<6E>es. Vous pouvez m<>me prendre
|
|||
|
un document XML, l'analyser en utilisant dom4j, et l'<27>crire dans la base de
|
|||
|
donn<6E>es via les op<6F>rations basiques d'Hibernate :
|
|||
|
<literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal>
|
|||
|
(merge() n'est pas encore support<72>).
|
|||
|
</para>
|
|||
|
|
|||
|
<para>
|
|||
|
Cette fonctionnalit<69> a plusieurs applications dont l'import/export de donn<6E>es,
|
|||
|
l'externalisation d'entit<69>s via JMS ou SOAP et les rapports XSLT.
|
|||
|
</para>
|
|||
|
|
|||
|
<para>
|
|||
|
Un simple mapping peut <20>tre utilis<69> pour simultan<61>ment mapper les propri<72>t<EFBFBD>s
|
|||
|
d'une classe et les noeuds d'un document XML vers la base de donn<6E>es, ou,
|
|||
|
si il n'y a pas de classe <20> mapper, il peut <20>tre utilis<69> juste pour mapper
|
|||
|
le XML.
|
|||
|
</para>
|
|||
|
|
|||
|
<sect2 id="xml-intro-mapping">
|
|||
|
<title>Sp<EFBFBD>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<61>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<EFBFBD>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<63>der aux donn<6E>es comme un arbre dom4j, ou comme
|
|||
|
un graphe de paire nom de propri<72>t<EFBFBD>/valeur (<literal>Map</literal>s java). Les
|
|||
|
noms des propri<72>t<EFBFBD>s sont des constructions purement logiques qui peuvent <20>tre
|
|||
|
r<>f<EFBFBD>r<EFBFBD>es des dans requ<71>tes HQL.
|
|||
|
</para>
|
|||
|
|
|||
|
</sect2>
|
|||
|
|
|||
|
</sect1>
|
|||
|
|
|||
|
<sect1 id="xml-mapping" revision="1">
|
|||
|
<title>M<EFBFBD>tadonn<EFBFBD>es du mapping XML</title>
|
|||
|
|
|||
|
<para>
|
|||
|
Plusieurs <20>l<EFBFBD>ments du mapping Hibernate acceptent l'attribut <literal>node</literal>.
|
|||
|
Ceci vous permet de sp<73>cifier le nom d'un attribut XML ou d'un <20>l<EFBFBD>ment qui
|
|||
|
contient la propri<72>t<EFBFBD> ou les donn<6E>es de l'entit<69>. Le format de l'attribut
|
|||
|
<literal>node</literal> doit <20>tre un des suivants :
|
|||
|
</para>
|
|||
|
|
|||
|
<itemizedlist spacing="compact">
|
|||
|
<listitem>
|
|||
|
<para><literal>"element-name"</literal> - mappe vers l'<27>l<EFBFBD>ment XML nomm<6D></para>
|
|||
|
</listitem>
|
|||
|
<listitem>
|
|||
|
<para><literal>"@attribute-name"</literal> - mappe vers l'attribut XML nomm<6D></para>
|
|||
|
</listitem>
|
|||
|
<listitem>
|
|||
|
<para><literal>"."</literal> - mappe vers le parent de l'<27>l<EFBFBD>ment</para>
|
|||
|
</listitem>
|
|||
|
<listitem>
|
|||
|
<para>
|
|||
|
<literal>"element-name/@attribute-name"</literal> -
|
|||
|
mappe vers l'<27>l<EFBFBD>ment nomm<6D> de l'attribut nomm<6D>
|
|||
|
</para>
|
|||
|
</listitem>
|
|||
|
</itemizedlist>
|
|||
|
|
|||
|
<para>
|
|||
|
Pour des collections et de simples associations valu<6C>es, il y a un attribut
|
|||
|
<literal>embed-xml</literal> suppl<70>mentaire. Si <literal>embed-xml="true"</literal>,
|
|||
|
qui est la valeur par d<>faut, l'arbre XML pour l'entit<69> associ<63>e (ou la collection
|
|||
|
des types de valeurs) sera embarqu<71>e directement dans l'arbre XML pour l'entit<69> qui
|
|||
|
poss<73>de l'association. Sinon, si <literal>embed-xml="false"</literal>, alors
|
|||
|
seule la valeur de l'identifiant r<>f<EFBFBD>renc<6E> appara<72>tra dans le XML pour de simples
|
|||
|
associations de points, et les collections n'appra<72>tront simplement pas.
|
|||
|
</para>
|
|||
|
|
|||
|
<para>
|
|||
|
Vous devriez faire attention <20> 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<69> d'embarquer la collection d'identifiants de compte,
|
|||
|
mais pas les donn<6E>es actuelles du compte. La requ<71>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<6E>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><one-to-many></literal>, les donn<6E>es pourraient
|
|||
|
ressembler plus <20> <20>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<6E>es XML</title>
|
|||
|
|
|||
|
<para>
|
|||
|
Relisons et mettons <20> jour des documents XML dans l'application. Nous faisons
|
|||
|
<20>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<74>mement utile de combiner cette fonctionnalit<69> avec l'op<6F>ration
|
|||
|
<literal>replicate()</literal> d'Hibernate pour impl<70>menter des imports/exports
|
|||
|
de donn<6E>es XML.
|
|||
|
</para>
|
|||
|
|
|||
|
</sect1>
|
|||
|
|
|||
|
</chapter>
|
|||
|
|