2005-11-27 11:17:00 -05:00
|
|
|
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
|
|
|
|
<chapter id="querysql" revision="2">
|
|
|
|
|
<title>SQL natif</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
Vous pouvez aussi <20>crire vos requ<71>tes dans le dialecte SQL natif de votre base de donn<6E>es.
|
|
|
|
|
Ceci est utile si vous souhaitez utiliser les fonctionnalit<69>s sp<73>cifiques de votre base de
|
|
|
|
|
donn<6E>es comme le mot cl<63> <literal>CONNECT</literal> d'Oracle. Cette fonctionnalit<69> offre par ailleurs un moyen
|
|
|
|
|
de migration plus propre et doux d'une application bas<61>e sur SQL/JDBC vers
|
|
|
|
|
une application Hibernate.
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>Hibernate3 vous permet de sp<73>cifier du SQL <20>crit <20> la main (incluant les proc<6F>dures stock<63>es)
|
|
|
|
|
pour toutes les op<6F>rations de cr<63>ation, mise <20> jour, suppression et chargement.</para>
|
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<sect1 id="querysql-creating" revision="4">
|
2005-11-27 11:17:00 -05:00
|
|
|
|
<title>Utiliser une <literal>SQLQuery</literal></title>
|
|
|
|
|
|
|
|
|
|
<para>L'ex<65>cution des requ<71>tes en SQL natif est contr<74>l<EFBFBD>e par l'interface <literal>SQLQuery</literal>,
|
|
|
|
|
laquelle est obtenue en appelant <literal>Session.createSQLQuery()</literal>.
|
|
|
|
|
Dans des cas extr<74>mement simples, nous pouvons utiliser la forme suivante :
|
|
|
|
|
</para>
|
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<sect2>
|
|
|
|
|
<title>Requ<EFBFBD>tes scalaires</title>
|
|
|
|
|
|
|
|
|
|
<para>La requ<71>te SQL la plus basique permet de r<>cup<75>rer une liste de (valeurs) scalaires.</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").list();
|
|
|
|
|
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
|
|
|
|
|
]]></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>Ces deux requ<71>tes retourneront un tableau d'objets (Object[]) avec
|
|
|
|
|
les valeurs scalaires de chacune des colonnes de la table CATS.
|
|
|
|
|
Hibernate utilisera le ResultSetMetadata pour d<>duire l'ordre et le type
|
|
|
|
|
des valeurs scalaires retourn<72>es.</para>
|
|
|
|
|
|
|
|
|
|
<para>Pour <20>viter l'overhead li<6C> <20> <literal>ResultSetMetadata</literal> ou simplement pour
|
|
|
|
|
<20>tre plus explicite dans ce qui est retourn<72>, vous pouvez utiliser <literal>addScalar()</literal>.</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
|
|
|
|
|
.addScalar("ID", Hibernate.LONG)
|
|
|
|
|
.addScalar("NAME", Hibernate.STRING)
|
|
|
|
|
.addScalar("BIRTHDATE", Hibernate.DATE)
|
|
|
|
|
]]></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>Cette requ<71>te sp<73>cifie:</para>
|
|
|
|
|
|
|
|
|
|
<itemizedlist>
|
|
|
|
|
<listitem>
|
|
|
|
|
<para>la cha<68>ne de caract<63>re SQL</para>
|
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
|
<para>les colonnes et les types retourn<72>s</para>
|
|
|
|
|
</listitem>
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
|
|
|
|
<para>Cela retournera toujours un tableau d'objets, mais sans utiliser le
|
|
|
|
|
<literal>ResultSetMetdata</literal>, mais r<>cup<75>rera explicitement les colonnes
|
|
|
|
|
ID, NAME and BIRTHDATE column <20>tant de respectivement de type Long, String et Short,
|
|
|
|
|
depuis le resultset sous jacent. Cela signifie aussi que seules ces colonnes seront
|
|
|
|
|
retourn<72>es m<>me si la requ<71>te utilise <literal>*</literal>
|
|
|
|
|
et aurait pu retourner plus que les trois colonnes list<73>es.</para>
|
|
|
|
|
|
|
|
|
|
<para>Il est possible de ne pas d<>finir l'information sur le type pour toutes ou partie
|
|
|
|
|
des calaires.</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
|
|
|
|
|
.addScalar("ID", Hibernate.LONG)
|
|
|
|
|
.addScalar("NAME")
|
|
|
|
|
.addScalar("BIRTHDATE")
|
|
|
|
|
]]></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>Il s'agit essentiellement de la m<>me requ<71>te que pr<70>c<EFBFBD>demment, mais
|
|
|
|
|
le <literal>ResultSetMetaData</literal> est utilis<69> pour d<>cider des types de NAME
|
|
|
|
|
et BIRTHDATE alors que le type de ID est explicitement sp<73>cifi<66>.</para>
|
|
|
|
|
|
|
|
|
|
<para>Les java.sql.Types retourn<72>s par le ResultSetMetaData sont mapp<70>s aux type Hibernate
|
|
|
|
|
via le Dialect. Si un type sp<73>cifique n'est pas mapp<70> ou est mapp<70> <20> un type non souhait<69>, il
|
|
|
|
|
est possible de personnaliser en invoquant <literal>registerHibernateType</literal> dans
|
|
|
|
|
le Dialect.</para>
|
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
|
<title>Requ<EFBFBD>tes d'entit<69>s</title>
|
|
|
|
|
|
|
|
|
|
<para>Les requ<71>tes pr<70>c<EFBFBD>dentes ne retournaient que des valeurs scalaires,
|
|
|
|
|
retournant basiquement que les valeurs brutes du resultset. Ce qui suit montre
|
|
|
|
|
comment r<>cup<75>rer des entit<69>s depuis une requ<71>te native SQL, gr<67>ce <20>
|
|
|
|
|
<literal>addEntity()</literal>.</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class);
|
|
|
|
|
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);
|
|
|
|
|
]]></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>Cette requ<71>te sp<73>cifie:</para>
|
|
|
|
|
|
|
|
|
|
<itemizedlist>
|
|
|
|
|
<listitem>
|
|
|
|
|
<para>La cha<68>ne de caract<63>re de requ<71>te SQL</para>
|
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
|
<para>L'entit<69> retourn<72>e par la requ<71>te</para>
|
|
|
|
|
</listitem>
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
|
|
|
|
<para>Avec Cat mapp<70> comme classe avec les colonnes ID, NAME
|
|
|
|
|
et BIRTHDATE, les requ<71>tes pr<70>c<EFBFBD>dentes retournent toutes deux une liste
|
|
|
|
|
o<> chaque <20>l<EFBFBD>ment est une entit<69> Cat.</para>
|
|
|
|
|
|
|
|
|
|
<para>Si l'entit<69> est mapp<70>e avec un <literal>many-to-one</literal> vers
|
|
|
|
|
une autre entit<69>, il est requis de retourner aussi cette entit<69> en ex<65>cutant
|
|
|
|
|
la requ<71>te native, sinon une erreur "column not found" sp<73>cifique <20> la base de
|
|
|
|
|
donn<6E>es sera soulev<65>e. Les colonnes additionnelles seront automatiquement
|
|
|
|
|
retourn<72>es en utilisant la notation *, mais nous pr<70>f<EFBFBD>rons <20>tre explicites
|
|
|
|
|
comme dans l'exemple suivant avec le <literal>many-to-one</literal> vers
|
|
|
|
|
<literal>Dog</literal>:</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);
|
|
|
|
|
]]></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>Ceci permet <20> cat.getDog() de fonctionner normalement.</para>
|
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
|
<title>G<EFBFBD>rer les associations et collections</title>
|
|
|
|
|
|
|
|
|
|
<para>Il est possible de charger agressivement <literal>Dog</literal> pour
|
|
|
|
|
<20>viter le chargement de proxy qui signifie aller retour suppl<70>mentaire vers
|
|
|
|
|
la base de donn<6E>es. Ceci est faisable via la m<>thode <literal>addJoin()</literal>,
|
|
|
|
|
qui vous permet de joindre une association ou collection.</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID")
|
|
|
|
|
.addEntity("cat", Cat.class)
|
|
|
|
|
.addJoin("cat.dog");
|
|
|
|
|
]]></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>Dans cet exemple, les <literal>Cat</literal> retourn<72>s auront leur
|
|
|
|
|
propri<72>t<EFBFBD> <literal>dog</literal> enti<74>rement initialis<69>es sans aucun aller/retour
|
|
|
|
|
suppl<70>mentaire vers la base de donn<6E>es. Notez que nous avons ajout<75> un alias
|
|
|
|
|
("cat") pour <20>tre capable de sp<73>cifier la propri<72>t<EFBFBD> cible de la jointure.
|
|
|
|
|
Il est possible de faire la m<>me jointure aggressive pour les collections, e.g. si le
|
|
|
|
|
<literal>Cat</literal> a un one-to-many vers <literal>Dog</literal>.</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID")
|
|
|
|
|
.addEntity("cat", Cat.class)
|
|
|
|
|
.addJoin("cat.dogs");
|
|
|
|
|
]]></programlisting>
|
|
|
|
|
|
|
|
|
|
<p>Nous arrivons aux limites de ce qui est possible avec les requ<71>tes natives
|
|
|
|
|
sans les modifier pour les rendre utilisables par Hibernate; les probl<62>mes
|
|
|
|
|
surviennent lorsque nous essayons de retourner des entit<69>s du m<>me type ou
|
|
|
|
|
lorsque les alias/colonnes par d<>faut ne sont plus suffisants..</p>
|
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
|
<title>Retour d'entit<69>s multiples</title>
|
|
|
|
|
|
|
|
|
|
<para>Jusqu'<27> pr<70>sent, les colonnes du resultset sont suppos<6F>es <20>tre les m<>mes
|
|
|
|
|
que les colonnes sp<73>cifi<66>es dans les fichiers de mapping. Ceci peut
|
|
|
|
|
<20>tre probl<62>matique pour les requ<71>tes SQL qui effectuent de multiples
|
|
|
|
|
jointures vers diff<66>rentes tables, puisque les m<>mes colonnes peuvent
|
|
|
|
|
appara<72>tre dans plus d'une table.</para>
|
|
|
|
|
|
|
|
|
|
<para>L'injection d'alias de colonne est requis pour la requ<71>te suivante
|
|
|
|
|
(qui risque de ne pas fonctionner):</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT c.*, m.* FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
|
|
|
|
|
.addEntity("cat", Cat.class)
|
|
|
|
|
.addEntity("mother", Cat.class)
|
|
|
|
|
]]></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>Le but de cette requ<71>te est de retourner deux instances de Cat par ligne,
|
|
|
|
|
un chat et sa m<>re. Cela <20>chouera puisqu'il y a conflit de nom puisqu'ils sont
|
|
|
|
|
mapp<70>s au m<>me nom de colonne et que sur certaines base de donn<6E>es, les alias
|
|
|
|
|
de colonnes retourn<72>s seront plut<75>t de la forme
|
|
|
|
|
"c.ID", "c.NAME", etc. qui ne sont pas <20>gaux aux colonnes sp<73>cifi<66>es dans les
|
|
|
|
|
mappings ("ID" and "NAME").</para>
|
|
|
|
|
|
|
|
|
|
<para>La forme suivante n'est pas vuln<6C>rable <20> la duplication des noms de colonnes:</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT {cat.*}, {mother.*} FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
|
|
|
|
|
.addEntity("cat", Cat.class)
|
|
|
|
|
.addEntity("mother", Cat.class)
|
|
|
|
|
]]></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>Cette requ<71>te sp<73>cifie:</para>
|
|
|
|
|
|
|
|
|
|
<itemizedlist>
|
|
|
|
|
<listitem>
|
|
|
|
|
<para>la requ<71>te SQL, avec des r<>ceptacles pour qu'Hibernate injecte les alias de colonnes</para>
|
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
|
<para>les entit<69>s retourn<72>s par la requ<71>te</para>
|
|
|
|
|
</listitem>
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
|
|
|
|
<para>Les notations {cat.*} et {mother.*} utilis<69>es sont un <20>quivalent <20> 'toutes les propri<72>t<EFBFBD>s'.
|
|
|
|
|
Alternativement, vous pouvez lister les colonnes explicitement, mais m<>me pour ce cas, nous
|
|
|
|
|
laissons Hibernate injecter les alias de colonne pour chaque propri<72>t<EFBFBD>.
|
|
|
|
|
Le r<>ceptable pour un alias de colonne est simplement le nom de la propri<72>t<EFBFBD>
|
|
|
|
|
qualifi<66> par l'alias de la table. Dans l'exemple suivant, nous r<>cup<75>rons
|
|
|
|
|
les chats et leur m<>re depuis une table diff<66>rentes (cat_log) de celle d<>clar<61>e
|
|
|
|
|
dans les mappings. Notez que nous pouvons aussi utiliser les alias de propri<72>t<EFBFBD>
|
|
|
|
|
dans la clause where si nous le voulons.</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><![CDATA[String sql = "SELECT ID as {c.id}, NAME as {c.name}, " +
|
|
|
|
|
"BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
|
|
|
|
|
"FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
List loggedCats = sess.createSQLQuery(sql)
|
|
|
|
|
.addEntity("cat", Cat.class)
|
|
|
|
|
.addEntity("mother", Cat.class).list()
|
|
|
|
|
]]></programlisting>
|
|
|
|
|
<sect3 id="querysql-aliasreferences" revision="2">
|
|
|
|
|
<title>R<EFBFBD>f<EFBFBD>rences d'alias et de propri<72>t<EFBFBD></title>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<para>Pour la plupart des cas pr<70>c<EFBFBD>dents, l'injection d'alias est requis,
|
|
|
|
|
mais pour les requ<71>tes relatives <20> des mappings plus complexes, comme
|
|
|
|
|
les propri<72>t<EFBFBD>s composite, les discriminants d'h<>ritage, les collections etc., il
|
|
|
|
|
y a des alias sp<73>cifiques <20> utiliser pour permettre <20> Hibernate l'injection
|
|
|
|
|
des bons alias.</para>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<para>Le tableau suivant montre les diverses possiblit<69>s d'utilisation
|
|
|
|
|
d'injection d'alias. Note: les noms d'alias dans le r<>sultat sont des
|
|
|
|
|
exemples, chaque alias aura un nom unique et probablement diff<66>rent lorsqu'ils
|
|
|
|
|
seront utilis<69>s.</para>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<table frame="topbot" id="aliasinjection-summary">
|
|
|
|
|
<title>Nom d'injection d'alias</title>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<tgroup cols="3">
|
|
|
|
|
<colspec colwidth="1*" />
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<colspec colwidth="1*" />
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<colspec colwidth="2.5*" />
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<thead>
|
|
|
|
|
<row>
|
|
|
|
|
<entry>Description</entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry>Syntaxe</entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry>Exemple</entry>
|
|
|
|
|
</row>
|
|
|
|
|
</thead>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<tbody>
|
|
|
|
|
<row>
|
|
|
|
|
<entry>Une propri<72>t<EFBFBD> simple</entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>{[aliasname].[propertyname]</literal></entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>A_NAME as {item.name}</literal></entry>
|
|
|
|
|
</row>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<row>
|
|
|
|
|
<entry>Une propri<72>t<EFBFBD> composite</entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>CURRENCY as {item.amount.currency}, VALUE as
|
|
|
|
|
{item.amount.value}</literal></entry>
|
|
|
|
|
</row>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<row>
|
|
|
|
|
<entry>Discriminateur d'une entit<69></entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>{[aliasname].class}</literal></entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>DISC as {item.class}</literal></entry>
|
|
|
|
|
</row>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<row>
|
|
|
|
|
<entry>Toutes les propri<72>t<EFBFBD>s d'une entit<69></entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>{[aliasname].*}</literal></entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>{item.*}</literal></entry>
|
|
|
|
|
</row>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<row>
|
|
|
|
|
<entry>La cl<63> d'une collection</entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>{[aliasname].key}</literal></entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>ORGID as {coll.key}</literal></entry>
|
|
|
|
|
</row>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<row>
|
|
|
|
|
<entry>L'id d'une collection</entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>{[aliasname].id}</literal></entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>EMPID as {coll.id}</literal></entry>
|
|
|
|
|
</row>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<row>
|
|
|
|
|
<entry>L'<27>l<EFBFBD>ment d'une collection</entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>{[aliasname].element}</literal></entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>XID as {coll.element}</literal></entry>
|
|
|
|
|
</row>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<row>
|
|
|
|
|
<entry>Propri<EFBFBD>t<EFBFBD> d'un <20>l<EFBFBD>ment de collection</entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>NAME as {coll.element.name}</literal></entry>
|
|
|
|
|
</row>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<row>
|
|
|
|
|
<entry>Toutes les propri<72>t<EFBFBD>s d'un <20>l<EFBFBD>ment de collection</entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>{[aliasname].element.*}</literal></entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>{coll.element.*}</literal></entry>
|
|
|
|
|
</row>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<row>
|
|
|
|
|
<entry>Toutes les propri<72>t<EFBFBD>s d'une collection</entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>{[aliasname].*}</literal></entry>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<entry><literal>{coll.*}</literal></entry>
|
|
|
|
|
</row>
|
|
|
|
|
</tbody>
|
|
|
|
|
</tgroup>
|
|
|
|
|
</table>
|
|
|
|
|
</sect3>
|
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
|
<title>Retour d'objet n'<27>tant pas des entit<69>s</title>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<para>Il est possible d'appliquer un ResultTransformer <20> une requ<71>te native SQL. Ce qui permet, par exemple, de
|
|
|
|
|
retourner des entit<69>s non g<>r<EFBFBD>es.</para>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS")
|
|
|
|
|
.setResultTransformer(Transformers.aliasToBean(CatDTO.class))]]></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>Cette requ<71>te sp<73>cifie:</para>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<itemizedlist>
|
|
|
|
|
<listitem>
|
|
|
|
|
<para>une requ<71>te SQL</para>
|
|
|
|
|
</listitem>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<listitem>
|
|
|
|
|
<para>un transformateur de r<>sultat</para>
|
|
|
|
|
</listitem>
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
La requ<71>te pr<70>c<EFBFBD>dente retournera une liste de <literal>CatDTO</literal> qui auront <20>t<EFBFBD> instanci<63>s
|
|
|
|
|
et dans lesquelles les valeurs de NAME et BIRTHNAME auront <20>t<EFBFBD> inject<63>es dans les propri<72>t<EFBFBD>s ou champs
|
|
|
|
|
correspondants.
|
|
|
|
|
</para>
|
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
|
<title>G<EFBFBD>rer l'h<>ritage</title>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<para>Les requ<71>tes natives SQL pour les entit<69>s prenant part <20> un h<>ritage
|
|
|
|
|
doivent inclure toutes les propri<72>t<EFBFBD>s de la classe de base et de toutes
|
|
|
|
|
ses sous classes.</para>
|
|
|
|
|
</sect2>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<sect2>
|
|
|
|
|
<title>Param<EFBFBD>tres</title>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<para>Les requ<71>tes natives SQL supportent aussi les param<61>tres nomm<6D>s:</para>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
2006-10-02 14:27:05 -04:00
|
|
|
|
<programlisting><![CDATA[Query query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class);
|
|
|
|
|
List pusList = query.setString(0, "Pus%").list();
|
|
|
|
|
|
|
|
|
|
query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like :name").addEntity(Cat.class);
|
|
|
|
|
List pusList = query.setString("name", "Pus%").list(); ]]></programlisting>
|
|
|
|
|
</sect2>
|
2005-11-27 11:17:00 -05:00
|
|
|
|
|
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
<sect1 id="querysql-namedqueries" revision="3">
|
|
|
|
|
<title>Requ<EFBFBD>tes SQL nomm<6D>es</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
Les requ<71>tes SQL nomm<6D>es peuvent <20>tre d<>finies dans le document de mapping
|
|
|
|
|
et appel<65>es exactement de la m<>me mani<6E>re qu'un requ<71>te HQL nomm<6D>e. Dans ce
|
|
|
|
|
cas, nous <emphasis>n'avons pas besoin</emphasis> d'appeler <literal>addEntity()</literal>.
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><sql-query name="persons">
|
|
|
|
|
<return alias="person" class="eg.Person"/>
|
|
|
|
|
SELECT person.NAME AS {person.name},
|
|
|
|
|
person.AGE AS {person.age},
|
|
|
|
|
person.SEX AS {person.sex}
|
|
|
|
|
FROM PERSON person
|
|
|
|
|
WHERE person.NAME LIKE :namePattern
|
|
|
|
|
</sql-query></programlisting>
|
|
|
|
|
|
|
|
|
|
<programlisting>List people = sess.getNamedQuery("persons")
|
|
|
|
|
.setString("namePattern", namePattern)
|
|
|
|
|
.setMaxResults(50)
|
|
|
|
|
.list();</programlisting>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
Les <20>l<EFBFBD>ments <literal><return-join></literal> et
|
|
|
|
|
<literal><load-collection></literal> sont respectivement utilis<69>s pour lier
|
|
|
|
|
des associations et d<>finir des requ<71>tes qui initialisent des collections.
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><sql-query name="personsWith">
|
|
|
|
|
<return alias="person" class="eg.Person"/>
|
|
|
|
|
<return-join alias="address" property="person.mailingAddress"/>
|
|
|
|
|
SELECT person.NAME AS {person.name},
|
|
|
|
|
person.AGE AS {person.age},
|
|
|
|
|
person.SEX AS {person.sex},
|
|
|
|
|
adddress.STREET AS {address.street},
|
|
|
|
|
adddress.CITY AS {address.city},
|
|
|
|
|
adddress.STATE AS {address.state},
|
|
|
|
|
adddress.ZIP AS {address.zip}
|
|
|
|
|
FROM PERSON person
|
|
|
|
|
JOIN ADDRESS adddress
|
|
|
|
|
ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
|
|
|
|
|
WHERE person.NAME LIKE :namePattern
|
|
|
|
|
</sql-query></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
Une requ<71>te SQL nomm<6D>e peut retourner une valeur scalaire. Vous devez
|
|
|
|
|
sp<73>cifier l'alias de colonne et le type Hibernate utilisant l'<27>l<EFBFBD>ment
|
|
|
|
|
<literal><return-scalar></literal> :</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><sql-query name="mySqlQuery">
|
|
|
|
|
<return-scalar column="name" type="string"/>
|
|
|
|
|
<return-scalar column="age" type="long"/>
|
|
|
|
|
SELECT p.NAME AS name,
|
|
|
|
|
p.AGE AS age,
|
|
|
|
|
FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
|
|
|
|
|
</sql-query></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
Vous pouvez externaliser les informations de mapping des r<>sultats dans un
|
|
|
|
|
<20>l<EFBFBD>ment <literal><resultset></literal> pour soit les r<>utiliser
|
|
|
|
|
dans diff<66>rentes requ<71>tes nomm<6D>es, soit <20> travers l'API
|
|
|
|
|
<literal>setResultSetMapping()</literal>.
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><resultset name="personAddress">
|
|
|
|
|
<return alias="person" class="eg.Person"/>
|
|
|
|
|
<return-join alias="address" property="person.mailingAddress"/>
|
|
|
|
|
</resultset>
|
|
|
|
|
|
|
|
|
|
<sql-query name="personsWith" resultset-ref="personAddress">
|
|
|
|
|
SELECT person.NAME AS {person.name},
|
|
|
|
|
person.AGE AS {person.age},
|
|
|
|
|
person.SEX AS {person.sex},
|
|
|
|
|
adddress.STREET AS {address.street},
|
|
|
|
|
adddress.CITY AS {address.city},
|
|
|
|
|
adddress.STATE AS {address.state},
|
|
|
|
|
adddress.ZIP AS {address.zip}
|
|
|
|
|
FROM PERSON person
|
|
|
|
|
JOIN ADDRESS adddress
|
|
|
|
|
ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
|
|
|
|
|
WHERE person.NAME LIKE :namePattern
|
|
|
|
|
</sql-query></programlisting>
|
|
|
|
|
|
|
|
|
|
<sect2 id="propertyresults">
|
|
|
|
|
<title>Utilisation de return-property pour sp<73>cifier explicitement les noms des colonnes/alias</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
Avec <literal><return-property></literal> vous pouvez explicitement dire
|
|
|
|
|
<20> Hibernate quels alias de colonne utiliser, plutot que d'employer la syntaxe
|
|
|
|
|
<literal>{}</literal> pour laisser Hibernate injecter ses propres alias.
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><sql-query name="mySqlQuery">
|
|
|
|
|
<return alias="person" class="eg.Person">
|
|
|
|
|
<return-property name="name" column="myName"/>
|
|
|
|
|
<return-property name="age" column="myAge"/>
|
|
|
|
|
<return-property name="sex" column="mySex"/>
|
|
|
|
|
</return>
|
|
|
|
|
SELECT person.NAME AS myName,
|
|
|
|
|
person.AGE AS myAge,
|
|
|
|
|
person.SEX AS mySex,
|
|
|
|
|
FROM PERSON person WHERE person.NAME LIKE :name
|
|
|
|
|
</sql-query>
|
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
|
|
<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<69> des propri<72>t<EFBFBD>s multi-colonnes.
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><sql-query name="organizationCurrentEmployments">
|
|
|
|
|
<return alias="emp" class="Employment">
|
|
|
|
|
<return-property name="salary">
|
|
|
|
|
<return-column name="VALUE"/>
|
|
|
|
|
<return-column name="CURRENCY"/>
|
|
|
|
|
</return-property>
|
|
|
|
|
<return-property name="endDate" column="myEndDate"/>
|
|
|
|
|
</return>
|
|
|
|
|
SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
|
|
|
|
|
STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
|
|
|
|
|
REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
|
|
|
|
|
FROM EMPLOYMENT
|
|
|
|
|
WHERE EMPLOYER = :id AND ENDDATE IS NULL
|
|
|
|
|
ORDER BY STARTDATE ASC
|
|
|
|
|
</sql-query></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
Notez que dans cet exemple nous avons utilis<69> <literal><return-property></literal>
|
|
|
|
|
en combinaison avec la syntaxe <literal>{}</literal> pour l'injection. Cela autorise les
|
|
|
|
|
utilisateurs <20> choisir comment ils veulent r<>f<EFBFBD>rencer les colonnes et les propri<72>t<EFBFBD>s.
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
Si votre mapping a un discriminant vous devez utiliser
|
|
|
|
|
<literal><return-discriminator></literal> pour sp<73>cifier la colonne
|
|
|
|
|
discriminante.
|
|
|
|
|
</para>
|
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
|
|
<sect2 id="sp_query" revision="1">
|
|
|
|
|
<title>Utilisation de proc<6F>dures stock<63>es pour les requ<71>tes</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
Hibernate 3 introduit le support des requ<71>tes via proc<6F>dures stock<63>es et les fonctions.
|
|
|
|
|
La documentation suivante est valable pour les deux.
|
|
|
|
|
Les proc<6F>dures stock<63>es/fonctions doivent retourner l'ensemble de r<>sultats en tant que
|
|
|
|
|
premier param<61>tre sortant (NdT: "out-parameter") pour <20>tre capable de fonctionner
|
|
|
|
|
avec Hibernate. Un exemple d'une telle proc<6F>dure stock<63>e en Oracle 9 et
|
|
|
|
|
version sup<75>rieure :
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<programlisting>CREATE OR REPLACE FUNCTION selectAllEmployments
|
|
|
|
|
RETURN SYS_REFCURSOR
|
|
|
|
|
AS
|
|
|
|
|
st_cursor SYS_REFCURSOR;
|
|
|
|
|
BEGIN
|
|
|
|
|
OPEN st_cursor FOR
|
|
|
|
|
SELECT EMPLOYEE, EMPLOYER,
|
|
|
|
|
STARTDATE, ENDDATE,
|
|
|
|
|
REGIONCODE, EID, VALUE, CURRENCY
|
|
|
|
|
FROM EMPLOYMENT;
|
|
|
|
|
RETURN st_cursor;
|
|
|
|
|
END;</programlisting>
|
|
|
|
|
|
|
|
|
|
<para>Pour utiliser cette requ<71>te dans Hibernate vous avez besoin de la mapper via une requ<71>te nomm<6D>e.</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><sql-query name="selectAllEmployees_SP" callable="true">
|
|
|
|
|
<return alias="emp" class="Employment">
|
|
|
|
|
<return-property name="employee" column="EMPLOYEE"/>
|
|
|
|
|
<return-property name="employer" column="EMPLOYER"/>
|
|
|
|
|
<return-property name="startDate" column="STARTDATE"/>
|
|
|
|
|
<return-property name="endDate" column="ENDDATE"/>
|
|
|
|
|
<return-property name="regionCode" column="REGIONCODE"/>
|
|
|
|
|
<return-property name="id" column="EID"/>
|
|
|
|
|
<return-property name="salary">
|
|
|
|
|
<return-column name="VALUE"/>
|
|
|
|
|
<return-column name="CURRENCY"/>
|
|
|
|
|
</return-property>
|
|
|
|
|
</return>
|
|
|
|
|
{ ? = call selectAllEmployments() }
|
|
|
|
|
</sql-query></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
Notez que les proc<6F>dures stock<63>es retournent, pour le moment, seulement des
|
|
|
|
|
scalaires et des entit<69>s. <literal><return-join></literal> et
|
|
|
|
|
<literal><load-collection></literal> ne sont pas support<72>s.
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<sect3 id="querysql-limits-storedprocedures" revision="1">
|
|
|
|
|
<title>R<EFBFBD>gles/limitations lors de l'utilisation des proc<6F>dures stock<63>es</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
Pur utiliser des proc<6F>dures stock<63>es avec Hibernate, les proc<6F>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<6F>dures vous
|
|
|
|
|
devez les ex<65>cuter via <literal>session.connection()</literal>. Les r<>gles
|
|
|
|
|
sont diff<66>rentes pour chaque base de donn<6E>es, puisque les vendeurs de base
|
|
|
|
|
de donn<6E>es ont des s<>mantiques/syntaxes diff<66>rentes pour les proc<6F>dures stock<63>es.
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
<para>Les requ<71>tes de proc<6F>dures stock<63>es ne peuvent pas <20>tre pagin<69>es avec
|
|
|
|
|
<literal>setFirstResult()/setMaxResults()</literal>.</para>
|
|
|
|
|
|
|
|
|
|
<para>Pour Oracle les r<>gles suivantes s'appliquent :</para>
|
|
|
|
|
|
|
|
|
|
<itemizedlist spacing="compact">
|
|
|
|
|
<listitem>
|
|
|
|
|
<para>
|
|
|
|
|
La proc<6F>dure doit retourner un ensemble de r<>sultats. Le
|
|
|
|
|
prmeier param<61>tre d'une proc<6F>dure doit <20>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>
|
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
|
|
|
|
<para>Pour Sybase ou MS SQL server les r<>gles suivantes s'appliquent :</para>
|
|
|
|
|
|
|
|
|
|
<itemizedlist spacing="compact">
|
|
|
|
|
<listitem>
|
|
|
|
|
<para>La proc<6F>dure doit retourner un ensemble de r<>sultats. Notez que comme
|
|
|
|
|
ces serveurs peuvent retourner de multiples ensembles de r<>sultats et mettre <20> jour
|
|
|
|
|
des compteurs, Hibernate it<69>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<6F>.</para>
|
|
|
|
|
</listitem>
|
|
|
|
|
|
|
|
|
|
<listitem>
|
|
|
|
|
<para>Si vous pouvez activer <literal>SET NOCOUNT ON</literal> dans votre proc<6F>dure,
|
|
|
|
|
elle sera probablement plus efficace, mais ce n'est pas une obligation.</para>
|
|
|
|
|
</listitem>
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
</sect3>
|
|
|
|
|
</sect2>
|
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
<sect1 id="querysql-cud">
|
|
|
|
|
<title>SQL personnalis<69> pour cr<63>er, mettre <20> jour et effacer</title>
|
|
|
|
|
|
|
|
|
|
<para>
|
|
|
|
|
Hibernate3 peut utiliser des expression SQL personnalis<69>es pour des op<6F>rations de cr<63>ation,
|
|
|
|
|
de mise <20> jour, et de suppression. Les objets persistants les classes et les collections
|
|
|
|
|
dans Hibernate contiennent d<>j<EFBFBD> un ensemble de cha<68>nes de caract<63>res g<>n<EFBFBD>r<EFBFBD>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<68>nes de caract<63>res :</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><class name="Person">
|
|
|
|
|
<id name="id">
|
|
|
|
|
<generator class="increment"/>
|
|
|
|
|
</id>
|
|
|
|
|
<property name="name" not-null="true"/>
|
|
|
|
|
<sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
|
|
|
|
|
<sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
|
|
|
|
|
<sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
|
|
|
|
|
</class></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>Le SQL est directement ex<65>cut<75> dans votre base de donn<6E>es, donc vous <20>tes libre d'utiliser
|
|
|
|
|
le dialecte que vous souhaitez. Cela r<>duira bien s<>r la portabilit<69> de votre mapping si vous
|
|
|
|
|
utilisez du SQL sp<73>cifique <20> votre base de donn<6E>es.</para>
|
|
|
|
|
|
|
|
|
|
<para>Les proc<6F>dures stock<63>es sont support<72>es si l'attribut <literal>callable</literal> est param<61>tr<74> :</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><class name="Person">
|
|
|
|
|
<id name="id">
|
|
|
|
|
<generator class="increment"/>
|
|
|
|
|
</id>
|
|
|
|
|
<property name="name" not-null="true"/>
|
|
|
|
|
<sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
|
|
|
|
|
<sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
|
|
|
|
|
<sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
|
|
|
|
|
</class></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>L'ordre des param<61>tres positionnels est actuellement vital, car ils doivent <20>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<69>,
|
|
|
|
|
Hibernate imprimera le SQL statique qui est utilis<69> pour cr<63>er, mettre <20> jour,
|
|
|
|
|
supprimer, etc. des entit<69>s. (Pour voir la s<>quence attendue, rappelez-vous de ne pas
|
|
|
|
|
inclure votre SQL personnalis<69> dans les fichiers de mapping de mani<6E>re <20> surcharger le
|
|
|
|
|
SQL statique g<>n<EFBFBD>r<EFBFBD> par Hibernate.)</para>
|
|
|
|
|
|
|
|
|
|
<para>Les proc<6F>dures stock<63>es sont dans la plupart des cas (lire : il vaut mieux le faire)
|
|
|
|
|
requises pour retourner le nombre de lignes ins<6E>r<EFBFBD>es/mises <20> jour/supprim<69>es, puisque
|
|
|
|
|
Hibernate fait quelques v<>rifications de succ<63>s lors de l'ex<65>cution de l'expression.
|
|
|
|
|
Hibernate inscrit toujours la premi<6D>re expression comme un param<61>tre de sortie num<75>rique pour les
|
|
|
|
|
op<6F>rations CUD :</para>
|
|
|
|
|
|
|
|
|
|
<programlisting>CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
|
|
|
|
|
RETURN NUMBER IS
|
|
|
|
|
BEGIN
|
|
|
|
|
|
|
|
|
|
update PERSON
|
|
|
|
|
set
|
|
|
|
|
NAME = uname,
|
|
|
|
|
where
|
|
|
|
|
ID = uid;
|
|
|
|
|
|
|
|
|
|
return SQL%ROWCOUNT;
|
|
|
|
|
|
|
|
|
|
END updatePerson;</programlisting>
|
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
<sect1 id="querysql-load">
|
|
|
|
|
<title>SQL personnalis<69> pour le chargement</title>
|
|
|
|
|
|
|
|
|
|
<para>Vous pouvez aussi d<>clarer vos propres requ<71>tes SQL (ou HQL) pour le chargement d'entit<69> :</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><sql-query name="person">
|
|
|
|
|
<return alias="pers" class="Person" lock-mode="upgrade"/>
|
|
|
|
|
SELECT NAME AS {pers.name}, ID AS {pers.id}
|
|
|
|
|
FROM PERSON
|
|
|
|
|
WHERE ID=?
|
|
|
|
|
FOR UPDATE
|
|
|
|
|
</sql-query></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>Ceci est juste une d<>claration de requ<71>te nomm<6D>e, comme vu plus t<>t. Vous pouvez r<>f<EFBFBD>rencer
|
|
|
|
|
cette requ<71>te nomm<6D>e dans un mapping de classe :</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><class name="Person">
|
|
|
|
|
<id name="id">
|
|
|
|
|
<generator class="increment"/>
|
|
|
|
|
</id>
|
|
|
|
|
<property name="name" not-null="true"/>
|
|
|
|
|
<loader query-ref="person"/>
|
|
|
|
|
</class></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>Ceci fonctionne m<>me avec des proc<6F>dures stock<63>es.</para>
|
|
|
|
|
|
|
|
|
|
<para>Vous pouvez m<>me d<>finir une requ<71>te pour le chargement d'une collection :</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><set name="employments" inverse="true">
|
|
|
|
|
<key/>
|
|
|
|
|
<one-to-many class="Employment"/>
|
|
|
|
|
<loader query-ref="employments"/>
|
|
|
|
|
</set></programlisting>
|
|
|
|
|
|
|
|
|
|
<programlisting><sql-query name="employments">
|
|
|
|
|
<load-collection alias="emp" role="Person.employments"/>
|
|
|
|
|
SELECT {emp.*}
|
|
|
|
|
FROM EMPLOYMENT emp
|
|
|
|
|
WHERE EMPLOYER = :id
|
|
|
|
|
ORDER BY STARTDATE ASC, EMPLOYEE ASC
|
|
|
|
|
</sql-query></programlisting>
|
|
|
|
|
|
|
|
|
|
<para>Vous pourriez m<>me d<>finir un chargeur d'entit<69> qui charge une collection par jointure :</para>
|
|
|
|
|
|
|
|
|
|
<programlisting><sql-query name="person">
|
|
|
|
|
<return alias="pers" class="Person"/>
|
|
|
|
|
<return-join alias="emp" property="pers.employments"/>
|
|
|
|
|
SELECT NAME AS {pers.*}, {emp.*}
|
|
|
|
|
FROM PERSON pers
|
|
|
|
|
LEFT OUTER JOIN EMPLOYMENT emp
|
|
|
|
|
ON pers.ID = emp.PERSON_ID
|
|
|
|
|
WHERE ID=?
|
|
|
|
|
</sql-query></programlisting>
|
|
|
|
|
</sect1>
|
|
|
|
|
</chapter>
|