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:
xhuang 2007-10-26 07:36:12 +00:00
parent f134d4ab5c
commit 1a1fc99092
12 changed files with 995 additions and 485 deletions

View File

@ -323,6 +323,14 @@
courantes sont associées au thread d'exécution. Voir les javadocs pour les détails.
</para>
</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>
<para>

View File

@ -365,7 +365,14 @@ create table Address ( addressId bigint not null primary key )
<one-to-many class="Person"/>
</list>
</class>]]></programlisting>
<para>
It is important that you define <literal>not-null="true"</literal> on the
<literal>&lt;key&gt;</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>&lt;column&gt;</literal> element, but on the <literal>&lt;key&gt;</literal>
element.
</para>
</sect2>
<sect2 id="assoc-bidirectional-121">

View File

@ -98,8 +98,61 @@
des recherches de la DTD sur Internet, vérifiez votre déclaration de DTD par rapport
au contenu de votre classpath.
</para>
</sect2>
<sect2 id="mapping-declaration-mapping" revision="3">
<sect3 id="mapping-declaration-entity-resolution">
<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>
<para>
Cet élément a plusieurs attributs optionnels. Les attributs <literal>schema</literal> et <literal>catalog</literal>
@ -357,19 +410,14 @@
pour plus d'informations.
</para>
</callout>
<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>
<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.
</para>
</callout>
<callout arearefs="class20">
<callout arearefs="class19">
<para>
<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
@ -377,14 +425,14 @@
la localisation physique d'un tuple enregistré.
</para>
</callout>
<callout arearefs="class21">
<callout arearefs="class20">
<para>
<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
pour plus d'information.
</para>
</callout>
<callout arearefs="class22">
<callout arearefs="class21">
<para>
<literal>abstract</literal> (optionnel) : Utilisé pour marquer des superclasses abstraites dans
des hiérarchies de <literal>&lt;union-subclass&gt;</literal>.
@ -733,6 +781,19 @@
avec une association <literal>&lt;one-to-one&gt;</literal> sur la clef primaire.
</para>
</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>
</variablelist>
</para>
@ -829,7 +890,177 @@
</para>
</sect3>
</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>
<programlisting><![CDATA[<composite-id
name="propertyName"

View File

@ -713,21 +713,28 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
<emphasis role="strong">ex.</emphasis>
<literal>on_close</literal> (default) | <literal>after_transaction</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>
</entry>
</row>
<row>
<entry>
<literal>hibernate.connection.<emphasis>&lt;propertyName&gt;</emphasis></literal>
<literal>hibernate.connection.</literal><emphasis>&lt;propertyName&gt;</emphasis>
</entry>
<entry>
Passe la propriété JDBC<literal>propertyName</literal>
Passe la propriété JDBC <emphasis>&lt;propertyName&gt;</emphasis>
à <literal>DriverManager.getConnection()</literal>.
</entry>
</row>
<row>
<entry>
<literal>hibernate.jndi.<emphasis>&lt;propertyName&gt;</emphasis></literal>
<literal>hibernate.jndi.</literal><emphasis>&lt;propertyName&gt;</emphasis>
</entry>
<entry>
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>
<para>
You can pick a different XML configuration file using
</para>
<programlisting><![CDATA[SessionFactory sf = new Configuration()
.configure("catdb.cfg.xml")
.buildSessionFactory();]]></programlisting>
</sect1>

View File

@ -116,15 +116,26 @@ public class AuditInterceptor extends EmptyInterceptor {
}]]></programlisting>
<para>
L'intercepteur doit être spécifié quand une session est créée.
<para>
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>
<programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
<para>
Vous pouvez aussi mettre un intercepteur au niveau global, en utilisant l'objet <literal>Configuration</literal>.
Dans ce cas, l'intercepteur doit être "threadsafe".
<para>
A <literal>SessionFactory</literal>-scoped interceptor is registered with the <literal>Configuration</literal>
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>
<programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>

View File

@ -719,7 +719,7 @@ Cat fritz = (Cat) iter.next();]]></programlisting>
<entry>OSCache</entry>
<entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
<entry>mémoire, disque</entry>
<entry>oui (invalidation de cluster)</entry>
<entry></entry>
<entry>oui</entry>
</row>
<row>

View File

@ -214,6 +214,43 @@
<programlisting><![CDATA[from Cat as cat where cat.mate.name like '%s%']]></programlisting>
</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">
<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.
</para>
<para>
Pour des sous-requêtes avec plus d'une expression dans le select, vous pouvez utiliser un constructeur de tuples :
<para>
Note that subqueries can also utilize <literal>row value constructor</literal> syntax. See
<xref linkend="queryhql-tuple"/> for more details.
</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 id="queryhql-examples">

View File

