Match to latest English XML
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@14142 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
f134d4ab5c
commit
1a1fc99092
|
@ -323,6 +323,14 @@
|
||||||
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>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>org.hibernate.context.ManagedSessionContext</literal> - current
|
||||||
|
sessions are tracked by thread of execution. However, you are responsible to
|
||||||
|
bind and unbind a <literal>Session</literal> instance with static methods
|
||||||
|
on this class, it does never open, flush, or close a <literal>Session</literal>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
|
|
@ -365,7 +365,14 @@ create table Address ( addressId bigint not null primary key )
|
||||||
<one-to-many class="Person"/>
|
<one-to-many class="Person"/>
|
||||||
</list>
|
</list>
|
||||||
</class>]]></programlisting>
|
</class>]]></programlisting>
|
||||||
|
<para>
|
||||||
|
It is important that you define <literal>not-null="true"</literal> on the
|
||||||
|
<literal><key></literal> element of the collection mapping if the
|
||||||
|
underlying foreign key column is <literal>NOT NULL</literal>. Don't only
|
||||||
|
declare <literal>not-null="true"</literal> on a possible nested
|
||||||
|
<literal><column></literal> element, but on the <literal><key></literal>
|
||||||
|
element.
|
||||||
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="assoc-bidirectional-121">
|
<sect2 id="assoc-bidirectional-121">
|
||||||
|
|
|
@ -98,8 +98,61 @@
|
||||||
des recherches de la DTD sur Internet, vérifiez votre déclaration de DTD par rapport
|
des recherches de la DTD sur Internet, vérifiez votre déclaration de DTD par rapport
|
||||||
au contenu de votre classpath.
|
au contenu de votre classpath.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
<sect3 id="mapping-declaration-entity-resolution">
|
||||||
<sect2 id="mapping-declaration-mapping" revision="3">
|
<title>EntityResolver</title>
|
||||||
|
<para>
|
||||||
|
As mentioned previously, Hibernate will first attempt to resolve DTDs in its classpath. The
|
||||||
|
manner in which it does this is by registering a custom <literal>org.xml.sax.EntityResolver</literal>
|
||||||
|
implementation with the SAXReader it uses to read in the xml files. This custom
|
||||||
|
<literal>EntityResolver</literal> recognizes two different systemId namespaces.
|
||||||
|
</para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a <literal>hibernate namespace</literal> is recognized whenever the
|
||||||
|
resolver encounteres a systemId starting with
|
||||||
|
<literal>http://hibernate.sourceforge.net/</literal>; the resolver
|
||||||
|
attempts to resolve these entities via the classlaoder which loaded
|
||||||
|
the Hibernate classes.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a <literal>user namespace</literal> is recognized whenever the
|
||||||
|
resolver encounteres a systemId using a <literal>classpath://</literal>
|
||||||
|
URL protocol; the resolver will attempt to resolve these entities
|
||||||
|
via (1) the current thread context classloader and (2) the
|
||||||
|
classloader which loaded the Hibernate classes.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
<para>
|
||||||
|
An example of utilizing user namespacing:
|
||||||
|
</para>
|
||||||
|
<programlisting><![CDATA[<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE hibernate-mapping PUBLIC
|
||||||
|
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||||
|
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" [
|
||||||
|
<!ENTITY types SYSTEM "classpath://your/domain/types.xml">
|
||||||
|
]>
|
||||||
|
|
||||||
|
<hibernate-mapping package="your.domain">
|
||||||
|
<class name="MyEntity">
|
||||||
|
<id name="id" type="my-custom-id-type">
|
||||||
|
...
|
||||||
|
</id>
|
||||||
|
<class>
|
||||||
|
&types;
|
||||||
|
</hibernate-mapping>]]></programlisting>
|
||||||
|
<para>
|
||||||
|
Where <literal>types.xml</literal> is a resource in the <literal>your.domain</literal>
|
||||||
|
package and contains a custom <link linkend="mapping-types-custom">typedef</link>.
|
||||||
|
</para>
|
||||||
|
</sect3>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="mapping-declaration-mapping" revision="3">
|
||||||
<title>hibernate-mapping</title>
|
<title>hibernate-mapping</title>
|
||||||
<para>
|
<para>
|
||||||
Cet élément a plusieurs attributs optionnels. Les attributs <literal>schema</literal> et <literal>catalog</literal>
|
Cet élément a plusieurs attributs optionnels. Les attributs <literal>schema</literal> et <literal>catalog</literal>
|
||||||
|
@ -357,19 +410,14 @@
|
||||||
pour plus d'informations.
|
pour plus d'informations.
|
||||||
</para>
|
</para>
|
||||||
</callout>
|
</callout>
|
||||||
|
|
||||||
<callout arearefs="class18">
|
<callout arearefs="class18">
|
||||||
<para>
|
|
||||||
<literal>catalog</literal> (optionnel) : The name of a database catalog used for this
|
|
||||||
class and its table.
|
|
||||||
</para>
|
|
||||||
</callout>
|
|
||||||
<callout arearefs="class19">
|
|
||||||
<para>
|
<para>
|
||||||
<literal>check</literal> (optionnel) : expression SQL utilisée pour générer une contrainte
|
<literal>check</literal> (optionnel) : expression SQL utilisée pour générer une contrainte
|
||||||
de vérification multi-lignes pour la génération automatique de schéma.
|
de vérification multi-lignes pour la génération automatique de schéma.
|
||||||
</para>
|
</para>
|
||||||
</callout>
|
</callout>
|
||||||
<callout arearefs="class20">
|
<callout arearefs="class19">
|
||||||
<para>
|
<para>
|
||||||
<literal>rowid</literal> (optionnel) : Hibernate peut utiliser des ROWID sur les bases de
|
<literal>rowid</literal> (optionnel) : Hibernate peut utiliser des ROWID sur les bases de
|
||||||
données qui utilisent ce mécanisme. Par exemple avec Oracle, Hibernate peut utiliser la colonne additionnelle
|
données qui utilisent ce mécanisme. Par exemple avec Oracle, Hibernate peut utiliser la colonne additionnelle
|
||||||
|
@ -377,14 +425,14 @@
|
||||||
la localisation physique d'un tuple enregistré.
|
la localisation physique d'un tuple enregistré.
|
||||||
</para>
|
</para>
|
||||||
</callout>
|
</callout>
|
||||||
<callout arearefs="class21">
|
<callout arearefs="class20">
|
||||||
<para>
|
<para>
|
||||||
<literal>subselect</literal> (optionnel) : Permet de mapper une entité immuable en lecture-seule
|
<literal>subselect</literal> (optionnel) : Permet de mapper une entité immuable en lecture-seule
|
||||||
sur un sous-select de base de données. Utile pour avoir une vue au lieu d'une table en base, mais à éviter. Voir plus bas
|
sur un sous-select de base de données. Utile pour avoir une vue au lieu d'une table en base, mais à éviter. Voir plus bas
|
||||||
pour plus d'information.
|
pour plus d'information.
|
||||||
</para>
|
</para>
|
||||||
</callout>
|
</callout>
|
||||||
<callout arearefs="class22">
|
<callout arearefs="class21">
|
||||||
<para>
|
<para>
|
||||||
<literal>abstract</literal> (optionnel) : Utilisé pour marquer des superclasses abstraites dans
|
<literal>abstract</literal> (optionnel) : Utilisé pour marquer des superclasses abstraites dans
|
||||||
des hiérarchies de <literal><union-subclass></literal>.
|
des hiérarchies de <literal><union-subclass></literal>.
|
||||||
|
@ -733,6 +781,19 @@
|
||||||
avec une association <literal><one-to-one></literal> sur la clef primaire.
|
avec une association <literal><one-to-one></literal> sur la clef primaire.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
</varlistentry> <varlistentry>
|
||||||
|
<term><literal>sequence-identity</literal></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a specialized sequence generation strategy which utilizes a
|
||||||
|
database sequence for the actual value generation, but combines
|
||||||
|
this with JDBC3 getGeneratedKeys to actually return the generated
|
||||||
|
identifier value as part of the insert statement execution. This
|
||||||
|
strategy is only known to be supported on Oracle 10g drivers
|
||||||
|
targetted for JDK 1.4. Note comments on these insert statements
|
||||||
|
are disabled due to a bug in the Oracle drivers.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</para>
|
</para>
|
||||||
|
@ -829,7 +890,177 @@
|
||||||
</para>
|
</para>
|
||||||
</sect3>
|
</sect3>
|
||||||
</sect2>
|
</sect2>
|
||||||
<sect2 id="mapping-declaration-compositeid" revision="3">
|
|
||||||
|
|
||||||
|
<sect2 id="mapping-declaration-id-enhanced">
|
||||||
|
<title>Enhanced identifier generators</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Starting with release 3.2.3, there are 2 new generators which represent a re-thinking of 2 different
|
||||||
|
aspects of identifier generation. The first aspect is database portability; the second is optimization
|
||||||
|
(not having to query the database for every request for a new identifier value). These two new
|
||||||
|
generators are intended to take the place of some of the named generators described above (starting
|
||||||
|
in 3.3.x); however, they are included in the current releases and can be referenced by FQN.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The first of these new generators is <literal>org.hibernate.id.enhanced.SequenceStyleGenerator</literal>
|
||||||
|
which is intended firstly as a replacement for the <literal>sequence</literal> generator and secondly as
|
||||||
|
a better portability generator than <literal>native</literal> (because <literal>native</literal>
|
||||||
|
(generally) chooses between <literal>identity</literal> and <literal>sequence</literal> which have
|
||||||
|
largely different semantics which can cause subtle isssues in applications eyeing portability).
|
||||||
|
<literal>org.hibernate.id.enhanced.SequenceStyleGenerator</literal> however achieves portability in
|
||||||
|
a different manner. It chooses between using a table or a sequence in the database to store its
|
||||||
|
incrementing values depending on the capabilities of the dialect being used. The difference between this
|
||||||
|
and <literal>native</literal> is that table-based and sequence-based storage have the same exact
|
||||||
|
semantic (in fact sequences are exactly what Hibernate tries to emmulate with its table-based
|
||||||
|
generators). This generator has a number of configuration parameters:
|
||||||
|
<itemizedlist spacing="compact">
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>sequence_name</literal> (optional, defaults to <literal>hibernate_sequence</literal>):
|
||||||
|
The name of the sequence (or table) to be used.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>initial_value</literal> (optional, defaults to <literal>1</literal>): The initial
|
||||||
|
value to be retrieved from the sequence/table. In sequence creation terms, this is analogous
|
||||||
|
to the clause typical named "STARTS WITH".
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>increment_size</literal> (optional, defaults to <literal>1</literal>): The value by
|
||||||
|
which subsequent calls to the sequence/table should differ. In sequence creation terms, this
|
||||||
|
is analogous to the clause typical named "INCREMENT BY".
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>force_table_use</literal> (optional, defaults to <literal>false</literal>): Should
|
||||||
|
we force the use of a table as the backing structure even though the dialect might support
|
||||||
|
sequence?
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>value_column</literal> (optional, defaults to <literal>next_val</literal>): Only
|
||||||
|
relevant for table structures! The name of the column on the table which is used to
|
||||||
|
hold the value.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>optimizer</literal> (optional, defaults to <literal>none</literal>):
|
||||||
|
See <xref linkend="mapping-declaration-id-enhanced-optimizers"/>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The second of these new generators is <literal>org.hibernate.id.enhanced.TableGenerator</literal> which
|
||||||
|
is intended firstly as a replacement for the <literal>table</literal> generator (although it actually
|
||||||
|
functions much more like <literal>org.hibernate.id.MultipleHiLoPerTableGenerator</literal>) and secondly
|
||||||
|
as a re-implementation of <literal>org.hibernate.id.MultipleHiLoPerTableGenerator</literal> utilizing the
|
||||||
|
notion of pluggable optimiziers. Essentially this generator defines a table capable of holding
|
||||||
|
a number of different increment values simultaneously by using multiple distinctly keyed rows. This
|
||||||
|
generator has a number of configuration parameters:
|
||||||
|
<itemizedlist spacing="compact">
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>table_name</literal> (optional, defaults to <literal>hibernate_sequences</literal>):
|
||||||
|
The name of the table to be used.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>value_column_name</literal> (optional, defaults to <literal>next_val</literal>):
|
||||||
|
The name of the column on the table which is used to hold the value.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>segment_column_name</literal> (optional, defaults to <literal>sequence_name</literal>):
|
||||||
|
The name of the column on the table which is used to hold the "segement key". This is the
|
||||||
|
value which distinctly identifies which increment value to use.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>segment_value</literal> (optional, defaults to <literal>default</literal>):
|
||||||
|
The "segment key" value for the segment from which we want to pull increment values for
|
||||||
|
this generator.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>segment_value_length</literal> (optional, defaults to <literal>255</literal>):
|
||||||
|
Used for schema generation; the column size to create this segment key column.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>initial_value</literal> (optional, defaults to <literal>1</literal>):
|
||||||
|
The initial value to be retrieved from the table.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>increment_size</literal> (optional, defaults to <literal>1</literal>):
|
||||||
|
The value by which subsequent calls to the table should differ.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>optimizer</literal> (optional, defaults to <literal></literal>):
|
||||||
|
See <xref linkend="mapping-declaration-id-enhanced-optimizers"/>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="mapping-declaration-id-enhanced-optimizers">
|
||||||
|
<title>Identifier generator optimization</title>
|
||||||
|
<para>
|
||||||
|
For identifier generators which store values in the database, it is inefficient for them to hit the
|
||||||
|
database on each and every call to generate a new identifier value. Instead, you'd ideally want to
|
||||||
|
group a bunch of them in memory and only hit the database when you have exhausted your in-memory
|
||||||
|
value group. This is the role of the pluggable optimizers. Currently only the two enhanced generators
|
||||||
|
(<xref linkend="mapping-declaration-id-enhanced"/> support this notion.
|
||||||
|
<itemizedlist spacing="compact">
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>none</literal> (generally this is the default if no optimizer was specified): This
|
||||||
|
says to not perform any optimizations, and hit the database each and every request.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>hilo</literal>: applies a hi/lo algorithm around the database retrieved values. The
|
||||||
|
values from the database for this optimizer are expected to be sequential. The values
|
||||||
|
retrieved from the database structure for this optimizer indicates the "group number"; the
|
||||||
|
<literal>increment_size</literal> is multiplied by that value in memory to define a group
|
||||||
|
"hi value".
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>pooled</literal>: like was discussed for <literal>hilo</literal>, this optimizers
|
||||||
|
attempts to minimize the number of hits to the database. Here, however, we simply store
|
||||||
|
the starting value for the "next group" into the database structure rather than a sequential
|
||||||
|
value in combination with an in-memory grouping algorithm. <literal>increment_size</literal>
|
||||||
|
here refers to the values coming from the database.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<sect2 id="mapping-declaration-compositeid" revision="3">
|
||||||
<title>composite-id</title>
|
<title>composite-id</title>
|
||||||
<programlisting><![CDATA[<composite-id
|
<programlisting><![CDATA[<composite-id
|
||||||
name="propertyName"
|
name="propertyName"
|
||||||
|
|
|
@ -713,21 +713,28 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
||||||
<emphasis role="strong">ex.</emphasis>
|
<emphasis role="strong">ex.</emphasis>
|
||||||
<literal>on_close</literal> (default) | <literal>after_transaction</literal> |
|
<literal>on_close</literal> (default) | <literal>after_transaction</literal> |
|
||||||
<literal>after_statement</literal> | <literal>auto</literal>
|
<literal>after_statement</literal> | <literal>auto</literal>
|
||||||
|
</para> <para>
|
||||||
|
Note that this setting only affects <literal>Session</literal>s returned from
|
||||||
|
<literal>SessionFactory.openSession</literal>. For <literal>Session</literal>s
|
||||||
|
obtained through <literal>SessionFactory.getCurrentSession</literal>, the
|
||||||
|
<literal>CurrentSessionContext</literal> implementation configured for use
|
||||||
|
controls the connection release mode for those <literal>Session</literal>s.
|
||||||
|
See <xref linkend="architecture-current-session"/>
|
||||||
</para>
|
</para>
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>
|
<entry>
|
||||||
<literal>hibernate.connection.<emphasis><propertyName></emphasis></literal>
|
<literal>hibernate.connection.</literal><emphasis><propertyName></emphasis>
|
||||||
</entry>
|
</entry>
|
||||||
<entry>
|
<entry>
|
||||||
Passe la propriété JDBC<literal>propertyName</literal>
|
Passe la propriété JDBC <emphasis><propertyName></emphasis>
|
||||||
à <literal>DriverManager.getConnection()</literal>.
|
à <literal>DriverManager.getConnection()</literal>.
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>
|
<entry>
|
||||||
<literal>hibernate.jndi.<emphasis><propertyName></emphasis></literal>
|
<literal>hibernate.jndi.</literal><emphasis><propertyName></emphasis>
|
||||||
</entry>
|
</entry>
|
||||||
<entry>
|
<entry>
|
||||||
Passe la propriété <literal>propertyName</literal> à l'<literal>InitialContextFactory</literal>
|
Passe la propriété <literal>propertyName</literal> à l'<literal>InitialContextFactory</literal>
|
||||||
|
@ -1415,7 +1422,13 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
||||||
|
|
||||||
<programlisting><![CDATA[SessionFactory sf = new Configuration().configure().buildSessionFactory();]]></programlisting>
|
<programlisting><![CDATA[SessionFactory sf = new Configuration().configure().buildSessionFactory();]]></programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
You can pick a different XML configuration file using
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting><![CDATA[SessionFactory sf = new Configuration()
|
||||||
|
.configure("catdb.cfg.xml")
|
||||||
|
.buildSessionFactory();]]></programlisting>
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
|
|
|
@ -116,15 +116,26 @@ public class AuditInterceptor extends EmptyInterceptor {
|
||||||
|
|
||||||
}]]></programlisting>
|
}]]></programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
L'intercepteur doit être spécifié quand une session est créée.
|
Interceptors come in two flavors: <literal>Session</literal>-scoped and
|
||||||
|
<literal>SessionFactory</literal>-scoped.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
A <literal>Session</literal>-scoped interceptor is specified
|
||||||
|
when a session is opened using one of the overloaded SessionFactory.openSession()
|
||||||
|
methods accepting an <literal>Interceptor</literal>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
|
<programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Vous pouvez aussi mettre un intercepteur au niveau global, en utilisant l'objet <literal>Configuration</literal>.
|
A <literal>SessionFactory</literal>-scoped interceptor is registered with the <literal>Configuration</literal>
|
||||||
Dans ce cas, l'intercepteur doit être "threadsafe".
|
object prior to building the <literal>SessionFactory</literal>. In this case, the supplied interceptor
|
||||||
|
will be applied to all sessions opened from that <literal>SessionFactory</literal>; this is true unless
|
||||||
|
a session is opened explicitly specifying the interceptor to use. <literal>SessionFactory</literal>-scoped
|
||||||
|
interceptors must be thread safe, taking care to not store session-specific state since multiple
|
||||||
|
sessions will use this interceptor (potentially) concurrently.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
|
<programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
|
||||||
|
|
|
@ -719,7 +719,7 @@ Cat fritz = (Cat) iter.next();]]></programlisting>
|
||||||
<entry>OSCache</entry>
|
<entry>OSCache</entry>
|
||||||
<entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
|
<entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
|
||||||
<entry>mémoire, disque</entry>
|
<entry>mémoire, disque</entry>
|
||||||
<entry>oui (invalidation de cluster)</entry>
|
<entry></entry>
|
||||||
<entry>oui</entry>
|
<entry>oui</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
|
|
|
@ -214,6 +214,43 @@
|
||||||
<programlisting><![CDATA[from Cat as cat where cat.mate.name like '%s%']]></programlisting>
|
<programlisting><![CDATA[from Cat as cat where cat.mate.name like '%s%']]></programlisting>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="queryhql-identifier-property">
|
||||||
|
<title>Refering to identifier property</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
There are, generally speaking, 2 ways to refer to an entity's identifier property:
|
||||||
|
</para>
|
||||||
|
<itemizedlist spacing="compact">
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The special property (lowercase) <literal>id</literal> may be used to reference the identifier
|
||||||
|
property of an entity <emphasis>provided that entity does not define a non-identifier property
|
||||||
|
named id</emphasis>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
If the entity defines a named identifier property, you may use that property name.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
References to composite identifier properties follow the same naming rules. If the
|
||||||
|
entity has a non-identifier property named id, the composite identifier property can only
|
||||||
|
be referenced by its defined named; otherwise, the special <literal>id</literal> property
|
||||||
|
can be used to rerference the identifier property.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Note: this has changed significantly starting in version 3.2.2. In previous versions,
|
||||||
|
<literal>id</literal> <emphasis>always</emphasis> referred to the identifier property no
|
||||||
|
matter what its actual name. A ramification of that decision was that non-identifier
|
||||||
|
properties named <literal>id</literal> could never be referenced in Hibernate queries.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
|
||||||
<sect1 id="queryhql-select">
|
<sect1 id="queryhql-select">
|
||||||
<title>La clause select</title>
|
<title>La clause select</title>
|
||||||
|
|
||||||
|
@ -904,34 +941,10 @@ from Cat as cat]]></programlisting>
|
||||||
Notez que les sous-requêtes HQL peuvent arriver seulememnt dans les clauses select ou where.
|
Notez que les sous-requêtes HQL peuvent arriver seulememnt dans les clauses select ou where.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Pour des sous-requêtes avec plus d'une expression dans le select, vous pouvez utiliser un constructeur de tuples :
|
Note that subqueries can also utilize <literal>row value constructor</literal> syntax. See
|
||||||
|
<xref linkend="queryhql-tuple"/> for more details.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><![CDATA[from Cat as cat
|
|
||||||
where not ( cat.name, cat.color ) in (
|
|
||||||
select cat.name, cat.color from DomesticCat cat
|
|
||||||
)]]></programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Notez que sur certaines bases de données (mais par Oracle ou HSQL), vous pouvez utiliser des constructeurs de tuples
|
|
||||||
dans d'autres contextes, par exemple lors du requêtage de composants ou de types utilisateur composites :
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<programlisting><![CDATA[from Person where name = ('Gavin', 'A', 'King')]]></programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Ce qui est équivalent à la forme plus verbeuse suivante :
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<programlisting><![CDATA[from Person where name.first = 'Gavin' and name.initial = 'A' and name.last = 'King')]]></programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Il y a deux bonnes raisons que vous ne puissiez ne pas vouloir faire cette sorte de choses : d'abord, ce n'est
|
|
||||||
pas complètement portable entre les plateformes de base de données ; deuxièmement, la requête est maintenant
|
|
||||||
dépendante de l'ordre des propriétés dans le document de mapping.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="queryhql-examples">
|
<sect1 id="queryhql-examples">
|
||||||
|
|
|
@ -23,225 +23,378 @@
|
||||||
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>
|
</para>
|
||||||
|
|
||||||
<programlisting>List cats = sess.createSQLQuery("select * from cats")
|
|
||||||
.addEntity(Cat.class)
|
|
||||||
.list();</programlisting>
|
|
||||||
|
|
||||||
<para>Cette requête a spécifié :</para>
|
<sect2>
|
||||||
|
<title>Scalar queries</title>
|
||||||
|
|
||||||
<itemizedlist>
|
<para>The most basic SQL query is to get a list of scalars
|
||||||
<listitem>
|
(values).</para>
|
||||||
<para>la requête SQL</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").list();
|
||||||
<para>l'entité retournée par la requête</para>
|
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
|
||||||
</listitem>
|
]]></programlisting>
|
||||||
</itemizedlist>
|
|
||||||
|
|
||||||
<para>
|
<para>These will both return a List of Object arrays (Object[]) with
|
||||||
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
|
scalar values for each column in the CATS table. Hibernate will use
|
||||||
document de mapping. Cela peut être problématique pour des requêtes SQL qui joignent de multiple tables, puisque
|
ResultSetMetadata to deduce the actual order and types of the returned
|
||||||
les mêmes noms de colonne peuvent apparaître dans plus d'une table. La forme suivante n'est pas vulnérable à la
|
scalar values.</para>
|
||||||
duplication des noms de colonne :
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<programlisting>List cats = sess.createSQLQuery("select {cat.*} from cats cat")
|
<para>To avoid the overhead of using
|
||||||
.addEntity("cat", Cat.class)
|
<literal>ResultSetMetadata</literal> or simply to be more explicit in
|
||||||
.list();</programlisting>
|
what is returned one can use <literal>addScalar()</literal>.</para>
|
||||||
|
|
||||||
<para>Cette requête a spécifié :</para>
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
|
||||||
|
.addScalar("ID", Hibernate.LONG)
|
||||||
|
.addScalar("NAME", Hibernate.STRING)
|
||||||
|
.addScalar("BIRTHDATE", Hibernate.DATE)
|
||||||
|
]]></programlisting>
|
||||||
|
|
||||||
<itemizedlist>
|
<para>This query specified:</para>
|
||||||
<listitem>
|
|
||||||
<para>la requête SQL, avec un paramètre fictif pour Hibernate pour injecter les alias de colonne</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
<itemizedlist>
|
||||||
<para>l'entité retournée par la requête, et son alias de table SQL</para>
|
<listitem>
|
||||||
</listitem>
|
<para>the SQL query string</para>
|
||||||
</itemizedlist>
|
</listitem>
|
||||||
|
|
||||||
<para>
|
<listitem>
|
||||||
La méthode <literal>addEntity()</literal> associe l'alias de la table SQL
|
<para>the columns and types to return</para>
|
||||||
avec la classe de l'entité retournée, et détermine la forme de l'ensemble des résultats de la requête.
|
</listitem>
|
||||||
</para>
|
</itemizedlist>
|
||||||
|
|
||||||
<para>
|
<para>This will still return Object arrays, but now it will not use
|
||||||
La méthode <literal>addJoin()</literal> peut être utilisée pour charger des associations vers d'autres
|
<literal>ResultSetMetdata</literal> but will instead explicitly get the
|
||||||
entités et collections.
|
ID, NAME and BIRTHDATE column as respectively a Long, String and a Short
|
||||||
</para>
|
from the underlying resultset. This also means that only these three
|
||||||
|
columns will be returned, even though the query is using
|
||||||
|
<literal>*</literal> and could return more than the three listed
|
||||||
|
columns.</para>
|
||||||
|
|
||||||
<programlisting>List cats = sess.createSQLQuery(
|
<para>It is possible to leave out the type information for all or some
|
||||||
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
|
of the scalars.</para>
|
||||||
)
|
|
||||||
.addEntity("cat", Cat.class)
|
|
||||||
.addJoin("kitten", "cat.kittens")
|
|
||||||
.list();</programlisting>
|
|
||||||
|
|
||||||
<para>
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
|
||||||
Une requête SQL native pourrait retourner une simple valeur scalaire ou une combinaison de scalaires et d'entités.
|
.addScalar("ID", Hibernate.LONG)
|
||||||
</para>
|
.addScalar("NAME")
|
||||||
|
.addScalar("BIRTHDATE")
|
||||||
|
]]></programlisting>
|
||||||
|
|
||||||
<programlisting>Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")
|
<para>This is essentially the same query as before, but now
|
||||||
.addScalar("maxWeight", Hibernate.DOUBLE);
|
<literal>ResultSetMetaData</literal> is used to decide the type of NAME
|
||||||
.uniqueResult();</programlisting>
|
and BIRTHDATE where as the type of ID is explicitly specified.</para>
|
||||||
|
|
||||||
<para>Vous pouvez alternativement décrire les informations de mapping des résultats dans vos fichiers hbm
|
<para>How the java.sql.Types returned from ResultSetMetaData is mapped
|
||||||
et les utiliser pour vos requêtes.</para>
|
to Hibernate types is controlled by the Dialect. If a specific type is
|
||||||
|
not mapped or does not result in the expected type it is possible to
|
||||||
|
customize it via calls to <literal>registerHibernateType</literal> in
|
||||||
|
the Dialect.</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
<programlisting>List cats = sess.createSQLQuery(
|
<sect2>
|
||||||
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
|
<title>Entity queries</title>
|
||||||
)
|
|
||||||
.setResultSetMapping("catAndKitten")
|
|
||||||
.list();</programlisting>
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<sect1 id="querysql-aliasreferences">
|
<para>The above queries were all about returning scalar values,
|
||||||
<title>Alias et références de propriété</title>
|
basically returning the "raw" values from the resultset. The following
|
||||||
|
shows how to get entity objects from a native sql query via
|
||||||
|
<literal>addEntity()</literal>.</para>
|
||||||
|
|
||||||
<para>
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class);
|
||||||
La notation <literal>{cat.*}</literal> utilisée au-dessus est un raccourci pour "toutes les propriétés".
|
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);
|
||||||
Alternativement, vous pouvez lister explicitement les colonnes, mais même ce cas que nous laissons à Hibernate
|
]]></programlisting>
|
||||||
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>
|
<para>This query specified:</para>
|
||||||
La syntaxe <literal>{}</literal> <emphasis>n'est pas</emphasis> requise pour le requêtes nommées. Voir
|
|
||||||
<xref linkend="querysql-namedqueries" />.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<programlisting>String sql = "select cat.originalId as {cat.id}, " +
|
<itemizedlist>
|
||||||
"cat.mateid as {cat.mate}, cat.sex as {cat.sex}, " +
|
<listitem>
|
||||||
"cat.weight*10 as {cat.weight}, cat.name as {cat.name} " +
|
<para>the SQL query string</para>
|
||||||
"from cat_log cat where {cat.mate} = :catId"
|
</listitem>
|
||||||
|
|
||||||
List loggedCats = sess.createSQLQuery(sql)
|
<listitem>
|
||||||
.addEntity("cat", Cat.class)
|
<para>the entity returned by the query</para>
|
||||||
.setLong("catId", catId)
|
</listitem>
|
||||||
.list();</programlisting>
|
</itemizedlist>
|
||||||
|
|
||||||
<para>
|
<para>Assuming that Cat is mapped as a class with the columns ID, NAME
|
||||||
<emphasis>À noter :</emphasis> si vous listez chaque propriété explicitement, vous devez inclure
|
and BIRTHDATE the above queries will both return a List where each
|
||||||
toutes les propriétés de la classe <emphasis>et ses sous-classes</emphasis> !
|
element is a Cat entity.</para>
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
<para>If the entity is mapped with a <literal>many-to-one</literal> to
|
||||||
La table suivante montre les différentes possibilités d'utilisation de l'injection d'alias. À noter : les noms
|
another entity it is required to also return this when performing the
|
||||||
des alias dans le résultat sont des exemples, chaque alias aura un nom unique et probablement différent lors de l'utilisation.
|
native query, otherwise a database specific "column not found" error
|
||||||
</para>
|
will occur. The additional columns will automatically be returned when
|
||||||
|
using the * notation, but we prefer to be explicit as in the following
|
||||||
|
example for a <literal>many-to-one</literal> to a
|
||||||
|
<literal>Dog</literal>:</para>
|
||||||
|
|
||||||
<table frame="topbot" id="aliasinjection-summary">
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);
|
||||||
<title>Noms d'injection d'alias</title>
|
]]></programlisting>
|
||||||
|
|
||||||
<tgroup cols="4">
|
<para>This will allow cat.getDog() to function properly.</para>
|
||||||
<colspec colwidth="1*" />
|
</sect2>
|
||||||
|
|
||||||
<colspec colwidth="1*" />
|
<sect2>
|
||||||
|
<title>Handling associations and collections</title>
|
||||||
|
|
||||||
<colspec colwidth="2.5*" />
|
<para>It is possible to eagerly join in the <literal>Dog</literal> to
|
||||||
|
avoid the possible extra roundtrip for initializing the proxy. This is
|
||||||
|
done via the <literal>addJoin()</literal> method, which allows you to
|
||||||
|
join in an association or collection.</para>
|
||||||
|
|
||||||
<thead>
|
<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")
|
||||||
<row>
|
.addEntity("cat", Cat.class)
|
||||||
<entry>Description</entry>
|
.addJoin("cat.dog");
|
||||||
|
]]></programlisting>
|
||||||
|
|
||||||
<entry>Syntaxe</entry>
|
<para>In this example the returned <literal>Cat</literal>'s will have
|
||||||
|
their <literal>dog</literal> property fully initialized without any
|
||||||
|
extra roundtrip to the database. Notice that we added a alias name
|
||||||
|
("cat") to be able to specify the target property path of the join. It
|
||||||
|
is possible to do the same eager joining for collections, e.g. if the
|
||||||
|
<literal>Cat</literal> had a one-to-many to <literal>Dog</literal>
|
||||||
|
instead.</para>
|
||||||
|
|
||||||
<entry>Exemple</entry>
|
<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")
|
||||||
</row>
|
.addEntity("cat", Cat.class)
|
||||||
</thead>
|
.addJoin("cat.dogs");
|
||||||
|
]]></programlisting>
|
||||||
|
|
||||||
<tbody>
|
<para>
|
||||||
<row>
|
At this stage we are reaching the limits of what is possible with native queries without starting to
|
||||||
<entry>Une simple propriété</entry>
|
enhance the sql queries to make them usable in Hibernate; the problems starts to arise when returning
|
||||||
|
multiple entities of the same type or when the default alias/column names are not enough.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
<entry><literal>{[aliasname].[propertyname]}</literal></entry>
|
<sect2>
|
||||||
|
<title>Returning multiple entities</title>
|
||||||
|
|
||||||
<entry><literal>A_NAME as {item.name}</literal></entry>
|
<para>Until now the result set column names are assumed to be the same
|
||||||
</row>
|
as the column names specified in the mapping document. This can be
|
||||||
|
problematic for SQL queries which join multiple tables, since the same
|
||||||
|
column names may appear in more than one table.</para>
|
||||||
|
|
||||||
<row>
|
<para>Column alias injection is needed in the following query (which
|
||||||
<entry>Une propriété composée</entry>
|
most likely will fail):</para>
|
||||||
|
|
||||||
<entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
|
<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>
|
||||||
|
|
||||||
<entry><literal>CURRENCY as {item.amount.currency}, VALUE as
|
<para>The intention for this query is to return two Cat instances per
|
||||||
{item.amount.value}</literal></entry>
|
row, a cat and its mother. This will fail since there is a conflict of
|
||||||
</row>
|
names since they are mapped to the same column names and on some
|
||||||
|
databases the returned column aliases will most likely be on the form
|
||||||
|
"c.ID", "c.NAME", etc. which are not equal to the columns specificed in
|
||||||
|
the mappings ("ID" and "NAME").</para>
|
||||||
|
|
||||||
<row>
|
<para>The following form is not vulnerable to column name
|
||||||
<entry>Discriminant d'une entité</entry>
|
duplication:</para>
|
||||||
|
|
||||||
<entry><literal>{[aliasname].class}</literal></entry>
|
<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>
|
||||||
|
|
||||||
<entry><literal>DISC as {item.class}</literal></entry>
|
<para>This query specified:</para>
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
<itemizedlist>
|
||||||
<entry>Toutes les propriétés d'une entité</entry>
|
<listitem>
|
||||||
|
<para>the SQL query string, with placeholders for Hibernate to
|
||||||
|
inject column aliases</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
<entry><literal>{[aliasname].*}</literal></entry>
|
<listitem>
|
||||||
|
<para>the entities returned by the query</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
<entry><literal>{item.*}</literal></entry>
|
<para>The {cat.*} and {mother.*} notation used above is a shorthand for
|
||||||
</row>
|
"all properties". Alternatively, you may list the columns explicity, but
|
||||||
|
even in this case we let Hibernate inject the SQL column aliases for
|
||||||
|
each property. The placeholder for a column alias is just the property
|
||||||
|
name qualified by the table alias. In the following example, we retrieve
|
||||||
|
Cats and their mothers from a different table (cat_log) to the one
|
||||||
|
declared in the mapping metadata. Notice that we may even use the
|
||||||
|
property aliases in the where clause if we like.</para>
|
||||||
|
|
||||||
<row>
|
<programlisting><![CDATA[String sql = "SELECT ID as {c.id}, NAME as {c.name}, " +
|
||||||
<entry>Une clef de collection</entry>
|
"BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
|
||||||
|
"FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
|
||||||
|
|
||||||
<entry><literal>{[aliasname].key}</literal></entry>
|
List loggedCats = sess.createSQLQuery(sql)
|
||||||
|
.addEntity("cat", Cat.class)
|
||||||
|
.addEntity("mother", Cat.class).list()
|
||||||
|
]]></programlisting>
|
||||||
|
|
||||||
<entry><literal>ORGID as {coll.key}</literal></entry>
|
<sect3 id="querysql-aliasreferences" revision="2">
|
||||||
</row>
|
<title>Alias and property references</title>
|
||||||
|
|
||||||
<row>
|
<para>For most cases the above alias injection is needed, but for
|
||||||
<entry>L'identifiant d'une collection</entry>
|
queries relating to more complex mappings like composite properties,
|
||||||
|
inheritance discriminators, collections etc. there are some specific
|
||||||
|
aliases to use to allow Hibernate to inject the proper aliases.</para>
|
||||||
|
|
||||||
<entry><literal>{[aliasname].id}</literal></entry>
|
<para>The following table shows the different possibilities of using
|
||||||
|
the alias injection. Note: the alias names in the result are examples,
|
||||||
|
each alias will have a unique and probably different name when
|
||||||
|
used.</para>
|
||||||
|
|
||||||
<entry><literal>EMPID as {coll.id}</literal></entry>
|
<table frame="topbot" id="aliasinjection-summary">
|
||||||
</row>
|
<title>Alias injection names</title>
|
||||||
|
|
||||||
<row>
|
<tgroup cols="3">
|
||||||
<entry>L'élément d'une collection</entry>
|
<colspec colwidth="1*" />
|
||||||
|
|
||||||
<entry><literal>{[aliasname].element}</literal></entry>
|
<colspec colwidth="1*" />
|
||||||
|
|
||||||
<entry><literal>XID as {coll.element}</literal></entry>
|
<colspec colwidth="2.5*" />
|
||||||
|
|
||||||
<entry></entry>
|
<thead>
|
||||||
</row>
|
<row>
|
||||||
|
<entry>Description</entry>
|
||||||
|
|
||||||
<row>
|
<entry>Syntax</entry>
|
||||||
<entry>Propriété de l'élément dans la collection</entry>
|
|
||||||
|
|
||||||
<entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
|
<entry>Example</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
|
||||||
<entry><literal>NAME as {coll.element.name}</literal></entry>
|
<tbody>
|
||||||
</row>
|
<row>
|
||||||
|
<entry>A simple property</entry>
|
||||||
|
|
||||||
<row>
|
<entry><literal>{[aliasname].[propertyname]</literal></entry>
|
||||||
<entry>Toutes les propriétés de l'élément dans la collection</entry>
|
|
||||||
|
|
||||||
<entry><literal>{[aliasname].element.*}</literal></entry>
|
<entry><literal>A_NAME as {item.name}</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<entry><literal>{coll.element.*}</literal></entry>
|
<row>
|
||||||
</row>
|
<entry>A composite property</entry>
|
||||||
|
|
||||||
<row>
|
<entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
|
||||||
<entry>Toutes les propriétés de la collection</entry>
|
|
||||||
|
|
||||||
<entry><literal>{[aliasname].*}</literal></entry>
|
<entry><literal>CURRENCY as {item.amount.currency}, VALUE as
|
||||||
|
{item.amount.value}</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<entry><literal>{coll.*}</literal></entry>
|
<row>
|
||||||
</row>
|
<entry>Discriminator of an entity</entry>
|
||||||
</tbody>
|
|
||||||
</tgroup>
|
<entry><literal>{[aliasname].class}</literal></entry>
|
||||||
</table>
|
|
||||||
</sect1>
|
<entry><literal>DISC as {item.class}</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>All properties of an entity</entry>
|
||||||
|
|
||||||
|
<entry><literal>{[aliasname].*}</literal></entry>
|
||||||
|
|
||||||
|
<entry><literal>{item.*}</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>A collection key</entry>
|
||||||
|
|
||||||
|
<entry><literal>{[aliasname].key}</literal></entry>
|
||||||
|
|
||||||
|
<entry><literal>ORGID as {coll.key}</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>The id of an collection</entry>
|
||||||
|
|
||||||
|
<entry><literal>{[aliasname].id}</literal></entry>
|
||||||
|
|
||||||
|
<entry><literal>EMPID as {coll.id}</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>The element of an collection</entry>
|
||||||
|
|
||||||
|
<entry><literal>{[aliasname].element}</literal></entry>
|
||||||
|
|
||||||
|
<entry><literal>XID as {coll.element}</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>roperty of the element in the collection</entry>
|
||||||
|
|
||||||
|
<entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
|
||||||
|
|
||||||
|
<entry><literal>NAME as {coll.element.name}</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>All properties of the element in the collection</entry>
|
||||||
|
|
||||||
|
<entry><literal>{[aliasname].element.*}</literal></entry>
|
||||||
|
|
||||||
|
<entry><literal>{coll.element.*}</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>All properties of the the collection</entry>
|
||||||
|
|
||||||
|
<entry><literal>{[aliasname].*}</literal></entry>
|
||||||
|
|
||||||
|
<entry><literal>{coll.*}</literal></entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
</sect3>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Returning non-managed entities</title>
|
||||||
|
|
||||||
|
<para>It is possible to apply a ResultTransformer to native sql queries. Allowing it to e.g. return non-managed entities.</para>
|
||||||
|
|
||||||
|
<programlisting><![CDATA[sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS")
|
||||||
|
.setResultTransformer(Transformers.aliasToBean(CatDTO.class))]]></programlisting>
|
||||||
|
|
||||||
|
<para>This query specified:</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>the SQL query string</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>a result transformer</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The above query will return a list of <literal>CatDTO</literal> which has been instantiated and injected the values of NAME and BIRTHNAME into its corresponding
|
||||||
|
properties or fields.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Handling inheritance</title>
|
||||||
|
|
||||||
|
<para>Native sql queries which query for entities that is mapped as part
|
||||||
|
of an inheritance must include all properties for the baseclass and all
|
||||||
|
it subclasses.</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Parameters</title>
|
||||||
|
|
||||||
|
<para>Native sql queries support positional as well as named
|
||||||
|
parameters:</para>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="querysql-namedqueries" revision="3">
|
<sect1 id="querysql-namedqueries" revision="3">
|
||||||
<title>Requêtes SQL nommées</title>
|
<title>Requêtes SQL nommées</title>
|
||||||
|
@ -252,19 +405,19 @@ List loggedCats = sess.createSQLQuery(sql)
|
||||||
cas, nous <emphasis>n'avons pas besoin</emphasis> d'appeler <literal>addEntity()</literal>.
|
cas, nous <emphasis>n'avons pas besoin</emphasis> d'appeler <literal>addEntity()</literal>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><sql-query name="persons">
|
<programlisting><![CDATA[<sql-query name="persons">
|
||||||
<return alias="person" class="eg.Person"/>
|
<return alias="person" class="eg.Person"/>
|
||||||
SELECT person.NAME AS {person.name},
|
SELECT person.NAME AS {person.name},
|
||||||
person.AGE AS {person.age},
|
person.AGE AS {person.age},
|
||||||
person.SEX AS {person.sex}
|
person.SEX AS {person.sex}
|
||||||
FROM PERSON person
|
FROM PERSON person
|
||||||
WHERE person.NAME LIKE :namePattern
|
WHERE person.NAME LIKE :namePattern
|
||||||
</sql-query></programlisting>
|
</sql-query>]]></programlisting>
|
||||||
|
|
||||||
<programlisting>List people = sess.getNamedQuery("persons")
|
<programlisting><![CDATA[List people = sess.getNamedQuery("persons")
|
||||||
.setString("namePattern", namePattern)
|
.setString("namePattern", namePattern)
|
||||||
.setMaxResults(50)
|
.setMaxResults(50)
|
||||||
.list();</programlisting>
|
.list();]]></programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Les éléments <literal><return-join></literal> et
|
Les éléments <literal><return-join></literal> et
|
||||||
|
@ -272,34 +425,34 @@ List loggedCats = sess.createSQLQuery(sql)
|
||||||
des associations et définir des requêtes qui initialisent des collections.
|
des associations et définir des requêtes qui initialisent des collections.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><sql-query name="personsWith">
|
<programlisting><![CDATA[<sql-query name="personsWith">
|
||||||
<return alias="person" class="eg.Person"/>
|
<return alias="person" class="eg.Person"/>
|
||||||
<return-join alias="address" property="person.mailingAddress"/>
|
<return-join alias="address" property="person.mailingAddress"/>
|
||||||
SELECT person.NAME AS {person.name},
|
SELECT person.NAME AS {person.name},
|
||||||
person.AGE AS {person.age},
|
person.AGE AS {person.age},
|
||||||
person.SEX AS {person.sex},
|
person.SEX AS {person.sex},
|
||||||
address.STREET AS {address.street},
|
address.STREET AS {address.street},
|
||||||
address.CITY AS {address.city},
|
address.CITY AS {address.city},
|
||||||
address.STATE AS {address.state},
|
address.STATE AS {address.state},
|
||||||
address.ZIP AS {address.zip}
|
address.ZIP AS {address.zip}
|
||||||
FROM PERSON person
|
FROM PERSON person
|
||||||
JOIN ADDRESS address
|
JOIN ADDRESS address
|
||||||
ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
|
ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
|
||||||
WHERE person.NAME LIKE :namePattern
|
WHERE person.NAME LIKE :namePattern
|
||||||
</sql-query></programlisting>
|
</sql-query>]]></programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Une requête SQL nommée peut retourner une valeur scalaire. Vous devez
|
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
|
spécifier l'alias de colonne et le type Hibernate utilisant l'élément
|
||||||
<literal><return-scalar></literal> :</para>
|
<literal><return-scalar></literal> :</para>
|
||||||
|
|
||||||
<programlisting><sql-query name="mySqlQuery">
|
<programlisting><![CDATA[<sql-query name="mySqlQuery">
|
||||||
<return-scalar column="name" type="string"/>
|
<return-scalar column="name" type="string"/>
|
||||||
<return-scalar column="age" type="long"/>
|
<return-scalar column="age" type="long"/>
|
||||||
SELECT p.NAME AS name,
|
SELECT p.NAME AS name,
|
||||||
p.AGE AS age,
|
p.AGE AS age,
|
||||||
FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
|
FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
|
||||||
</sql-query></programlisting>
|
</sql-query>]]></programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Vous pouvez externaliser les informations de mapping des résultats dans un
|
Vous pouvez externaliser les informations de mapping des résultats dans un
|
||||||
|
@ -308,24 +461,32 @@ List loggedCats = sess.createSQLQuery(sql)
|
||||||
<literal>setResultSetMapping()</literal>.
|
<literal>setResultSetMapping()</literal>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><resultset name="personAddress">
|
<programlisting><![CDATA[<resultset name="personAddress">
|
||||||
<return alias="person" class="eg.Person"/>
|
<return alias="person" class="eg.Person"/>
|
||||||
<return-join alias="address" property="person.mailingAddress"/>
|
<return-join alias="address" property="person.mailingAddress"/>
|
||||||
</resultset>
|
</resultset>
|
||||||
|
|
||||||
<sql-query name="personsWith" resultset-ref="personAddress">
|
<sql-query name="personsWith" resultset-ref="personAddress">
|
||||||
SELECT person.NAME AS {person.name},
|
SELECT person.NAME AS {person.name},
|
||||||
person.AGE AS {person.age},
|
person.AGE AS {person.age},
|
||||||
person.SEX AS {person.sex},
|
person.SEX AS {person.sex},
|
||||||
address.STREET AS {address.street},
|
address.STREET AS {address.street},
|
||||||
address.CITY AS {address.city},
|
address.CITY AS {address.city},
|
||||||
address.STATE AS {address.state},
|
address.STATE AS {address.state},
|
||||||
address.ZIP AS {address.zip}
|
address.ZIP AS {address.zip}
|
||||||
FROM PERSON person
|
FROM PERSON person
|
||||||
JOIN ADDRESS address
|
JOIN ADDRESS address
|
||||||
ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
|
ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
|
||||||
WHERE person.NAME LIKE :namePattern
|
WHERE person.NAME LIKE :namePattern
|
||||||
</sql-query></programlisting>
|
</sql-query>]]></programlisting>
|
||||||
|
<para>You can alternatively use the resultset mapping information in your
|
||||||
|
hbm files directly in java code.</para>
|
||||||
|
|
||||||
|
<programlisting><![CDATA[List cats = sess.createSQLQuery(
|
||||||
|
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
|
||||||
|
)
|
||||||
|
.setResultSetMapping("catAndKitten")
|
||||||
|
.list();]]></programlisting>
|
||||||
|
|
||||||
<sect2 id="propertyresults">
|
<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>
|
||||||
|
@ -336,18 +497,18 @@ List loggedCats = sess.createSQLQuery(sql)
|
||||||
<literal>{}</literal> pour laisser Hibernate injecter ses propres alias.
|
<literal>{}</literal> pour laisser Hibernate injecter ses propres alias.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><sql-query name="mySqlQuery">
|
<programlisting><![CDATA[<sql-query name="mySqlQuery">
|
||||||
<return alias="person" class="eg.Person">
|
<return alias="person" class="eg.Person">
|
||||||
<return-property name="name" column="myName"/>
|
<return-property name="name" column="myName"/>
|
||||||
<return-property name="age" column="myAge"/>
|
<return-property name="age" column="myAge"/>
|
||||||
<return-property name="sex" column="mySex"/>
|
<return-property name="sex" column="mySex"/>
|
||||||
</return>
|
</return>
|
||||||
SELECT person.NAME AS myName,
|
SELECT person.NAME AS myName,
|
||||||
person.AGE AS myAge,
|
person.AGE AS myAge,
|
||||||
person.SEX AS mySex,
|
person.SEX AS mySex,
|
||||||
FROM PERSON person WHERE person.NAME LIKE :name
|
FROM PERSON person WHERE person.NAME LIKE :name
|
||||||
</sql-query>
|
</sql-query>
|
||||||
</programlisting>
|
]]></programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<literal><return-property></literal> fonctionne aussi avec de
|
<literal><return-property></literal> fonctionne aussi avec de
|
||||||
|
@ -355,21 +516,22 @@ List loggedCats = sess.createSQLQuery(sql)
|
||||||
qui ne peut pas permettre une bonne granularité des propriétés multi-colonnes.
|
qui ne peut pas permettre une bonne granularité des propriétés multi-colonnes.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><sql-query name="organizationCurrentEmployments">
|
|
||||||
<return alias="emp" class="Employment">
|
<programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
|
||||||
<return-property name="salary">
|
<return alias="emp" class="Employment">
|
||||||
<return-column name="VALUE"/>
|
<return-property name="salary">
|
||||||
<return-column name="CURRENCY"/>
|
<return-column name="VALUE"/>
|
||||||
</return-property>
|
<return-column name="CURRENCY"/>
|
||||||
<return-property name="endDate" column="myEndDate"/>
|
</return-property>
|
||||||
</return>
|
<return-property name="endDate" column="myEndDate"/>
|
||||||
SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
|
</return>
|
||||||
STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
|
SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
|
||||||
REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
|
STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
|
||||||
FROM EMPLOYMENT
|
REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
|
||||||
WHERE EMPLOYER = :id AND ENDDATE IS NULL
|
FROM EMPLOYMENT
|
||||||
ORDER BY STARTDATE ASC
|
WHERE EMPLOYER = :id AND ENDDATE IS NULL
|
||||||
</sql-query></programlisting>
|
ORDER BY STARTDATE ASC
|
||||||
|
</sql-query>]]></programlisting>
|
||||||
|
|
||||||
<para>
|
<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>
|
||||||
|
@ -396,36 +558,37 @@ List loggedCats = sess.createSQLQuery(sql)
|
||||||
version supérieure :
|
version supérieure :
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting>CREATE OR REPLACE FUNCTION selectAllEmployments
|
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
|
||||||
RETURN SYS_REFCURSOR
|
RETURN SYS_REFCURSOR
|
||||||
AS
|
AS
|
||||||
st_cursor SYS_REFCURSOR;
|
st_cursor SYS_REFCURSOR;
|
||||||
BEGIN
|
BEGIN
|
||||||
OPEN st_cursor FOR
|
OPEN st_cursor FOR
|
||||||
SELECT EMPLOYEE, EMPLOYER,
|
SELECT EMPLOYEE, EMPLOYER,
|
||||||
STARTDATE, ENDDATE,
|
STARTDATE, ENDDATE,
|
||||||
REGIONCODE, EID, VALUE, CURRENCY
|
REGIONCODE, EID, VALUE, CURRENCY
|
||||||
FROM EMPLOYMENT;
|
FROM EMPLOYMENT;
|
||||||
RETURN st_cursor;
|
RETURN st_cursor;
|
||||||
END;</programlisting>
|
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">
|
<programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
|
||||||
<return alias="emp" class="Employment">
|
<return alias="emp" class="Employment">
|
||||||
<return-property name="employee" column="EMPLOYEE"/>
|
<return-property name="employee" column="EMPLOYEE"/>
|
||||||
<return-property name="employer" column="EMPLOYER"/>
|
<return-property name="employer" column="EMPLOYER"/>
|
||||||
<return-property name="startDate" column="STARTDATE"/>
|
<return-property name="startDate" column="STARTDATE"/>
|
||||||
<return-property name="endDate" column="ENDDATE"/>
|
<return-property name="endDate" column="ENDDATE"/>
|
||||||
<return-property name="regionCode" column="REGIONCODE"/>
|
<return-property name="regionCode" column="REGIONCODE"/>
|
||||||
<return-property name="id" column="EID"/>
|
<return-property name="id" column="EID"/>
|
||||||
<return-property name="salary">
|
<return-property name="salary">
|
||||||
<return-column name="VALUE"/>
|
<return-column name="VALUE"/>
|
||||||
<return-column name="CURRENCY"/>
|
<return-column name="CURRENCY"/>
|
||||||
</return-property>
|
</return-property>
|
||||||
</return>
|
</return>
|
||||||
{ ? = call selectAllEmployments() }
|
{ ? = call selectAllEmployments() }
|
||||||
</sql-query></programlisting>
|
</sql-query>]]></programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Notez que les procédures stockées retournent, pour le moment, seulement des
|
Notez que les procédures stockées retournent, pour le moment, seulement des
|
||||||
|
@ -447,7 +610,10 @@ BEGIN
|
||||||
|
|
||||||
<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>
|
<literal>setFirstResult()/setMaxResults()</literal>.</para>
|
||||||
|
<para>Recommended call form is standard SQL92: <literal>{ ? = call
|
||||||
|
functionName(<parameters>) }</literal> or <literal>{ ? = call
|
||||||
|
procedureName(<parameters>}</literal>. Native call syntax is not
|
||||||
|
supported.</para>
|
||||||
<para>Pour Oracle les règles suivantes s'appliquent :</para>
|
<para>Pour Oracle les règles suivantes s'appliquent :</para>
|
||||||
|
|
||||||
<itemizedlist spacing="compact">
|
<itemizedlist spacing="compact">
|
||||||
|
@ -493,15 +659,15 @@ BEGIN
|
||||||
<literal><sql-delete></literal>, et
|
<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">
|
<programlisting><![CDATA[<class name="Person">
|
||||||
<id name="id">
|
<id name="id">
|
||||||
<generator class="increment"/>
|
<generator class="increment"/>
|
||||||
</id>
|
</id>
|
||||||
<property name="name" not-null="true"/>
|
<property name="name" not-null="true"/>
|
||||||
<sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
|
<sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
|
||||||
<sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
|
<sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
|
||||||
<sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
|
<sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
|
||||||
</class></programlisting>
|
</class>]]></programlisting>
|
||||||
|
|
||||||
<para>Le SQL est directement exécuté dans votre base de données, donc vous êtes libre d'utiliser
|
<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
|
le dialecte que vous souhaitez. Cela réduira bien sûr la portabilité de votre mapping si vous
|
||||||
|
@ -509,15 +675,16 @@ BEGIN
|
||||||
|
|
||||||
<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">
|
<programlisting><![CDATA[<class name="Person">
|
||||||
<generator class="increment"/>
|
<id name="id">
|
||||||
</id>
|
<generator class="increment"/>
|
||||||
<property name="name" not-null="true"/>
|
</id>
|
||||||
<sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
|
<property name="name" not-null="true"/>
|
||||||
<sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
|
<sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
|
||||||
<sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
|
<sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
|
||||||
</class></programlisting>
|
<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
|
<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>
|
même séquence qu'Hibernate les attend.</para>
|
||||||
|
@ -536,19 +703,20 @@ BEGIN
|
||||||
Hibernate inscrit toujours la première expression comme un paramètre de sortie numérique pour les
|
Hibernate inscrit toujours la première expression comme un paramètre de sortie numérique pour les
|
||||||
opérations CUD :</para>
|
opérations CUD :</para>
|
||||||
|
|
||||||
<programlisting>CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
|
|
||||||
RETURN NUMBER IS
|
|
||||||
BEGIN
|
|
||||||
|
|
||||||
update PERSON
|
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
|
||||||
set
|
RETURN NUMBER IS
|
||||||
NAME = uname,
|
BEGIN
|
||||||
where
|
|
||||||
ID = uid;
|
|
||||||
|
|
||||||
return SQL%ROWCOUNT;
|
update PERSON
|
||||||
|
set
|
||||||
|
NAME = uname,
|
||||||
|
where
|
||||||
|
ID = uid;
|
||||||
|
|
||||||
END updatePerson;</programlisting>
|
return SQL%ROWCOUNT;
|
||||||
|
|
||||||
|
END updatePerson;]]></programlisting>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="querysql-load">
|
<sect1 id="querysql-load">
|
||||||
|
@ -556,53 +724,52 @@ END updatePerson;</programlisting>
|
||||||
|
|
||||||
<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"/>
|
<programlisting><![CDATA[<sql-query name="person">
|
||||||
SELECT NAME AS {pers.name}, ID AS {pers.id}
|
<return alias="pers" class="Person" lock-mode="upgrade"/>
|
||||||
FROM PERSON
|
SELECT NAME AS {pers.name}, ID AS {pers.id}
|
||||||
WHERE ID=?
|
FROM PERSON
|
||||||
FOR UPDATE
|
WHERE ID=?
|
||||||
</sql-query></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
|
<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>
|
cette requête nommée dans un mapping de classe :</para>
|
||||||
|
<programlisting><![CDATA[<class name="Person">
|
||||||
<programlisting><class name="Person">
|
<id name="id">
|
||||||
<id name="id">
|
<generator class="increment"/>
|
||||||
<generator class="increment"/>
|
</id>
|
||||||
</id>
|
<property name="name" not-null="true"/>
|
||||||
<property name="name" not-null="true"/>
|
<loader query-ref="person"/>
|
||||||
<loader query-ref="person"/>
|
</class>]]></programlisting>
|
||||||
</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><![CDATA[<set name="employments" inverse="true">
|
||||||
|
<key/>
|
||||||
|
<one-to-many class="Employment"/>
|
||||||
|
<loader query-ref="employments"/>
|
||||||
|
</set>]]></programlisting>
|
||||||
|
|
||||||
<programlisting><set name="employments" inverse="true">
|
<programlisting><![CDATA[<sql-query name="employments">
|
||||||
<key/>
|
<load-collection alias="emp" role="Person.employments"/>
|
||||||
<one-to-many class="Employment"/>
|
SELECT {emp.*}
|
||||||
<loader query-ref="employments"/>
|
FROM EMPLOYMENT emp
|
||||||
</set></programlisting>
|
WHERE EMPLOYER = :id
|
||||||
|
ORDER BY STARTDATE ASC, EMPLOYEE ASC
|
||||||
<programlisting><sql-query name="employments">
|
</sql-query>]]></programlisting>
|
||||||
<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é 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">
|
<programlisting><![CDATA[<sql-query name="person">
|
||||||
<return alias="pers" class="Person"/>
|
<return alias="pers" class="Person"/>
|
||||||
<return-join alias="emp" property="pers.employments"/>
|
<return-join alias="emp" property="pers.employments"/>
|
||||||
SELECT NAME AS {pers.*}, {emp.*}
|
SELECT NAME AS {pers.*}, {emp.*}
|
||||||
FROM PERSON pers
|
FROM PERSON pers
|
||||||
LEFT OUTER JOIN EMPLOYMENT emp
|
LEFT OUTER JOIN EMPLOYMENT emp
|
||||||
ON pers.ID = emp.PERSON_ID
|
ON pers.ID = emp.PERSON_ID
|
||||||
WHERE ID=?
|
WHERE ID=?
|
||||||
</sql-query></programlisting>
|
</sql-query>]]></programlisting>
|
||||||
</sect1>
|
</sect1>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
|
@ -95,6 +95,30 @@ Long generatedId = (Long) sess.save(fritz);]]></programlisting>
|
||||||
avec la sémantique définie plus tôt dans le brouillon d'EJB3.
|
avec la sémantique définie plus tôt dans le brouillon d'EJB3.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<itemizedlist spacing="compact">
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>persist()</literal> makes a transient instance persistent.
|
||||||
|
However, it doesn't guarantee that the identifier value will be assigned to
|
||||||
|
the persistent instance immediately, the assignment might happen at flush time.
|
||||||
|
<literal>persist()</literal> also guarantees that it will not execute an
|
||||||
|
<literal>INSERT</literal> statement if it is called outside of transaction
|
||||||
|
boundaries. This is useful in long-running conversations with an extended
|
||||||
|
Session/persistence context.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>save()</literal> does guarantee to return an identifier. If an INSERT
|
||||||
|
has to be executed to get the identifier ( e.g. "identity" generator, not
|
||||||
|
"sequence"), this INSERT happens immediately, no matter if you are inside or
|
||||||
|
outside of a transaction. This is problematic in a long-running conversation
|
||||||
|
with an extended Session/persistence context.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Alternativement, vous pouvez assigner l'identifiant en utilisant une version
|
Alternativement, vous pouvez assigner l'identifiant en utilisant une version
|
||||||
surchargée de <literal>save()</literal>.
|
surchargée de <literal>save()</literal>.
|
||||||
|
@ -478,6 +502,13 @@ List cats = q.list();]]></programlisting>
|
||||||
utilisé, vous pouvez aussi définir des requêtes SQL nativez dans les méta-données, ou
|
utilisé, vous pouvez aussi définir des requêtes SQL nativez dans les méta-données, ou
|
||||||
migrer des requêtes existantes vers Hibernate en les plaçant dans les fichiers de mapping.
|
migrer des requêtes existantes vers Hibernate en les plaçant dans les fichiers de mapping.
|
||||||
</para>
|
</para>
|
||||||
|
<para> UNTRANSLATED!
|
||||||
|
Also note that a query declaration inside a <literal><hibernate-mapping></literal>
|
||||||
|
element requires a global unique name for the query, while a query declaration inside a
|
||||||
|
<literal><class></literal> element is made unique automatically by prepending the
|
||||||
|
fully qualified name of the class, for example
|
||||||
|
<literal>eg.Cat.ByNameAndMaximumWeight</literal>.
|
||||||
|
</para>
|
||||||
|
|
||||||
</sect3>
|
</sect3>
|
||||||
|
|
||||||
|
|
|
@ -219,7 +219,9 @@
|
||||||
<entry>
|
<entry>
|
||||||
spécifie le nom d'une contrainte de clé étrangère générée pour
|
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
|
une association, utilisez-la avec les éléments de mapping
|
||||||
<one-to-one>, <many-to-one>, <key>, et <many-to-many>
|
<literal><one-to-one></literal>,
|
||||||
|
<literal><many-to-one></literal>, <literal><key></literal>,
|
||||||
|
or <literal><many-to-many></literal>
|
||||||
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>.
|
se seront pas prises en compte par <literal>SchemaExport</literal>.
|
||||||
</entry>
|
</entry>
|
||||||
|
@ -451,8 +453,8 @@ new SchemaExport(cfg).create(false, true);]]></programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<literal>java -cp </literal><emphasis>classpath_hibernate</emphasis>
|
<literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
|
||||||
<literal>net.sf.hibernate.tool.hbm2ddl.SchemaUpdate</literal> <emphasis>options fichiers_de_mapping</emphasis>
|
<literal>org.hibernate.tool.hbm2ddl.SchemaUpdate</literal> <emphasis>options mapping_files</emphasis>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<table frame="topbot">
|
<table frame="topbot">
|
||||||
|
@ -482,6 +484,9 @@ new SchemaExport(cfg).create(false, true);]]></programlisting>
|
||||||
<row>
|
<row>
|
||||||
<entry><literal>--properties=hibernate.properties</literal></entry>
|
<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> <row>
|
||||||
|
<entry><literal>--config=hibernate.cfg.xml</literal></entry>
|
||||||
|
<entry>specify a <literal>.cfg.xml</literal> file</entry>
|
||||||
</row>
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
|
|
|
@ -800,7 +800,12 @@ catch (RuntimeException e) {
|
||||||
pour conserver la <literal>Session</literal> et évitez de la sérialiser et de la transférer à la couche de présentation (i.e. Il est préférable de ne pas
|
pour conserver la <literal>Session</literal> et évitez de la sérialiser et de la transférer à la couche de présentation (i.e. Il est préférable de ne pas
|
||||||
la conserver dans la session <literal>HttpSession</literal> .)
|
la conserver dans la session <literal>HttpSession</literal> .)
|
||||||
</para>
|
</para>
|
||||||
|
<para>
|
||||||
|
The extended session pattern, or <emphasis>session-per-conversation</emphasis>, is
|
||||||
|
more difficult to implement with automatic current session context management.
|
||||||
|
You need to supply your own implementation of the <literal>CurrentSessionContext</literal>
|
||||||
|
for this, see the Hibernate Wiki for examples.
|
||||||
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="transactions-optimistic-detached">
|
<sect2 id="transactions-optimistic-detached">
|
||||||
|
|
|
@ -681,7 +681,9 @@ public class EventManager {
|
||||||
La méthode <literal>getCurrentSession()</literal> renvoie toujours l'unité de travail courante.
|
La méthode <literal>getCurrentSession()</literal> renvoie toujours l'unité de travail courante.
|
||||||
Souvenez vous que nous avons basculé notre option de configuration au mécanisme basé sur le "thread"
|
Souvenez vous que nous avons basculé notre option de configuration au mécanisme basé sur le "thread"
|
||||||
dans <literal>hibernate.cfg.xml</literal>. Par conséquent, le scope de l'unité de travail
|
dans <literal>hibernate.cfg.xml</literal>. Par conséquent, le scope de l'unité de travail
|
||||||
courante est le thread java courant d'exécution. Ceci n'est pas totalement vrai. Une
|
courante est le thread java courant d'exécution. Ceci n'est pas totalement vrai. </para>
|
||||||
|
|
||||||
|
<para>Une
|
||||||
<literal>Session</literal> commence lorsqu'elle est vraiment utilisée la première fois,
|
<literal>Session</literal> commence lorsqu'elle est vraiment utilisée la première fois,
|
||||||
Lorsque nous appelons pour la première fois <literal>getCurrentSession()</literal>.
|
Lorsque nous appelons pour la première fois <literal>getCurrentSession()</literal>.
|
||||||
Ensuite, elle est liée, par Hibernate, au thread courant. Lorsque la transaction s'achève
|
Ensuite, elle est liée, par Hibernate, au thread courant. Lorsque la transaction s'achève
|
||||||
|
@ -691,7 +693,17 @@ public class EventManager {
|
||||||
Ce modèle de programmation "<emphasis>thread-bound</emphasis>" est le moyen le plus
|
Ce modèle de programmation "<emphasis>thread-bound</emphasis>" est le moyen le plus
|
||||||
populaire d'utiliser Hibernate.
|
populaire d'utiliser Hibernate.
|
||||||
</para>
|
</para>
|
||||||
|
<para> UNTRANSLATED
|
||||||
|
!
|
||||||
|
Related to the unit of work scope, should the Hibernate <literal>Session</literal> be used to
|
||||||
|
execute one or several database operations? The above example uses one <literal>Session</literal>
|
||||||
|
for one operation. This is pure coincidence, the example is just not complex enough to show any
|
||||||
|
other approach. The scope of a Hibernate <literal>Session</literal> is flexible but you should
|
||||||
|
never design your application to use a new Hibernate <literal>Session</literal> for
|
||||||
|
<emphasis>every</emphasis> database operation. So even if you see it a few more times in
|
||||||
|
the following (very trivial) examples, consider <emphasis>session-per-operation</emphasis>
|
||||||
|
an anti-pattern. A real (web) application is shown later in this tutorial.
|
||||||
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Lisez <xref linkend="transactions"/> pour plus d'informations sur la gestion des transactions et leur démarcations.
|
Lisez <xref linkend="transactions"/> pour plus d'informations sur la gestion des transactions et leur démarcations.
|
||||||
Nous n'avons pas géré les erreurs et rollback sur l'exemple précédent.
|
Nous n'avons pas géré les erreurs et rollback sur l'exemple précédent.
|
||||||
|
@ -801,7 +813,13 @@ else if (args[0].equals("list")) {
|
||||||
les événements que vous avez stockés jusque là. Vous pouvez bien sûr aussi appeler l'action
|
les événements que vous avez stockés jusque là. Vous pouvez bien sûr aussi appeler l'action
|
||||||
<literal>store</literal> plusieurs fois.
|
<literal>store</literal> plusieurs fois.
|
||||||
</para>
|
</para>
|
||||||
|
<para> UNTRANSLATED!
|
||||||
|
Note: Most new Hibernate users fail at this point and we see questions about
|
||||||
|
<emphasis>Table not found</emphasis> error messages regularly. However, if you follow the
|
||||||
|
steps outlined above you will not have this problem, as hbm2ddl creates the database
|
||||||
|
schema on the first run, and subsequent application restarts will use this schema. If
|
||||||
|
you change the mapping and/or database schema, you have to re-enable hbm2ddl once again.
|
||||||
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
@ -1285,7 +1303,12 @@ public void removeFromEvent(Event event) {
|
||||||
doesn't scale anymore with our growing application.
|
doesn't scale anymore with our growing application.
|
||||||
</para>
|
</para>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
<para>
|
||||||
|
Let's turn this into a small web application.
|
||||||
|
</para>
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="tutorial-webapp">
|
<sect1 id="tutorial-webapp">
|
||||||
|
@ -1305,27 +1328,18 @@ public void removeFromEvent(Event event) {
|
||||||
Créons une nouvelle classe dans notre répertoire source, dans le package <literal>events</literal>:
|
Créons une nouvelle classe dans notre répertoire source, dans le package <literal>events</literal>:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><![CDATA[package events;
|
<programlisting><![CDATA[package events;
|
||||||
|
|
||||||
// Imports
|
// Imports
|
||||||
|
|
||||||
public class EventManagerServlet extends HttpServlet {
|
public class EventManagerServlet extends HttpServlet {
|
||||||
|
|
||||||
private final SimpleDateFormat dateFormatter =
|
// Servlet code
|
||||||
new SimpleDateFormat("dd.MM.yyyy");
|
}]]></programlisting>
|
||||||
|
|
||||||
// Servlet code
|
<para>
|
||||||
}]]></programlisting>
|
The servlet handles HTTP <literal>GET</literal> requests only, hence, the method
|
||||||
|
we implement is <literal>doGet()</literal>:
|
||||||
<para>
|
|
||||||
Le <literal>dateFormatter</literal> est un outil que nous utiliserons plus tard pour convertir les objets
|
|
||||||
<literal>Date</literal> depuis et vers des chaines de caractères. Il est propice de n'avoir qu'un
|
|
||||||
formatter comme membre de la servlet.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
La servlet n'accepte que les requêtes HTTP <literal>GET</literal>, la méthode à implémenter est donc
|
|
||||||
<literal>doGet()</literal>:
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting><![CDATA[protected void doGet(HttpServletRequest request,
|
<programlisting><![CDATA[protected void doGet(HttpServletRequest request,
|
||||||
|
@ -1359,7 +1373,12 @@ public class EventManagerServlet extends HttpServlet {
|
||||||
tous les accès à la base de données interviennent au sein de la transactiton, peu importe que les données
|
tous les accès à la base de données interviennent au sein de la transactiton, peu importe que les données
|
||||||
soient lues ou écrites (nous n'utilisons pas le mode auto-commit dans les applications).
|
soient lues ou écrites (nous n'utilisons pas le mode auto-commit dans les applications).
|
||||||
</para>
|
</para>
|
||||||
|
<para> UNTRANSLATED
|
||||||
|
Do <emphasis>not</emphasis> use a new Hibernate <literal>Session</literal> for
|
||||||
|
every database operation. Use one Hibernate <literal>Session</literal> that is
|
||||||
|
scoped to the whole request. Use <literal>getCurrentSession()</literal>, so that
|
||||||
|
it is automatically bound to the current Java thread.
|
||||||
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Ensuite, les actions possibles de la requêtes sont exécutées et la réponse HTML
|
Ensuite, les actions possibles de la requêtes sont exécutées et la réponse HTML
|
||||||
est rendue. Nous en parlerons plus tard.
|
est rendue. Nous en parlerons plus tard.
|
||||||
|
|
Loading…
Reference in New Issue