@ -94,6 +94,30 @@ Long generatedId = (Long) sess.save(fritz);]]></programlisting>
Vous pouvez aussi utiliser <literal>persist()</literal> à la place de<literal>save()</literal>,
avec la sémantique définie plus tôt dans le brouillon d'EJB3.
</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>
Alternativement, vous pouvez assigner l'identifiant en utilisant une version
@ -307,8 +331,8 @@ while ( iter.hasNext() ) {
while ( kittensAndMothers.hasNext() ) {
Object[] tuple = (Object[]) kittensAndMothers.next();
Cat kitten = (Cat) tuple[0];
Cat mother = (Cat) tuple[1];
Cat kitten = (Cat) tuple[0];
Cat mother = (Cat) tuple[1];
....
}]]></programlisting>
@ -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
migrer des requêtes existantes vers Hibernate en les plaçant dans les fichiers de mapping.
</para>
<para> UNTRANSLATED!
Also note that a query declaration inside a <literal>&lt;hibernate-mapping&gt;</literal>
element requires a global unique name for the query, while a query declaration inside a
<literal>&lt;class&gt;</literal> element is made unique automatically by prepending the
fully qualified name of the class, for example
<literal>eg.Cat.ByNameAndMaximumWeight</literal>.
</para>
</sect3>
@ -560,16 +591,16 @@ List cats = crit.list();]]></programlisting>
l'API Hibernate, vous devez mettre les alias SQL entre accolades :
</para>
<programlisting><![CDATA[List cats = session.createSQLQuery("SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10")
.addEntity("cat", Cat.class)
.list();]]></programlisting>
<programlisting><![CDATA[List cats = session.createSQLQuery(
"SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
"{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
"FROM CAT {cat} WHERE ROWNUM<10")
.addEntity("cat", Cat.class)
.list()]]></programlisting>
<programlisting><![CDATA[List cats = session.createSQLQuery("SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10")
.addEntity("cat", Cat.class)
.list();]]></programlisting>
<programlisting><![CDATA[List cats = session.createSQLQuery(
"SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
"{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
"FROM CAT {cat} WHERE ROWNUM<10")
.addEntity("cat", Cat.class)
.list()]]></programlisting>
<para>
Les requêtes SQL peuvent contenir des paramètres nommés et positionnels, comme des

View File

@ -219,7 +219,9 @@
<entry>
spécifie le nom d'une contrainte de clé étrangère générée pour
une association, utilisez-la avec les éléments de mapping
&lt;one-to-one&gt;, &lt;many-to-one&gt;, &lt;key&gt;, et &lt;many-to-many&gt;
<literal>&lt;one-to-one&gt;</literal>,
<literal>&lt;many-to-one&gt;</literal>, <literal>&lt;key&gt;</literal>,
or <literal>&lt;many-to-many&gt;</literal>
Notez que les extrêmités <literal>inverse="true"</literal>
se seront pas prises en compte par <literal>SchemaExport</literal>.
</entry>
@ -451,8 +453,8 @@ new SchemaExport(cfg).create(false, true);]]></programlisting>
</para>
<para>
<literal>java -cp </literal><emphasis>classpath_hibernate</emphasis>
<literal>net.sf.hibernate.tool.hbm2ddl.SchemaUpdate</literal> <emphasis>options fichiers_de_mapping</emphasis>
<literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
<literal>org.hibernate.tool.hbm2ddl.SchemaUpdate</literal> <emphasis>options mapping_files</emphasis>
</para>
<table frame="topbot">
@ -482,6 +484,9 @@ new SchemaExport(cfg).create(false, true);]]></programlisting>
<row>
<entry><literal>--properties=hibernate.properties</literal></entry>
<entry>lire les propriétés de la base de données à partir d'un fichier</entry>
</row> <row>
<entry><literal>--config=hibernate.cfg.xml</literal></entry>
<entry>specify a <literal>.cfg.xml</literal> file</entry>
</row>
</tbody>
</tgroup>

View File

@ -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
la conserver dans la session <literal>HttpSession</literal> .)
</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 id="transactions-optimistic-detached">

View File

@ -681,7 +681,9 @@ public class EventManager {
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"
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,
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
@ -691,7 +693,17 @@ public class EventManager {
Ce modèle de programmation "<emphasis>thread-bound</emphasis>" est le moyen le plus
populaire d'utiliser Hibernate.
</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>
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.
@ -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
<literal>store</literal> plusieurs fois.
</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>
</sect1>
@ -1285,7 +1303,12 @@ public void removeFromEvent(Event event) {
doesn't scale anymore with our growing application.
</para>
-->
</sect2>
<para>
Let's turn this into a small web application.
</para>
</sect1>
<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>:
</para>
<programlisting><![CDATA[package events;
// Imports
public class EventManagerServlet extends HttpServlet {
private final SimpleDateFormat dateFormatter =
new SimpleDateFormat("dd.MM.yyyy");
// Servlet code
}]]></programlisting>
<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>:
<programlisting><![CDATA[package events;
// Imports
public class EventManagerServlet extends HttpServlet {
// Servlet code
}]]></programlisting>
<para>
The servlet handles HTTP <literal>GET</literal> requests only, hence, the method
we implement is <literal>doGet()</literal>:
</para>
<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
soient lues ou écrites (nous n'utilisons pas le mode auto-commit dans les applications).
</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>
Ensuite, les actions possibles de la requêtes sont exécutées et la réponse HTML
est rendue. Nous en parlerons plus tard.