[hibernate-commits] Hibernate SVN: r11558 - in trunk/sandbox/maven-poc/Hibernate3/documentation: en-US and 17 other directories.
hibernate-commits at lists.jboss.org
hibernate-commits at lists.jboss.org
Thu May 24 15:01:51 EDT 2007
Author: steve.ebersole at jboss.com
Date: 2007-05-24 15:01:51 -0400 (Thu, 24 May 2007)
New Revision: 11558
Added:
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/pom.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/master.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/architecture.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/association_mapping.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/basic_mapping.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/batch.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/best_practices.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/collection_mapping.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/component_mapping.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/configuration.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/events.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/example_mappings.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/example_parentchild.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/example_weblog.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/filters.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/inheritance_mapping.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/performance.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/persistent_classes.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/query_criteria.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/query_hql.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/query_sql.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/session_api.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/toolset_guide.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/transactions.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/tutorial.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/xml.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/css/
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/css/html.css
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/AuthorWork.gif
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/AuthorWork.zargo
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/CustomerOrderProduct.gif
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/CustomerOrderProduct.zargo
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/EmployerEmployee.gif
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/EmployerEmployee.zargo
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/full_cream.gif
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/full_cream.svg
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/hibernate_logo_a.png
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/lite.gif
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/lite.svg
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/overview.gif
trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/overview.svg
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/pom.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/master.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/architecture.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/association_mapping.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/basic_mapping.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/batch.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/best_practices.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/collection_mapping.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/component_mapping.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/configuration.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/events.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/example_mappings.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/example_parentchild.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/example_weblog.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/filters.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/inheritance_mapping.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/performance.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/persistent_classes.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/query_criteria.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/query_hql.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/query_sql.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/session_api.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/toolset_guide.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/transactions.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/tutorial.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/xml.xml
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/css/
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/css/html.css
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/AuthorWork.gif
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/AuthorWork.zargo
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/CustomerOrderProduct.gif
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/CustomerOrderProduct.zargo
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/EmployerEmployee.gif
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/EmployerEmployee.zargo
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/full_cream.gif
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/full_cream.svg
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/hibernate_logo_a.png
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/lite.gif
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/lite.svg
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/overview.gif
trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/overview.svg
Removed:
trunk/sandbox/maven-poc/Hibernate3/documentation/src/
Modified:
trunk/sandbox/maven-poc/Hibernate3/documentation/pom.xml
Log:
moved closer to the layout proposed by the RH doc team
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/pom.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/pom.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/pom.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,22 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-manual</artifactId>
+ <version>3.3.0.beta1</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>hibernate-manual-${translation}</artifactId>
+ <packaging>pom</packaging>
+ <name>Hibernate Manual (${translation})</name>
+
+ <properties>
+ <translation>en-US</translation>
+ </properties>
+
+</project>
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/master.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/master.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/master.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,183 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+<!ENTITY mdash "-">
+<!ENTITY tutorial SYSTEM "modules/tutorial.xml">
+<!ENTITY architecture SYSTEM "modules/architecture.xml">
+<!ENTITY configuration SYSTEM "modules/configuration.xml">
+<!ENTITY persistent-classes SYSTEM "modules/persistent_classes.xml">
+<!ENTITY basic-mapping SYSTEM "modules/basic_mapping.xml">
+<!ENTITY collection-mapping SYSTEM "modules/collection_mapping.xml">
+<!ENTITY association-mapping SYSTEM "modules/association_mapping.xml">
+<!ENTITY component-mapping SYSTEM "modules/component_mapping.xml">
+<!ENTITY inheritance-mapping SYSTEM "modules/inheritance_mapping.xml">
+<!ENTITY session-api SYSTEM "modules/session_api.xml">
+<!ENTITY transactions SYSTEM "modules/transactions.xml">
+<!ENTITY events SYSTEM "modules/events.xml">
+<!ENTITY batch SYSTEM "modules/batch.xml">
+<!ENTITY query-hql SYSTEM "modules/query_hql.xml">
+<!ENTITY query-criteria SYSTEM "modules/query_criteria.xml">
+<!ENTITY query-sql SYSTEM "modules/query_sql.xml">
+<!ENTITY filters SYSTEM "modules/filters.xml">
+<!ENTITY xml SYSTEM "modules/xml.xml">
+<!ENTITY performance SYSTEM "modules/performance.xml">
+<!ENTITY toolset-guide SYSTEM "modules/toolset_guide.xml">
+<!ENTITY example-parentchild SYSTEM "modules/example_parentchild.xml">
+<!ENTITY example-weblog SYSTEM "modules/example_weblog.xml">
+<!ENTITY example-mappings SYSTEM "modules/example_mappings.xml">
+<!ENTITY best-practices SYSTEM "modules/best_practices.xml">
+]>
+
+<book lang="en">
+
+ <bookinfo>
+ <title>HIBERNATE - Relational Persistence for Idiomatic Java</title>
+ <subtitle>Hibernate Reference Documentation</subtitle>
+ <releaseinfo>3.3.0.beta1</releaseinfo>
+ </bookinfo>
+
+ <toc/>
+
+ <preface id="preface" revision="2">
+ <title>Preface</title>
+
+ <para>
+ Working with object-oriented software and a relational database can be cumbersome
+ and time consuming in today's enterprise environments. Hibernate is an object/relational
+ mapping tool for Java environments. The term object/relational mapping (ORM) refers to
+ the technique of mapping a data representation from an object model to a relational
+ data model with a SQL-based schema.
+ </para>
+
+ <para>
+ Hibernate not only takes care of the mapping from Java classes to
+ database tables (and from Java data types to SQL data types), but also provides data
+ query and retrieval facilities and can significantly reduce development time otherwise
+ spent with manual data handling in SQL and JDBC.
+ </para>
+
+ <para>
+ Hibernates goal is to relieve the developer from 95 percent of common data persistence
+ related programming tasks. Hibernate may not be the best solution for data-centric
+ applications that only use stored-procedures to implement the business logic in the
+ database, it is most useful with object-oriented domain models and business logic in
+ the Java-based middle-tier. However, Hibernate can certainly help you to remove or
+ encapsulate vendor-specific SQL code and will help with the common task of result set
+ translation from a tabular representation to a graph of objects.
+ </para>
+
+ <para>
+ If you are new to Hibernate and Object/Relational Mapping or even Java,
+ please follow these steps:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>
+ Read <xref linkend="tutorial"/> for a tutorial with step-by-step
+ instructions. The source code for the tutorial is included in the
+ distribution in the <literal>doc/reference/tutorial/</literal>
+ directory.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Read <xref linkend="architecture"/> to understand the environments where
+ Hibernate can be used.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Have a look at the <literal>eg/</literal> directory in the Hibernate
+ distribution, it contains a simple standalone application. Copy your
+ JDBC driver to the <literal>lib/</literal> directory and edit
+ <literal>etc/hibernate.properties</literal>, specifying correct values for
+ your database. From a command prompt in the distribution directory,
+ type <literal>ant eg</literal> (using Ant), or under Windows, type
+ <literal>build eg</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Use this reference documentation as your primary source of information.
+ Consider reading <emphasis>Hibernate in Action</emphasis>
+ (http://www.manning.com/bauer) if you need more help with application
+ design or if you prefer a step-by-step tutorial. Also visit
+ http://caveatemptor.hibernate.org and download the example application
+ for Hibernate in Action.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ FAQs are answered on the Hibernate website.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Third party demos, examples, and tutorials are linked on the Hibernate
+ website.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The Community Area on the Hibernate website is a good resource for
+ design patterns and various integration solutions (Tomcat, JBoss AS,
+ Struts, EJB, etc.).
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ If you have questions, use the user forum linked on the Hibernate website. We also
+ provide a JIRA issue trackings system for bug reports and feature requests. If you
+ are interested in the development of Hibernate, join the developer mailing list. If
+ you are interested in translating this documentation into your language, contact us
+ on the developer mailing list.
+ </para>
+
+ <para>
+ Commercial development support, production support, and training for Hibernate is
+ available through JBoss Inc. (see http://www.hibernate.org/SupportTraining/).
+ Hibernate is a Professional Open Source project and a critical component of the
+ JBoss Enterprise Middleware System (JEMS) suite of products.
+ </para>
+
+ </preface>
+
+ &tutorial;
+
+ &architecture;
+
+ &configuration;
+
+ &persistent-classes;
+
+ &basic-mapping;
+ &collection-mapping;
+ &association-mapping;
+ &component-mapping;
+ &inheritance-mapping;
+
+ &session-api;
+ &transactions;
+ &events;
+ &batch;
+
+ &query-hql;
+ &query-criteria;
+ &query-sql;
+ &filters;
+ &xml;
+
+ &performance;
+
+ &toolset-guide;
+
+ &example-parentchild;
+ &example-weblog;
+ &example-mappings;
+
+ &best-practices;
+
+</book>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/architecture.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/architecture.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/architecture.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,357 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="architecture">
+
+ <title>Architecture</title>
+
+ <sect1 id="architecture-overview" revision="1">
+ <title>Overview</title>
+
+ <para>
+ A (very) high-level view of the Hibernate architecture:
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="shared/images/overview.svg" format="SVG" align="center" />
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../shared/images/overview.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ This diagram shows Hibernate using the database and configuration data to
+ provide persistence services (and persistent objects) to the application.
+ </para>
+
+ <para>
+ We would like to show a more detailed view of the runtime architecture.
+ Unfortunately, Hibernate is flexible and supports several approaches. We will
+ show the two extremes. The "lite" architecture has the application
+ provide its own JDBC connections and manage its own transactions. This approach
+ uses a minimal subset of Hibernate's APIs:
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="shared/images/lite.svg" format="SVG" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../shared/images/lite.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ The "full cream" architecture abstracts the application away from the
+ underlying JDBC/JTA APIs and lets Hibernate take care of the details.
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="shared/images/full_cream.svg" format="SVG" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../shared/images/full_cream.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ Heres some definitions of the objects in the diagrams:
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term>
+ <listitem>
+ <para>
+ A threadsafe (immutable) cache of compiled mappings for a single database.
+ A factory for <literal>Session</literal> and a client of
+ <literal>ConnectionProvider</literal>. Might hold an optional (second-level)
+ cache of data that is reusable between transactions, at a
+ process- or cluster-level.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Session (<literal>org.hibernate.Session</literal>)</term>
+ <listitem>
+ <para>
+ A single-threaded, short-lived object representing a conversation between
+ the application and the persistent store. Wraps a JDBC connection. Factory
+ for <literal>Transaction</literal>. Holds a mandatory (first-level) cache
+ of persistent objects, used when navigating the object graph or looking up
+ objects by identifier.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Persistent objects and collections</term>
+ <listitem>
+ <para>
+ Short-lived, single threaded objects containing persistent state and business
+ function. These might be ordinary JavaBeans/POJOs, the only special thing about
+ them is that they are currently associated with (exactly one)
+ <literal>Session</literal>. As soon as the <literal>Session</literal> is closed,
+ they will be detached and free to use in any application layer (e.g. directly
+ as data transfer objects to and from presentation).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Transient and detached objects and collections</term>
+ <listitem>
+ <para>
+ Instances of persistent classes that are not currently associated with a
+ <literal>Session</literal>. They may have been instantiated by
+ the application and not (yet) persisted or they may have been instantiated by a
+ closed <literal>Session</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Transaction (<literal>org.hibernate.Transaction</literal>)</term>
+ <listitem>
+ <para>
+ (Optional) A single-threaded, short-lived object used by the application to
+ specify atomic units of work. Abstracts application from underlying JDBC,
+ JTA or CORBA transaction. A <literal>Session</literal> might span several
+ <literal>Transaction</literal>s in some cases. However, transaction demarcation,
+ either using the underlying API or <literal>Transaction</literal>, is never
+ optional!
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term>
+ <listitem>
+ <para>
+ (Optional) A factory for (and pool of) JDBC connections. Abstracts application from
+ underlying <literal>Datasource</literal> or <literal>DriverManager</literal>.
+ Not exposed to application, but can be extended/implemented by the developer.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term>
+ <listitem>
+ <para>
+ (Optional) A factory for <literal>Transaction</literal> instances. Not exposed to the
+ application, but can be extended/implemented by the developer.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><emphasis>Extension Interfaces</emphasis></term>
+ <listitem>
+ <para>
+ Hibernate offers many optional extension interfaces you can implement to customize
+ the behavior of your persistence layer. See the API documentation for details.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
+ <para>
+ Given a "lite" architecture, the application bypasses the
+ <literal>Transaction</literal>/<literal>TransactionFactory</literal> and/or
+ <literal>ConnectionProvider</literal> APIs to talk to JTA or JDBC directly.
+ </para>
+ </sect1>
+
+ <sect1 id="architecture-states" revision="1">
+ <title>Instance states</title>
+ <para>
+ An instance of a persistent classes may be in one of three different states,
+ which are defined with respect to a <emphasis>persistence context</emphasis>.
+ The Hibernate <literal>Session</literal> object is the persistence context:
+ </para>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>transient</term>
+ <listitem>
+ <para>
+ The instance is not, and has never been associated with
+ any persistence context. It has no persistent identity
+ (primary key value).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>persistent</term>
+ <listitem>
+ <para>
+ The instance is currently associated with a persistence
+ context. It has a persistent identity (primary key value)
+ and, perhaps, a corresponding row in the database. For a
+ particular persistence context, Hibernate
+ <emphasis>guarantees</emphasis> that persistent identity
+ is equivalent to Java identity (in-memory location of the
+ object).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>detached</term>
+ <listitem>
+ <para>
+ The instance was once associated with a persistence
+ context, but that context was closed, or the instance
+ was serialized to another process. It has a persistent
+ identity and, perhaps, a corrsponding row in the database.
+ For detached instances, Hibernate makes no guarantees
+ about the relationship between persistent identity and
+ Java identity.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="architecture-jmx" revision="1">
+ <title>JMX Integration</title>
+
+ <para>
+ JMX is the J2EE standard for management of Java components. Hibernate may be managed via
+ a JMX standard service. We provide an MBean implementation in the distribution,
+ <literal>org.hibernate.jmx.HibernateService</literal>.
+ </para>
+
+ <para>
+ For an example how to deploy Hibernate as a JMX service on the JBoss Application Server,
+ please see the JBoss User Guide. On JBoss AS, you also get these benefits if you deploy
+ using JMX:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Session Management:</emphasis> The Hibernate <literal>Session</literal>'s lifecycle
+ can be automatically bound to the scope of a JTA transaction. This means you no
+ longer have to manually open and close the <literal>Session</literal>, this
+ becomes the job of a JBoss EJB interceptor. You also don't have to worry about
+ transaction demarcation in your code anymore (unless you'd like to write a portable
+ persistence layer of course, use the optional Hibernate <literal>Transaction</literal>
+ API for this). You call the <literal>HibernateContext</literal> to access a
+ <literal>Session</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>HAR deployment:</emphasis> Usually you deploy the Hibernate JMX service using a JBoss
+ service deployment descriptor (in an EAR and/or SAR file), it supports all the usual
+ configuration options of a Hibernate <literal>SessionFactory</literal>. However, you still
+ have to name all your mapping files in the deployment descriptor. If you decide to use
+ the optional HAR deployment, JBoss will automatically detect all mapping files in your
+ HAR file.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Consult the JBoss AS user guide for more information about these options.
+ </para>
+
+ <para>
+ Another feature available as a JMX service are runtime Hibernate statistics. See
+ <xref linkend="configuration-optional-statistics"/>.
+ </para>
+ </sect1>
+
+ <sect1 id="architecture-jca" revision="1">
+ <title>JCA Support</title>
+ <para>
+ Hibernate may also be configured as a JCA connector. Please see the website for more
+ details. Please note that Hibernate JCA support is still considered experimental.
+ </para>
+ </sect1>
+
+ <sect1 id="architecture-current-session" revision="2">
+ <title>Contextual Sessions</title>
+ <para>
+ Most applications using Hibernate need some form of "contextual" sessions, where a given
+ session is in effect throughout the scope of a given context. However, across applications
+ the definition of what constitutes a context is typically different; and different contexts
+ define different scopes to the notion of current. Applications using Hibernate prior
+ to version 3.0 tended to utilize either home-grown <literal>ThreadLocal</literal>-based
+ contextual sessions, helper classes such as <literal>HibernateUtil</literal>, or utilized
+ third-party frameworks (such as Spring or Pico) which provided proxy/interception-based contextual sessions.
+ </para>
+ <para>
+ Starting with version 3.0.1, Hibernate added the <literal>SessionFactory.getCurrentSession()</literal>
+ method. Initially, this assumed usage of <literal>JTA</literal> transactions, where the
+ <literal>JTA</literal> transaction defined both the scope and context of a current session.
+ The Hibernate team maintains that, given the maturity of the numerous stand-alone
+ <literal>JTA TransactionManager</literal> implementations out there, most (if not all)
+ applications should be using <literal>JTA</literal> transaction management whether or not
+ they are deployed into a <literal>J2EE</literal> container. Based on that, the
+ <literal>JTA</literal>-based contextual sessions is all you should ever need to use.
+ </para>
+ <para>
+ However, as of version 3.1, the processing behind
+ <literal>SessionFactory.getCurrentSession()</literal> is now pluggable. To that
+ end, a new extension interface (<literal>org.hibernate.context.CurrentSessionContext</literal>)
+ and a new configuration parameter (<literal>hibernate.current_session_context_class</literal>)
+ have been added to allow pluggability of the scope and context of defining current sessions.
+ </para>
+ <para>
+ See the Javadocs for the <literal>org.hibernate.context.CurrentSessionContext</literal>
+ interface for a detailed discussion of its contract. It defines a single method,
+ <literal>currentSession()</literal>, by which the implementation is responsible for
+ tracking the current contextual session. Out-of-the-box, Hibernate comes with three
+ implementations of this interface.
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>org.hibernate.context.JTASessionContext</literal> - current sessions
+ are tracked and scoped by a <literal>JTA</literal> transaction. The processing
+ here is exactly the same as in the older JTA-only approach. See the Javadocs
+ for details.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>org.hibernate.context.ThreadLocalSessionContext</literal> - current
+ sessions are tracked by thread of execution. Again, see the Javadocs for details.
+ </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>
+ The first two implementations provide a "one session - one database transaction" programming
+ model, also known and used as <emphasis>session-per-request</emphasis>. The beginning
+ and end of a Hibernate session is defined by the duration of a database transaction.
+ If you use programatic transaction demarcation in plain JSE without JTA, you are adviced to
+ use the Hibernate <literal>Transaction</literal> API to hide the underlying transaction system
+ from your code. If you use JTA, use the JTA interfaces to demarcate transactions. If you
+ execute in an EJB container that supports CMT, transaction boundaries are defined declaratively
+ and you don't need any transaction or session demarcation operations in your code.
+ Refer to <xref linkend="transactions"/> for more information and code examples.
+ </para>
+
+ <para>
+ The <literal>hibernate.current_session_context_class</literal> configuration parameter
+ defines which <literal>org.hibernate.context.CurrentSessionContext</literal> implementation
+ should be used. Note that for backwards compatibility, if this config param is not set
+ but a <literal>org.hibernate.transaction.TransactionManagerLookup</literal> is configured,
+ Hibernate will use the <literal>org.hibernate.context.JTASessionContext</literal>.
+ Typically, the value of this parameter would just name the implementation class to
+ use; for the three out-of-the-box implementations, however, there are two corresponding
+ short names, "jta", "thread", and "managed".
+ </para>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/association_mapping.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/association_mapping.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/association_mapping.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,625 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="associations">
+
+ <title>Association Mappings</title>
+
+ <sect1 id="assoc-intro" revision="1">
+ <title>Introduction</title>
+
+ <para>
+ Association mappings are the often most difficult thing to get right. In
+ this section we'll go through the canonical cases one by one, starting
+ with unidirectional mappings, and then considering the bidirectional cases.
+ We'll use <literal>Person</literal> and <literal>Address</literal> in all
+ the examples.
+ </para>
+
+ <para>
+ We'll classify associations by whether or not they map to an intervening
+ join table, and by multiplicity.
+ </para>
+
+ <para>
+ Nullable foreign keys are not considered good practice in traditional data
+ modelling, so all our examples use not null foreign keys. This is not a
+ requirement of Hibernate, and the mappings will all work if you drop the
+ nullability constraints.
+ </para>
+
+ </sect1>
+
+ <sect1 id="assoc-unidirectional" revision="1">
+ <title>Unidirectional associations</title>
+
+ <sect2 id="assoc-unidirectional-m21">
+ <title>many to one</title>
+
+ <para>
+ A <emphasis>unidirectional many-to-one association</emphasis> is the most
+ common kind of unidirectional association.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"/>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-unidirectional-121">
+ <title>one to one</title>
+
+ <para>
+ A <emphasis>unidirectional one-to-one association on a foreign key</emphasis>
+ is almost identical. The only difference is the column unique constraint.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <many-to-one name="address"
+ column="addressId"
+ unique="true"
+ not-null="true"/>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ <para>
+ A <emphasis>unidirectional one-to-one association on a primary key</emphasis>
+ usually uses a special id generator. (Notice that we've reversed the direction
+ of the association in this example.)
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+</class>
+
+<class name="Address">
+ <id name="id" column="personId">
+ <generator class="foreign">
+ <param name="property">person</param>
+ </generator>
+ </id>
+ <one-to-one name="person" constrained="true"/>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-unidirectional-12m">
+ <title>one to many</title>
+
+ <para>
+ A <emphasis>unidirectional one-to-many association on a foreign key</emphasis>
+ is a very unusual case, and is not really recommended.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <set name="addresses">
+ <key column="personId"
+ not-null="true"/>
+ <one-to-many class="Address"/>
+ </set>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( addressId bigint not null primary key, personId bigint not null )
+ ]]></programlisting>
+
+ <para>
+ We think it's better to use a join table for this kind of association.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="assoc-unidirectional-join" revision="1">
+ <title>Unidirectional associations with join tables</title>
+
+ <sect2 id="assoc-unidirectional-join-12m">
+ <title>one to many</title>
+
+ <para>
+ A <emphasis>unidirectional one-to-many association on a join table</emphasis>
+ is much preferred. Notice that by specifying <literal>unique="true"</literal>,
+ we have changed the multiplicity from many-to-many to one-to-many.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <set name="addresses" table="PersonAddress">
+ <key column="personId"/>
+ <many-to-many column="addressId"
+ unique="true"
+ class="Address"/>
+ </set>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-unidirectional-join-m21">
+ <title>many to one</title>
+
+ <para>
+ A <emphasis>unidirectional many-to-one association on a join table</emphasis>
+ is quite common when the association is optional.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <join table="PersonAddress"
+ optional="true">
+ <key column="personId" unique="true"/>
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"/>
+ </join>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-unidirectional-join-121">
+ <title>one to one</title>
+
+ <para>
+ A <emphasis>unidirectional one-to-one association on a join table</emphasis>
+ is extremely unusual, but possible.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <join table="PersonAddress"
+ optional="true">
+ <key column="personId"
+ unique="true"/>
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"
+ unique="true"/>
+ </join>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-unidirectional-join-m2m">
+ <title>many to many</title>
+
+ <para>
+ Finally, we have a <emphasis>unidirectional many-to-many association</emphasis>.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <set name="addresses" table="PersonAddress">
+ <key column="personId"/>
+ <many-to-many column="addressId"
+ class="Address"/>
+ </set>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="assoc-bidirectional" revision="1">
+ <title>Bidirectional associations</title>
+
+ <sect2 id="assoc-bidirectional-m21" revision="2">
+ <title>one to many / many to one</title>
+
+ <para>
+ A <emphasis>bidirectional many-to-one association</emphasis> is the
+ most common kind of association. (This is the standard parent/child
+ relationship.)
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"/>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+ <set name="people" inverse="true">
+ <key column="addressId"/>
+ <one-to-many class="Person"/>
+ </set>
+</class>]]></programlisting>
+
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ <para>
+ If you use a <literal>List</literal> (or other indexed collection) you need
+ to set the <literal>key</literal> column of the foreign key to <literal>not null</literal>,
+ and let Hibernate manage the association from the collections side to maintain the index
+ of each element (making the other side virtually inverse by setting
+ <literal>update="false"</literal> and <literal>insert="false"</literal>):
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id"/>
+ ...
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"
+ insert="false"
+ update="false"/>
+</class>
+
+<class name="Address">
+ <id name="id"/>
+ ...
+ <list name="people">
+ <key column="addressId" not-null="true"/>
+ <list-index column="peopleIdx"/>
+ <one-to-many class="Person"/>
+ </list>
+</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 id="assoc-bidirectional-121">
+ <title>one to one</title>
+
+ <para>
+ A <emphasis>bidirectional one-to-one association on a foreign key</emphasis>
+ is quite common.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <many-to-one name="address"
+ column="addressId"
+ unique="true"
+ not-null="true"/>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+ <one-to-one name="person"
+ property-ref="address"/>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ <para>
+ A <emphasis>bidirectional one-to-one association on a primary key</emphasis>
+ uses the special id generator.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <one-to-one name="address"/>
+</class>
+
+<class name="Address">
+ <id name="id" column="personId">
+ <generator class="foreign">
+ <param name="property">person</param>
+ </generator>
+ </id>
+ <one-to-one name="person"
+ constrained="true"/>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="assoc-bidirectional-join" revision="1">
+ <title>Bidirectional associations with join tables</title>
+
+ <sect2 id="assoc-bidirectional-join-12m">
+ <title>one to many / many to one</title>
+
+ <para>
+ A <emphasis>bidirectional one-to-many association on a join table</emphasis>.
+ Note that the <literal>inverse="true"</literal> can go on either end of the
+ association, on the collection, or on the join.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <set name="addresses"
+ table="PersonAddress">
+ <key column="personId"/>
+ <many-to-many column="addressId"
+ unique="true"
+ class="Address"/>
+ </set>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+ <join table="PersonAddress"
+ inverse="true"
+ optional="true">
+ <key column="addressId"/>
+ <many-to-one name="person"
+ column="personId"
+ not-null="true"/>
+ </join>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-bidirectional-join-121">
+ <title>one to one</title>
+
+ <para>
+ A <emphasis>bidirectional one-to-one association on a join table</emphasis>
+ is extremely unusual, but possible.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <join table="PersonAddress"
+ optional="true">
+ <key column="personId"
+ unique="true"/>
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"
+ unique="true"/>
+ </join>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+ <join table="PersonAddress"
+ optional="true"
+ inverse="true">
+ <key column="addressId"
+ unique="true"/>
+ <many-to-one name="person"
+ column="personId"
+ not-null="true"
+ unique="true"/>
+ </join>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-bidirectional-join-m2m" revision="1">
+ <title>many to many</title>
+
+ <para>
+ Finally, we have a <emphasis>bidirectional many-to-many association</emphasis>.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <set name="addresses" table="PersonAddress">
+ <key column="personId"/>
+ <many-to-many column="addressId"
+ class="Address"/>
+ </set>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+ <set name="people" inverse="true" table="PersonAddress">
+ <key column="addressId"/>
+ <many-to-many column="personId"
+ class="Person"/>
+ </set>
+</class>]]></programlisting>
+
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="assoc-complex">
+ <title>More complex association mappings</title>
+
+ <para>
+ More complex association joins are <emphasis>extremely</emphasis> rare.
+ Hibernate makes it possible to handle more complex situations using
+ SQL fragments embedded in the mapping document. For example, if a table
+ with historical account information data defines
+ <literal>accountNumber</literal>, <literal>effectiveEndDate</literal>
+ and <literal>effectiveStartDate</literal>columns, mapped as follows:
+ </para>
+
+ <programlisting><![CDATA[<properties name="currentAccountKey">
+ <property name="accountNumber" type="string" not-null="true"/>
+ <property name="currentAccount" type="boolean">
+ <formula>case when effectiveEndDate is null then 1 else 0 end</formula>
+ </property>
+</properties>
+<property name="effectiveEndDate" type="date"/>
+<property name="effectiveStateDate" type="date" not-null="true"/>]]></programlisting>
+
+ <para>
+ Then we can map an association to the <emphasis>current</emphasis> instance
+ (the one with null <literal>effectiveEndDate</literal>) using:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="currentAccountInfo"
+ property-ref="currentAccountKey"
+ class="AccountInfo">
+ <column name="accountNumber"/>
+ <formula>'1'</formula>
+</many-to-one>]]></programlisting>
+
+ <para>
+ In a more complex example, imagine that the association between
+ <literal>Employee</literal> and <literal>Organization</literal> is maintained
+ in an <literal>Employment</literal> table full of historical employment data.
+ Then an association to the employee's <emphasis>most recent</emphasis> employer
+ (the one with the most recent <literal>startDate</literal>) might be mapped this way:
+ </para>
+
+ <programlisting><![CDATA[<join>
+ <key column="employeeId"/>
+ <subselect>
+ select employeeId, orgId
+ from Employments
+ group by orgId
+ having startDate = max(startDate)
+ </subselect>
+ <many-to-one name="mostRecentEmployer"
+ class="Organization"
+ column="orgId"/>
+</join>]]></programlisting>
+
+ <para>
+ You can get quite creative with this functionality, but it is usually more practical
+ to handle these kinds of cases using HQL or a criteria query.
+ </para>
+
+ </sect1>
+
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/basic_mapping.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/basic_mapping.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/basic_mapping.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,3562 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="mapping">
+ <title>Basic O/R Mapping</title>
+
+ <sect1 id="mapping-declaration" revision="2">
+ <title>Mapping declaration</title>
+
+ <para>
+ Object/relational mappings are usually defined in an XML document. The mapping
+ document is designed to be readable and hand-editable. The mapping language is
+ Java-centric, meaning that mappings are constructed around persistent class
+ declarations, not table declarations.
+ </para>
+
+ <para>
+ Note that, even though many Hibernate users choose to write the XML by hand,
+ a number of tools exist to generate the mapping document, including XDoclet,
+ Middlegen and AndroMDA.
+ </para>
+
+ <para>
+ Lets kick off with an example mapping:
+ </para>
+
+ <programlisting id="mapping-declaration-ex1" revision="1"><![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">
+
+<hibernate-mapping package="eg">
+
+ <class name="Cat"
+ table="cats"
+ discriminator-value="C">
+
+ <id name="id">
+ <generator class="native"/>
+ </id>
+
+ <discriminator column="subclass"
+ type="character"/>
+
+ <property name="weight"/>
+
+ <property name="birthdate"
+ type="date"
+ not-null="true"
+ update="false"/>
+
+ <property name="color"
+ type="eg.types.ColorUserType"
+ not-null="true"
+ update="false"/>
+
+ <property name="sex"
+ not-null="true"
+ update="false"/>
+
+ <property name="litterId"
+ column="litterId"
+ update="false"/>
+
+ <many-to-one name="mother"
+ column="mother_id"
+ update="false"/>
+
+ <set name="kittens"
+ inverse="true"
+ order-by="litter_id">
+ <key column="mother_id"/>
+ <one-to-many class="Cat"/>
+ </set>
+
+ <subclass name="DomesticCat"
+ discriminator-value="D">
+
+ <property name="name"
+ type="string"/>
+
+ </subclass>
+
+ </class>
+
+ <class name="Dog">
+ <!-- mapping for Dog could go here -->
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ We will now discuss the content of the mapping document. We will only describe the
+ document elements and attributes that are used by Hibernate at runtime. The mapping
+ document also contains some extra optional attributes and elements that affect the
+ database schemas exported by the schema export tool. (For example the <literal>
+ not-null</literal> attribute.)
+ </para>
+
+
+
+ <sect2 id="mapping-declaration-doctype" revision="3">
+ <title>Doctype</title>
+
+ <para>
+ All XML mappings should declare the doctype shown. The actual DTD may be found
+ at the URL above, in the directory <literal>hibernate-x.x.x/src/org/hibernate
+ </literal> or in <literal>hibernate3.jar</literal>. Hibernate will always look for
+ the DTD in its classpath first. If you experience lookups of the DTD using an
+ Internet connection, check your DTD declaration against the contents of your
+ claspath.
+ </para>
+
+ <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 <xref linkend="mapping-types-custom">typedef</xref>.
+ </para>
+ </sect3>
+ </sect2>
+
+ <sect2 id="mapping-declaration-mapping" revision="3">
+ <title>hibernate-mapping</title>
+
+ <para>
+ This element has several optional attributes. The <literal>schema</literal> and
+ <literal>catalog</literal> attributes specify that tables referred to in this mapping
+ belong to the named schema and/or catalog. If specified, tablenames will be qualified
+ by the given schema and catalog names. If missing, tablenames will be unqualified.
+ The <literal>default-cascade</literal> attribute specifies what cascade style
+ should be assumed for properties and collections which do not specify a
+ <literal>cascade</literal> attribute. The <literal>auto-import</literal> attribute lets us
+ use unqualified class names in the query language, by default.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="hm1" coords="2 55"/>
+ <area id="hm2" coords="3 55"/>
+ <area id="hm3" coords="4 55"/>
+ <area id="hm4" coords="5 55"/>
+ <area id="hm5" coords="6 55"/>
+ <area id="hm6" coords="7 55"/>
+ <area id="hm7" coords="8 55"/>
+ </areaspec>
+ <programlisting><![CDATA[<hibernate-mapping
+ schema="schemaName"
+ catalog="catalogName"
+ default-cascade="cascade_style"
+ default-access="field|property|ClassName"
+ default-lazy="true|false"
+ auto-import="true|false"
+ package="package.name"
+ />]]></programlisting>
+ <calloutlist>
+ <callout arearefs="hm1">
+ <para>
+ <literal>schema</literal> (optional): The name of a database schema.
+ </para>
+ </callout>
+ <callout arearefs="hm2">
+ <para>
+ <literal>catalog</literal> (optional): The name of a database catalog.
+ </para>
+ </callout>
+ <callout arearefs="hm3">
+ <para>
+ <literal>default-cascade</literal> (optional - defaults to <literal>none</literal>):
+ A default cascade style.
+ </para>
+ </callout>
+ <callout arearefs="hm4">
+ <para>
+ <literal>default-access</literal> (optional - defaults to <literal>property</literal>):
+ The strategy Hibernate should use for accessing all properties. Can be a custom
+ implementation of <literal>PropertyAccessor</literal>.
+ </para>
+ </callout>
+ <callout arearefs="hm5">
+ <para>
+ <literal>default-lazy</literal> (optional - defaults to <literal>true</literal>):
+ The default value for unspecifed <literal>lazy</literal> attributes of class and
+ collection mappings.
+ </para>
+ </callout>
+ <callout arearefs="hm6">
+ <para>
+ <literal>auto-import</literal> (optional - defaults to <literal>true</literal>):
+ Specifies whether we can use unqualified class names (of classes in this mapping)
+ in the query language.
+ </para>
+ </callout>
+ <callout arearefs="hm7">
+ <para>
+ <literal>package</literal> (optional): Specifies a package prefix to assume for
+ unqualified class names in the mapping document.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ If you have two persistent classes with the same (unqualified) name, you should set
+ <literal>auto-import="false"</literal>. Hibernate will throw an exception if you attempt
+ to assign two classes to the same "imported" name.
+ </para>
+
+ <para>
+ Note that the <literal>hibernate-mapping</literal> element allows you to nest
+ several persistent <literal><class></literal> mappings, as shown above.
+ It is however good practice (and expected by some tools) to map only a single
+ persistent class (or a single class hierarchy) in one mapping file and name
+ it after the persistent superclass, e.g. <literal>Cat.hbm.xml</literal>,
+ <literal>Dog.hbm.xml</literal>, or if using inheritance,
+ <literal>Animal.hbm.xml</literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-class" revision="3">
+ <title>class</title>
+
+ <para>
+ You may declare a persistent class using the <literal>class</literal> element:
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="class1" coords="2 55"/>
+ <area id="class2" coords="3 55" />
+ <area id="class3" coords="4 55"/>
+ <area id="class4" coords="5 55" />
+ <area id="class5" coords="6 55"/>
+ <area id="class6" coords="7 55" />
+ <area id="class7" coords="8 55"/>
+ <area id="class8" coords="9 55" />
+ <area id="class9" coords="10 55" />
+ <area id="class10" coords="11 55"/>
+ <area id="class11" coords="12 55"/>
+ <area id="class12" coords="13 55"/>
+ <area id="class13" coords="14 55"/>
+ <area id="class14" coords="15 55"/>
+ <area id="class15" coords="16 55"/>
+ <area id="class16" coords="17 55"/>
+ <area id="class17" coords="18 55"/>
+ <area id="class18" coords="19 55"/>
+ <area id="class19" coords="20 55"/>
+ <area id="class20" coords="21 55"/>
+ <area id="class21" coords="22 55"/>
+ </areaspec>
+ <programlisting><![CDATA[<class
+ name="ClassName"
+ table="tableName"
+ discriminator-value="discriminator_value"
+ mutable="true|false"
+ schema="owner"
+ catalog="catalog"
+ proxy="ProxyInterface"
+ dynamic-update="true|false"
+ dynamic-insert="true|false"
+ select-before-update="true|false"
+ polymorphism="implicit|explicit"
+ where="arbitrary sql where condition"
+ persister="PersisterClass"
+ batch-size="N"
+ optimistic-lock="none|version|dirty|all"
+ lazy="true|false"
+ entity-name="EntityName"
+ check="arbitrary sql check condition"
+ rowid="rowid"
+ subselect="SQL expression"
+ abstract="true|false"
+ node="element-name"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="class1">
+ <para>
+ <literal>name</literal> (optional): The fully qualified Java class name of the
+ persistent class (or interface). If this attribute is missing, it is assumed
+ that the mapping is for a non-POJO entity.
+ </para>
+ </callout>
+ <callout arearefs="class2">
+ <para>
+ <literal>table</literal> (optional - defaults to the unqualified class name): The
+ name of its database table.
+ </para>
+ </callout>
+ <callout arearefs="class3">
+ <para>
+ <literal>discriminator-value</literal> (optional - defaults to the class name): A value
+ that distiguishes individual subclasses, used for polymorphic behaviour. Acceptable
+ values include <literal>null</literal> and <literal>not null</literal>.
+ </para>
+ </callout>
+ <callout arearefs="class4">
+ <para>
+ <literal>mutable</literal> (optional, defaults to <literal>true</literal>): Specifies
+ that instances of the class are (not) mutable.
+ </para>
+ </callout>
+ <callout arearefs="class5">
+ <para>
+ <literal>schema</literal> (optional): Override the schema name specified by
+ the root <literal><hibernate-mapping></literal> element.
+ </para>
+ </callout>
+ <callout arearefs="class6">
+ <para>
+ <literal>catalog</literal> (optional): Override the catalog name specified by
+ the root <literal><hibernate-mapping></literal> element.
+ </para>
+ </callout>
+ <callout arearefs="class7">
+ <para>
+ <literal>proxy</literal> (optional): Specifies an interface to use for lazy
+ initializing proxies. You may specify the name of the class itself.
+ </para>
+ </callout>
+ <callout arearefs="class8">
+ <para>
+ <literal>dynamic-update</literal> (optional, defaults to <literal>false</literal>):
+ Specifies that <literal>UPDATE</literal> SQL should be generated at runtime and
+ contain only those columns whose values have changed.
+ </para>
+ </callout>
+ <callout arearefs="class9">
+ <para>
+ <literal>dynamic-insert</literal> (optional, defaults to <literal>false</literal>):
+ Specifies that <literal>INSERT</literal> SQL should be generated at runtime and
+ contain only the columns whose values are not null.
+ </para>
+ </callout>
+ <callout arearefs="class10">
+ <para>
+ <literal>select-before-update</literal> (optional, defaults to <literal>false</literal>):
+ Specifies that Hibernate should <emphasis>never</emphasis> perform an SQL <literal>UPDATE</literal>
+ unless it is certain that an object is actually modified. In certain cases (actually, only
+ when a transient object has been associated with a new session using <literal>update()</literal>),
+ this means that Hibernate will perform an extra SQL <literal>SELECT</literal> to determine
+ if an <literal>UPDATE</literal> is actually required.
+ </para>
+ </callout>
+ <callout arearefs="class11">
+ <para>
+ <literal>polymorphism</literal> (optional, defaults to <literal>implicit</literal>):
+ Determines whether implicit or explicit query polymorphism is used.
+ </para>
+ </callout>
+ <callout arearefs="class12">
+ <para>
+ <literal>where</literal> (optional) specify an arbitrary SQL <literal>WHERE</literal>
+ condition to be used when retrieving objects of this class
+ </para>
+ </callout>
+ <callout arearefs="class13">
+ <para>
+ <literal>persister</literal> (optional): Specifies a custom <literal>ClassPersister</literal>.
+ </para>
+ </callout>
+ <callout arearefs="class14">
+ <para>
+ <literal>batch-size</literal> (optional, defaults to <literal>1</literal>) specify a "batch size"
+ for fetching instances of this class by identifier.
+ </para>
+ </callout>
+ <callout arearefs="class15">
+ <para>
+ <literal>optimistic-lock</literal> (optional, defaults to <literal>version</literal>):
+ Determines the optimistic locking strategy.
+ </para>
+ </callout>
+ <callout arearefs="class16">
+ <para>
+ <literal>lazy</literal> (optional): Lazy fetching may be completely disabled by setting
+ <literal>lazy="false"</literal>.
+ </para>
+ </callout>
+ <callout arearefs="class17">
+ <para>
+ <literal>entity-name</literal> (optional, defaults to the class name): Hibernate3
+ allows a class to be mapped multiple times (to different tables, potentially),
+ and allows entity mappings that are represented by Maps or XML at the Java level.
+ In these cases, you should provide an explicit arbitrary name for the entity. See
+ <xref linkend="persistent-classes-dynamicmodels"/> and <xref linkend="xml"/>
+ for more information.
+ </para>
+ </callout>
+ <callout arearefs="class18">
+ <para>
+ <literal>check</literal> (optional): A SQL expression used to generate a multi-row
+ <emphasis>check</emphasis> constraint for automatic schema generation.
+ </para>
+ </callout>
+ <callout arearefs="class19">
+ <para>
+ <literal>rowid</literal> (optional): Hibernate can use so called ROWIDs on databases
+ which support. E.g. on Oracle, Hibernate can use the <literal>rowid</literal> extra
+ column for fast updates if you set this option to <literal>rowid</literal>. A ROWID
+ is an implementation detail and represents the physical location of a stored tuple.
+ </para>
+ </callout>
+ <callout arearefs="class20">
+ <para>
+ <literal>subselect</literal> (optional): Maps an immutable and read-only entity
+ to a database subselect. Useful if you want to have a view instead of a base table,
+ but don't. See below for more information.
+ </para>
+ </callout>
+ <callout arearefs="class21">
+ <para>
+ <literal>abstract</literal> (optional): Used to mark abstract superclasses in
+ <literal><union-subclass></literal> hierarchies.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ It is perfectly acceptable for the named persistent class to be an interface. You would then
+ declare implementing classes of that interface using the <literal><subclass></literal>
+ element. You may persist any <emphasis>static</emphasis> inner class. You should specify the
+ class name using the standard form ie. <literal>eg.Foo$Bar</literal>.
+ </para>
+
+ <para>
+ Immutable classes, <literal>mutable="false"</literal>, may not be updated or deleted by the
+ application. This allows Hibernate to make some minor performance optimizations.
+ </para>
+
+ <para>
+ The optional <literal>proxy</literal> attribute enables lazy initialization of persistent
+ instances of the class. Hibernate will initially return CGLIB proxies which implement
+ the named interface. The actual persistent object will be loaded when a method of the
+ proxy is invoked. See "Proxies for Lazy Initialization" below.
+ </para>
+
+ <para><emphasis>Implicit</emphasis> polymorphism means that instances of the class will be returned
+ by a query that names any superclass or implemented interface or the class and that instances
+ of any subclass of the class will be returned by a query that names the class itself.
+ <emphasis>Explicit</emphasis> polymorphism means that class instances will be returned only
+ by queries that explicitly name that class and that queries that name the class will return
+ only instances of subclasses mapped inside this <literal><class></literal> declaration
+ as a <literal><subclass></literal> or <literal><joined-subclass></literal>. For
+ most purposes the default, <literal>polymorphism="implicit"</literal>, is appropriate.
+ Explicit polymorphism is useful when two different classes are mapped to the same table
+ (this allows a "lightweight" class that contains a subset of the table columns).
+ </para>
+
+ <para>
+ The <literal>persister</literal> attribute lets you customize the persistence strategy used for
+ the class. You may, for example, specify your own subclass of
+ <literal>org.hibernate.persister.EntityPersister</literal> or you might even provide a
+ completely new implementation of the interface
+ <literal>org.hibernate.persister.ClassPersister</literal> that implements persistence via,
+ for example, stored procedure calls, serialization to flat files or LDAP. See
+ <literal>org.hibernate.test.CustomPersister</literal> for a simple example (of "persistence"
+ to a <literal>Hashtable</literal>).
+ </para>
+
+ <para>
+ Note that the <literal>dynamic-update</literal> and <literal>dynamic-insert</literal>
+ settings are not inherited by subclasses and so may also be specified on the
+ <literal><subclass></literal> or <literal><joined-subclass></literal> elements.
+ These settings may increase performance in some cases, but might actually decrease
+ performance in others. Use judiciously.
+ </para>
+
+ <para>
+ Use of <literal>select-before-update</literal> will usually decrease performance. It is very
+ useful to prevent a database update trigger being called unnecessarily if you reattach a
+ graph of detached instances to a <literal>Session</literal>.
+ </para>
+
+ <para>
+ If you enable <literal>dynamic-update</literal>, you will have a choice of optimistic
+ locking strategies:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>version</literal> check the version/timestamp columns
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>all</literal> check all columns
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>dirty</literal> check the changed columns, allowing some concurrent updates
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>none</literal> do not use optimistic locking
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ We <emphasis>very</emphasis> strongly recommend that you use version/timestamp
+ columns for optimistic locking with Hibernate. This is the optimal strategy with
+ respect to performance and is the only strategy that correctly handles modifications
+ made to detached instances (ie. when <literal>Session.merge()</literal> is used).
+ </para>
+
+ <para>
+ There is no difference between a view and a base table for a Hibernate mapping, as
+ expected this is transparent at the database level (note that some DBMS don't support
+ views properly, especially with updates). Sometimes you want to use a view, but can't
+ create one in the database (ie. with a legacy schema). In this case, you can map an
+ immutable and read-only entity to a given SQL subselect expression:
+ </para>
+
+ <programlisting><![CDATA[<class name="Summary">
+ <subselect>
+ select item.name, max(bid.amount), count(*)
+ from item
+ join bid on bid.item_id = item.id
+ group by item.name
+ </subselect>
+ <synchronize table="item"/>
+ <synchronize table="bid"/>
+ <id name="name"/>
+ ...
+</class>]]></programlisting>
+
+ <para>
+ Declare the tables to synchronize this entity with, ensuring that auto-flush happens
+ correctly, and that queries against the derived entity do not return stale data.
+ The <literal><subselect></literal> is available as both as an attribute and
+ a nested mapping element.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-id" revision="4">
+ <title>id</title>
+
+ <para>
+ Mapped classes <emphasis>must</emphasis> declare the primary key column of the database
+ table. Most classes will also have a JavaBeans-style property holding the unique identifier
+ of an instance. The <literal><id></literal> element defines the mapping from that
+ property to the primary key column.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="id1" coords="2 70"/>
+ <area id="id2" coords="3 70" />
+ <area id="id3" coords="4 70"/>
+ <area id="id4" coords="5 70" />
+ <area id="id5" coords="6 70" />
+ </areaspec>
+ <programlisting><![CDATA[<id
+ name="propertyName"
+ type="typename"
+ column="column_name"
+ unsaved-value="null|any|none|undefined|id_value"
+ access="field|property|ClassName">
+ node="element-name|@attribute-name|element/@attribute|."
+
+ <generator class="generatorClass"/>
+</id>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="id1">
+ <para>
+ <literal>name</literal> (optional): The name of the identifier property.
+ </para>
+ </callout>
+ <callout arearefs="id2">
+ <para>
+ <literal>type</literal> (optional): A name that indicates the Hibernate type.
+ </para>
+ </callout>
+ <callout arearefs="id3">
+ <para>
+ <literal>column</literal> (optional - defaults to the property name): The
+ name of the primary key column.
+ </para>
+ </callout>
+ <callout arearefs="id4">
+ <para>
+ <literal>unsaved-value</literal> (optional - defaults to a "sensible" value):
+ An identifier property value that indicates that an instance is newly instantiated
+ (unsaved), distinguishing it from detached instances that were saved or loaded
+ in a previous session.
+ </para>
+ </callout>
+ <callout arearefs="id5">
+ <para>
+ <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+ strategy Hibernate should use for accessing the property value.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ If the <literal>name</literal> attribute is missing, it is assumed that the class has no
+ identifier property.
+ </para>
+
+ <para>
+ The <literal>unsaved-value</literal> attribute is almost never needed in Hibernate3.
+ </para>
+
+ <para>
+ There is an alternative <literal><composite-id></literal> declaration to allow access to
+ legacy data with composite keys. We strongly discourage its use for anything else.
+ </para>
+
+ <sect3 id="mapping-declaration-id-generator" revision="2">
+ <title>Generator</title>
+
+ <para>
+ The optional <literal><generator></literal> child element names a Java class used
+ to generate unique identifiers for instances of the persistent class. If any parameters
+ are required to configure or initialize the generator instance, they are passed using the
+ <literal><param></literal> element.
+ </para>
+
+ <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+ <generator class="org.hibernate.id.TableHiLoGenerator">
+ <param name="table">uid_table</param>
+ <param name="column">next_hi_value_column</param>
+ </generator>
+</id>]]></programlisting>
+
+ <para>
+ All generators implement the interface <literal>org.hibernate.id.IdentifierGenerator</literal>.
+ This is a very simple interface; some applications may choose to provide their own specialized
+ implementations. However, Hibernate provides a range of built-in implementations. There are shortcut
+ names for the built-in generators:
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>increment</literal></term>
+ <listitem>
+ <para>
+ generates identifiers of type <literal>long</literal>, <literal>short</literal> or
+ <literal>int</literal> that are unique only when no other process is inserting data
+ into the same table.
+ <emphasis>Do not use in a cluster.</emphasis>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>identity</literal></term>
+ <listitem>
+ <para>
+ supports identity columns in DB2, MySQL, MS SQL Server, Sybase and
+ HypersonicSQL. The returned identifier is of type <literal>long</literal>,
+ <literal>short</literal> or <literal>int</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>sequence</literal></term>
+ <listitem>
+ <para>
+ uses a sequence in DB2, PostgreSQL, Oracle, SAP DB, McKoi or a generator
+ in Interbase. The returned identifier is of type <literal>long</literal>,
+ <literal>short</literal> or <literal>int</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>hilo</literal></term>
+ <listitem>
+ <para id="mapping-declaration-id-hilodescription" revision="1">
+ uses a hi/lo algorithm to efficiently generate identifiers of
+ type <literal>long</literal>, <literal>short</literal> or <literal>int</literal>,
+ given a table and column (by default <literal>hibernate_unique_key</literal> and
+ <literal>next_hi</literal> respectively) as a source of hi values. The hi/lo
+ algorithm generates identifiers that are unique only for a particular database.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>seqhilo</literal></term>
+ <listitem>
+ <para>
+ uses a hi/lo algorithm to efficiently generate identifiers of type
+ <literal>long</literal>, <literal>short</literal> or <literal>int</literal>,
+ given a named database sequence.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>uuid</literal></term>
+ <listitem>
+ <para>
+ uses a 128-bit UUID algorithm to generate identifiers of type string,
+ unique within a network (the IP address is used). The UUID is encoded
+ as a string of hexadecimal digits of length 32.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>guid</literal></term>
+ <listitem>
+ <para>
+ uses a database-generated GUID string on MS SQL Server and MySQL.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>native</literal></term>
+ <listitem>
+ <para>
+ picks <literal>identity</literal>, <literal>sequence</literal> or
+ <literal>hilo</literal> depending upon the capabilities of the
+ underlying database.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>assigned</literal></term>
+ <listitem>
+ <para>
+ lets the application to assign an identifier to the object before
+ <literal>save()</literal> is called. This is the default strategy
+ if no <literal><generator></literal> element is specified.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>select</literal></term>
+ <listitem>
+ <para>
+ retrieves a primary key assigned by a database trigger by selecting
+ the row by some unique key and retrieving the primary key value.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>foreign</literal></term>
+ <listitem>
+ <para>
+ uses the identifier of another associated object. Usually used in conjunction
+ with a <literal><one-to-one></literal> primary key association.
+ </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>
+ </sect3>
+
+ <sect3 id="mapping-declaration-id-hilo" revision="1">
+ <title>Hi/lo algorithm</title>
+ <para>
+ The <literal>hilo</literal> and <literal>seqhilo</literal> generators provide two alternate
+ implementations of the hi/lo algorithm, a favorite approach to identifier generation. The
+ first implementation requires a "special" database table to hold the next available "hi" value.
+ The second uses an Oracle-style sequence (where supported).
+ </para>
+
+ <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+ <generator class="hilo">
+ <param name="table">hi_value</param>
+ <param name="column">next_value</param>
+ <param name="max_lo">100</param>
+ </generator>
+</id>]]></programlisting>
+
+ <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+ <generator class="seqhilo">
+ <param name="sequence">hi_value</param>
+ <param name="max_lo">100</param>
+ </generator>
+</id>]]></programlisting>
+
+ <para>
+ Unfortunately, you can't use <literal>hilo</literal> when supplying your own
+ <literal>Connection</literal> to Hibernate. When Hibernate is using an application
+ server datasource to obtain connections enlisted with JTA, you must properly configure
+ the <literal>hibernate.transaction.manager_lookup_class</literal>.
+ </para>
+ </sect3>
+
+ <sect3 id="mapping-declaration-id-uuid">
+ <title>UUID algorithm</title>
+ <para>
+ The UUID contains: IP address, startup time of the JVM (accurate to a quarter
+ second), system time and a counter value (unique within the JVM). It's not
+ possible to obtain a MAC address or memory address from Java code, so this is
+ the best we can do without using JNI.
+ </para>
+ </sect3>
+
+ <sect3 id="mapping-declaration-id-sequences">
+ <title>Identity columns and sequences</title>
+ <para>
+ For databases which support identity columns (DB2, MySQL, Sybase, MS SQL), you
+ may use <literal>identity</literal> key generation. For databases that support
+ sequences (DB2, Oracle, PostgreSQL, Interbase, McKoi, SAP DB) you may use
+ <literal>sequence</literal> style key generation. Both these strategies require
+ two SQL queries to insert a new object.
+ </para>
+
+ <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+ <generator class="sequence">
+ <param name="sequence">person_id_sequence</param>
+ </generator>
+</id>]]></programlisting>
+
+ <programlisting><![CDATA[<id name="id" type="long" column="person_id" unsaved-value="0">
+ <generator class="identity"/>
+</id>]]></programlisting>
+
+ <para>
+ For cross-platform development, the <literal>native</literal> strategy will
+ choose from the <literal>identity</literal>, <literal>sequence</literal> and
+ <literal>hilo</literal> strategies, dependant upon the capabilities of the
+ underlying database.
+ </para>
+ </sect3>
+
+ <sect3 id="mapping-declaration-id-assigned">
+ <title>Assigned identifiers</title>
+ <para>
+ If you want the application to assign identifiers (as opposed to having
+ Hibernate generate them), you may use the <literal>assigned</literal> generator.
+ This special generator will use the identifier value already assigned to the
+ object's identifier property. This generator is used when the primary key
+ is a natural key instead of a surrogate key. This is the default behavior
+ if you do no specify a <literal><generator></literal> element.
+ </para>
+
+ <para>
+ Choosing the <literal>assigned</literal> generator makes Hibernate use
+ <literal>unsaved-value="undefined"</literal>, forcing Hibernate to go to
+ the database to determine if an instance is transient or detached, unless
+ there is a version or timestamp property, or you define
+ <literal>Interceptor.isUnsaved()</literal>.
+ </para>
+ </sect3>
+
+ <sect3 id="mapping-declaration-id-select">
+ <title>Primary keys assigned by triggers</title>
+ <para>
+ For legacy schemas only (Hibernate does not generate DDL with triggers).
+ </para>
+
+ <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+ <generator class="select">
+ <param name="key">socialSecurityNumber</param>
+ </generator>
+</id>]]></programlisting>
+
+ <para>
+ In the above example, there is a unique valued property named
+ <literal>socialSecurityNumber</literal> defined by the class, as a
+ natural key, and a surrogate key named <literal>person_id</literal>
+ whose value is generated by a trigger.
+ </para>
+
+ </sect3>
+
+ </sect2>
+
+ <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"
+ class="ClassName"
+ mapped="true|false"
+ access="field|property|ClassName">
+ node="element-name|."
+
+ <key-property name="propertyName" type="typename" column="column_name"/>
+ <key-many-to-one name="propertyName class="ClassName" column="column_name"/>
+ ......
+</composite-id>]]></programlisting>
+
+ <para>
+ For a table with a composite key, you may map multiple properties of the class
+ as identifier properties. The <literal><composite-id></literal> element
+ accepts <literal><key-property></literal> property mappings and
+ <literal><key-many-to-one></literal> mappings as child elements.
+ </para>
+
+ <programlisting><![CDATA[<composite-id>
+ <key-property name="medicareNumber"/>
+ <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+ <para>
+ Your persistent class <emphasis>must</emphasis> override <literal>equals()</literal>
+ and <literal>hashCode()</literal> to implement composite identifier equality. It must
+ also implements <literal>Serializable</literal>.
+ </para>
+
+ <para>
+ Unfortunately, this approach to composite identifiers means that a persistent object
+ is its own identifier. There is no convenient "handle" other than the object itself.
+ You must instantiate an instance of the persistent class itself and populate its
+ identifier properties before you can <literal>load()</literal> the persistent state
+ associated with a composite key. We call this approach an <emphasis>embedded</emphasis>
+ composite identifier, and discourage it for serious applications.
+ </para>
+
+ <para>
+ A second approach is what we call a <emphasis>mapped</emphasis> composite identifier,
+ where the identifier properties named inside the <literal><composite-id></literal>
+ element are duplicated on both the persistent class and a separate identifier class.
+ </para>
+
+ <programlisting><![CDATA[<composite-id class="MedicareId" mapped="true">
+ <key-property name="medicareNumber"/>
+ <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+ <para>
+ In this example, both the composite identifier class, <literal>MedicareId</literal>,
+ and the entity class itself have properties named <literal>medicareNumber</literal>
+ and <literal>dependent</literal>. The identifier class must override
+ <literal>equals()</literal> and <literal>hashCode()</literal> and implement.
+ <literal>Serializable</literal>. The disadvantage of this approach is quite
+ obvious—code duplication.
+ </para>
+
+ <para>
+ The following attributes are used to specify a mapped composite identifier:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>mapped</literal> (optional, defaults to <literal>false</literal>):
+ indicates that a mapped composite identifier is used, and that the contained
+ property mappings refer to both the entity class and the composite identifier
+ class.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>class</literal> (optional, but required for a mapped composite identifier):
+ The class used as a composite identifier.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ We will describe a third, even more convenient approach where the composite identifier
+ is implemented as a component class in <xref linkend="components-compositeid"/>. The
+ attributes described below apply only to this alternative approach:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>name</literal> (optional, required for this approach): A property of
+ component type that holds the composite identifier (see chapter 9).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>access</literal> (optional - defaults to <literal>property</literal>):
+ The strategy Hibernate should use for accessing the property value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>class</literal> (optional - defaults to the property type determined by
+ reflection): The component class used as a composite identifier (see next section).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ This third approach, an <emphasis>identifier component</emphasis> is the one we recommend
+ for almost all applications.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-discriminator" revision="3">
+ <title>discriminator</title>
+
+ <para>
+ The <literal><discriminator></literal> element is required for polymorphic persistence
+ using the table-per-class-hierarchy mapping strategy and declares a discriminator column of the
+ table. The discriminator column contains marker values that tell the persistence layer what
+ subclass to instantiate for a particular row. A restricted set of types may be used:
+ <literal>string</literal>, <literal>character</literal>, <literal>integer</literal>,
+ <literal>byte</literal>, <literal>short</literal>, <literal>boolean</literal>,
+ <literal>yes_no</literal>, <literal>true_false</literal>.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="discriminator1" coords="2 60"/>
+ <area id="discriminator2" coords="3 60" />
+ <area id="discriminator3" coords="4 60" />
+ <area id="discriminator4" coords="5 60" />
+ <area id="discriminator5" coords="6 60" />
+ </areaspec>
+ <programlisting><![CDATA[<discriminator
+ column="discriminator_column"
+ type="discriminator_type"
+ force="true|false"
+ insert="true|false"
+ formula="arbitrary sql expression"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="discriminator1">
+ <para>
+ <literal>column</literal> (optional - defaults to <literal>class</literal>) the
+ name of the discriminator column.
+ </para>
+ </callout>
+ <callout arearefs="discriminator2">
+ <para>
+ <literal>type</literal> (optional - defaults to <literal>string</literal>) a
+ name that indicates the Hibernate type
+ </para>
+ </callout>
+ <callout arearefs="discriminator3">
+ <para>
+ <literal>force</literal> (optional - defaults to <literal>false</literal>)
+ "force" Hibernate to specify allowed discriminator values even when retrieving
+ all instances of the root class.
+ </para>
+ </callout>
+ <callout arearefs="discriminator4">
+ <para>
+ <literal>insert</literal> (optional - defaults to <literal>true</literal>)
+ set this to <literal>false</literal> if your discriminator column is also part
+ of a mapped composite identifier. (Tells Hibernate to not include the column
+ in SQL <literal>INSERT</literal>s.)
+ </para>
+ </callout>
+ <callout arearefs="discriminator5">
+ <para>
+ <literal>formula</literal> (optional) an arbitrary SQL expression that is
+ executed when a type has to be evaluated. Allows content-based discrimination.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Actual values of the discriminator column are specified by the
+ <literal>discriminator-value</literal> attribute of the <literal><class></literal> and
+ <literal><subclass></literal> elements.
+ </para>
+
+ <para>
+ The <literal>force</literal> attribute is (only) useful if the table contains rows with
+ "extra" discriminator values that are not mapped to a persistent class. This will not
+ usually be the case.
+ </para>
+
+ <para>
+ Using the <literal>formula</literal> attribute you can declare an arbitrary SQL expression
+ that will be used to evaluate the type of a row:
+ </para>
+
+ <programlisting><![CDATA[<discriminator
+ formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
+ type="integer"/>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-version" revision="4">
+ <title>version (optional)</title>
+
+ <para>
+ The <literal><version></literal> element is optional and indicates that
+ the table contains versioned data. This is particularly useful if you plan to
+ use <emphasis>long transactions</emphasis> (see below).
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="version1" coords="2 70"/>
+ <area id="version2" coords="3 70"/>
+ <area id="version3" coords="4 70"/>
+ <area id="version4" coords="5 70"/>
+ <area id="version5" coords="6 70"/>
+ <area id="version6" coords="7 70"/>
+ <area id="version7" coords="8 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<version
+ column="version_column"
+ name="propertyName"
+ type="typename"
+ access="field|property|ClassName"
+ unsaved-value="null|negative|undefined"
+ generated="never|always"
+ insert="true|false"
+ node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="version1">
+ <para>
+ <literal>column</literal> (optional - defaults to the property name): The name
+ of the column holding the version number.
+ </para>
+ </callout>
+ <callout arearefs="version2">
+ <para>
+ <literal>name</literal>: The name of a property of the persistent class.
+ </para>
+ </callout>
+ <callout arearefs="version3">
+ <para>
+ <literal>type</literal> (optional - defaults to <literal>integer</literal>):
+ The type of the version number.
+ </para>
+ </callout>
+ <callout arearefs="version4">
+ <para>
+ <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+ strategy Hibernate should use for accessing the property value.
+ </para>
+ </callout>
+ <callout arearefs="version5">
+ <para>
+ <literal>unsaved-value</literal> (optional - defaults to <literal>undefined</literal>):
+ A version property value that indicates that an instance is newly instantiated
+ (unsaved), distinguishing it from detached instances that were saved or loaded
+ in a previous session. (<literal>undefined</literal> specifies that the identifier
+ property value should be used.)
+ </para>
+ </callout>
+ <callout arearefs="version6">
+ <para>
+ <literal>generated</literal> (optional - defaults to <literal>never</literal>):
+ Specifies that this version property value is actually generated by the database.
+ See the discussion of <xref linkend="mapping-generated">generated properties</xref>.
+ </para>
+ </callout>
+ <callout arearefs="version7">
+ <para>
+ <literal>insert</literal> (optional - defaults to <literal>true</literal>):
+ Specifies whether the version column should be included in SQL insert statements.
+ May be set to <literal>false</literal> if and only if the database column
+ is defined with a default value of <literal>0</literal>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Version numbers may be of Hibernate type <literal>long</literal>, <literal>integer</literal>,
+ <literal>short</literal>, <literal>timestamp</literal> or <literal>calendar</literal>.
+ </para>
+
+ <para>
+ A version or timestamp property should never be null for a detached instance, so
+ Hibernate will detact any instance with a null version or timestamp as transient,
+ no matter what other <literal>unsaved-value</literal> strategies are specified.
+ <emphasis>Declaring a nullable version or timestamp property is an easy way to avoid
+ any problems with transitive reattachment in Hibernate, especially useful for people
+ using assigned identifiers or composite keys!</emphasis>
+ </para>
+ </sect2>
+
+ <sect2 id="mapping-declaration-timestamp" revision="4" >
+ <title>timestamp (optional)</title>
+
+ <para>
+ The optional <literal><timestamp></literal> element indicates that the table contains
+ timestamped data. This is intended as an alternative to versioning. Timestamps are by nature
+ a less safe implementation of optimistic locking. However, sometimes the application might
+ use the timestamps in other ways.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="timestamp1" coords="2 70"/>
+ <area id="timestamp2" coords="3 70" />
+ <area id="timestamp3" coords="4 70" />
+ <area id="timestamp4" coords="5 70" />
+ <area id="timestamp5" coords="6 70" />
+ <area id="timestamp6" coords="7 70" />
+ </areaspec>
+ <programlisting><![CDATA[<timestamp
+ column="timestamp_column"
+ name="propertyName"
+ access="field|property|ClassName"
+ unsaved-value="null|undefined"
+ source="vm|db"
+ generated="never|always"
+ node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="timestamp1">
+ <para>
+ <literal>column</literal> (optional - defaults to the property name): The name
+ of a column holding the timestamp.
+ </para>
+ </callout>
+ <callout arearefs="timestamp2">
+ <para>
+ <literal>name</literal>: The name of a JavaBeans style property of
+ Java type <literal>Date</literal> or <literal>Timestamp</literal> of the
+ persistent class.
+ </para>
+ </callout>
+ <callout arearefs="timestamp3">
+ <para>
+ <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+ strategy Hibernate should use for accessing the property value.
+ </para>
+ </callout>
+ <callout arearefs="timestamp4">
+ <para>
+ <literal>unsaved-value</literal> (optional - defaults to <literal>null</literal>):
+ A version property value that indicates that an instance is newly instantiated
+ (unsaved), distinguishing it from detached instances that were saved or loaded
+ in a previous session. (<literal>undefined</literal> specifies that the identifier
+ property value should be used.)
+ </para>
+ </callout>
+ <callout arearefs="timestamp5">
+ <para>
+ <literal>source</literal> (optional - defaults to <literal>vm</literal>):
+ From where should Hibernate retrieve the timestamp value? From the database,
+ or from the current JVM? Database-based timestamps incur an overhead because
+ Hibernate must hit the database in order to determine the "next value",
+ but will be safer for use in clustered environments. Note also, that not
+ all <literal>Dialect</literal>s are known to support retrieving of the
+ database's current timestamp, while others might be unsafe for usage
+ in locking due to lack of precision (Oracle 8 for example).
+ </para>
+ </callout>
+ <callout arearefs="timestamp6">
+ <para>
+ <literal>generated</literal> (optional - defaults to <literal>never</literal>):
+ Specifies that this timestamp property value is actually generated by the database.
+ See the discussion of <xref linkend="mapping-generated">generated properties</xref>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Note that <literal><timestamp></literal> is equivalent to
+ <literal><version type="timestamp"></literal>. And
+ <literal><timestamp source="db"></literal> is equivalent to
+ <literal><version type="dbtimestamp"></literal>
+ </para>
+ </sect2>
+
+
+ <sect2 id="mapping-declaration-property" revision="4">
+ <title>property</title>
+
+ <para>
+ The <literal><property></literal> element declares a persistent, JavaBean style
+ property of the class.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="property1" coords="2 70"/>
+ <area id="property2" coords="3 70"/>
+ <area id="property3" coords="4 70"/>
+ <areaset id="property4-5" coords="">
+ <area id="property4" coords='5 70'/>
+ <area id="property5" coords='6 70'/>
+ </areaset>
+ <area id="property6" coords="7 70"/>
+ <area id="property7" coords="8 70"/>
+ <area id="property8" coords="9 70"/>
+ <area id="property9" coords="10 70"/>
+ <area id="property10" coords="11 70"/>
+ <area id="property11" coords="12 70"/>
+ <area id="property12" coords="13 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<property
+ name="propertyName"
+ column="column_name"
+ type="typename"
+ update="true|false"
+ insert="true|false"
+ formula="arbitrary SQL expression"
+ access="field|property|ClassName"
+ lazy="true|false"
+ unique="true|false"
+ not-null="true|false"
+ optimistic-lock="true|false"
+ generated="never|insert|always"
+ node="element-name|@attribute-name|element/@attribute|."
+ index="index_name"
+ unique_key="unique_key_id"
+ length="L"
+ precision="P"
+ scale="S"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="property1">
+ <para>
+ <literal>name</literal>: the name of the property, with an initial lowercase
+ letter.
+ </para>
+ </callout>
+ <callout arearefs="property2">
+ <para>
+ <literal>column</literal> (optional - defaults to the property name): the name
+ of the mapped database table column. This may also be specified by nested
+ <literal><column></literal> element(s).
+ </para>
+ </callout>
+ <callout arearefs="property3">
+ <para>
+ <literal>type</literal> (optional): a name that indicates the Hibernate type.
+ </para>
+ </callout>
+ <callout arearefs="property4-5">
+ <para>
+ <literal>update, insert</literal> (optional - defaults to <literal>true</literal>) :
+ specifies that the mapped columns should be included in SQL <literal>UPDATE</literal>
+ and/or <literal>INSERT</literal> statements. Setting both to <literal>false</literal>
+ allows a pure "derived" property whose value is initialized from some other
+ property that maps to the same colum(s) or by a trigger or other application.
+ </para>
+ </callout>
+ <callout arearefs="property6">
+ <para>
+ <literal>formula</literal> (optional): an SQL expression that defines the value for a
+ <emphasis>computed</emphasis> property. Computed properties do not have a column
+ mapping of their own.
+ </para>
+ </callout>
+ <callout arearefs="property7">
+ <para>
+ <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+ strategy Hibernate should use for accessing the property value.
+ </para>
+ </callout>
+ <callout arearefs="property8">
+ <para>
+ <literal>lazy</literal> (optional - defaults to <literal>false</literal>): Specifies
+ that this property should be fetched lazily when the instance variable is first
+ accessed (requires build-time bytecode instrumentation).
+ </para>
+ </callout>
+ <callout arearefs="property9">
+ <para>
+ <literal>unique</literal> (optional): Enable the DDL generation of a unique
+ constraint for the columns. Also, allow this to be the target of
+ a <literal>property-ref</literal>.
+ </para>
+ </callout>
+ <callout arearefs="property10">
+ <para>
+ <literal>not-null</literal> (optional): Enable the DDL generation of a nullability
+ constraint for the columns.
+ </para>
+ </callout>
+ <callout arearefs="property11">
+ <para>
+ <literal>optimistic-lock</literal> (optional - defaults to <literal>true</literal>):
+ Specifies that updates to this property do or do not require acquisition of the
+ optimistic lock. In other words, determines if a version increment should occur when
+ this property is dirty.
+ </para>
+ </callout>
+ <callout arearefs="property12">
+ <para>
+ <literal>generated</literal> (optional - defaults to <literal>never</literal>):
+ Specifies that this property value is actually generated by the database.
+ See the discussion of <xref linkend="mapping-generated">generated properties</xref>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ <emphasis>typename</emphasis> could be:
+ </para>
+
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ The name of a Hibernate basic type (eg. <literal>integer, string, character,
+ date, timestamp, float, binary, serializable, object, blob</literal>).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The name of a Java class with a default basic type (eg. <literal>int, float,
+ char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob</literal>).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The name of a serializable Java class.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The class name of a custom type (eg. <literal>com.illflow.type.MyCustomType</literal>).
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ If you do not specify a type, Hibernate will use reflection upon the named
+ property to take a guess at the correct Hibernate type. Hibernate will try to
+ interpret the name of the return class of the property getter using rules 2, 3,
+ 4 in that order. However, this is not always enough.
+ In certain cases you will still need the <literal>type</literal>
+ attribute. (For example, to distinguish between <literal>Hibernate.DATE</literal> and
+ <literal>Hibernate.TIMESTAMP</literal>, or to specify a custom type.)
+ </para>
+
+ <para>
+ The <literal>access</literal> attribute lets you control how Hibernate will access
+ the property at runtime. By default, Hibernate will call the property get/set pair.
+ If you specify <literal>access="field"</literal>, Hibernate will bypass the get/set
+ pair and access the field directly, using reflection. You may specify your own
+ strategy for property access by naming a class that implements the interface
+ <literal>org.hibernate.property.PropertyAccessor</literal>.
+ </para>
+
+ <para>
+ An especially powerful feature are derived properties. These properties are by
+ definition read-only, the property value is computed at load time. You declare
+ the computation as a SQL expression, this translates to a <literal>SELECT</literal>
+ clause subquery in the SQL query that loads an instance:
+ </para>
+
+ <programlisting><![CDATA[
+<property name="totalPrice"
+ formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p
+ WHERE li.productId = p.productId
+ AND li.customerId = customerId
+ AND li.orderNumber = orderNumber )"/>]]></programlisting>
+
+ <para>
+ Note that you can reference the entities own table by not declaring an alias on
+ a particular column (<literal>customerId</literal> in the given example). Also note
+ that you can use the nested <literal><formula></literal> mapping element
+ if you don't like to use the attribute.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-manytoone" revision="5">
+ <title>many-to-one</title>
+
+ <para>
+ An ordinary association to another persistent class is declared using a
+ <literal>many-to-one</literal> element. The relational model is a
+ many-to-one association: a foreign key in one table is referencing
+ the primary key column(s) of the target table.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="manytoone1" coords="2 70"/>
+ <area id="manytoone2" coords="3 70"/>
+ <area id="manytoone3" coords="4 70"/>
+ <area id="manytoone4" coords="5 70"/>
+ <area id="manytoone5" coords="6 70"/>
+ <areaset id="manytoone6-7" coords="">
+ <area id="manytoone6" coords='7 70'/>
+ <area id="manytoone7" coords='8 70'/>
+ </areaset>
+ <area id="manytoone8" coords="9 70"/>
+ <area id="manytoone9" coords="10 70"/>
+ <area id="manytoone10" coords="11 70"/>
+ <area id="manytoone11" coords="12 70"/>
+ <area id="manytoone12" coords="13 70"/>
+ <area id="manytoone13" coords="14 70"/>
+ <area id="manytoone14" coords="15 70"/>
+ <area id="manytoone15" coords="16 70"/>
+ <area id="manytoone16" coords="17 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<many-to-one
+ name="propertyName"
+ column="column_name"
+ class="ClassName"
+ cascade="cascade_style"
+ fetch="join|select"
+ update="true|false"
+ insert="true|false"
+ property-ref="propertyNameFromAssociatedClass"
+ access="field|property|ClassName"
+ unique="true|false"
+ not-null="true|false"
+ optimistic-lock="true|false"
+ lazy="proxy|no-proxy|false"
+ not-found="ignore|exception"
+ entity-name="EntityName"
+ formula="arbitrary SQL expression"
+ node="element-name|@attribute-name|element/@attribute|."
+ embed-xml="true|false"
+ index="index_name"
+ unique_key="unique_key_id"
+ foreign-key="foreign_key_name"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="manytoone1">
+ <para>
+ <literal>name</literal>: The name of the property.
+ </para>
+ </callout>
+ <callout arearefs="manytoone2">
+ <para>
+ <literal>column</literal> (optional): The name of the foreign key column.
+ This may also be specified by nested <literal><column></literal>
+ element(s).
+ </para>
+ </callout>
+ <callout arearefs="manytoone3">
+ <para>
+ <literal>class</literal> (optional - defaults to the property type
+ determined by reflection): The name of the associated class.
+ </para>
+ </callout>
+ <callout arearefs="manytoone4">
+ <para>
+ <literal>cascade</literal> (optional): Specifies which operations should
+ be cascaded from the parent object to the associated object.
+ </para>
+ </callout>
+ <callout arearefs="manytoone5">
+ <para>
+ <literal>fetch</literal> (optional - defaults to <literal>select</literal>):
+ Chooses between outer-join fetching or sequential select fetching.
+ </para>
+ </callout>
+ <callout arearefs="manytoone6-7">
+ <para>
+ <literal>update, insert</literal> (optional - defaults to <literal>true</literal>)
+ specifies that the mapped columns should be included in SQL <literal>UPDATE</literal>
+ and/or <literal>INSERT</literal> statements. Setting both to <literal>false</literal>
+ allows a pure "derived" association whose value is initialized from some other
+ property that maps to the same colum(s) or by a trigger or other application.
+ </para>
+ </callout>
+ <callout arearefs="manytoone8">
+ <para>
+ <literal>property-ref</literal>: (optional) The name of a property of the associated
+ class that is joined to this foreign key. If not specified, the primary key of
+ the associated class is used.
+ </para>
+ </callout>
+ <callout arearefs="manytoone9">
+ <para>
+ <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+ strategy Hibernate should use for accessing the property value.
+ </para>
+ </callout>
+ <callout arearefs="manytoone10">
+ <para>
+ <literal>unique</literal> (optional): Enable the DDL generation of a unique
+ constraint for the foreign-key column. Also, allow this to be the target of
+ a <literal>property-ref</literal>. This makes the association multiplicity
+ effectively one to one.
+ </para>
+ </callout>
+ <callout arearefs="manytoone11">
+ <para>
+ <literal>not-null</literal> (optional): Enable the DDL generation of a nullability
+ constraint for the foreign key columns.
+ </para>
+ </callout>
+ <callout arearefs="manytoone12">
+ <para>
+ <literal>optimistic-lock</literal> (optional - defaults to <literal>true</literal>):
+ Specifies that updates to this property do or do not require acquisition of the
+ optimistic lock. In other words, dertermines if a version increment should occur when
+ this property is dirty.
+ </para>
+ </callout>
+ <callout arearefs="manytoone13">
+ <para>
+ <literal>lazy</literal> (optional - defaults to <literal>proxy</literal>):
+ By default, single point associations are proxied. <literal>lazy="no-proxy"</literal>
+ specifies that the property should be fetched lazily when the instance variable
+ is first accessed (requires build-time bytecode instrumentation).
+ <literal>lazy="false"</literal> specifies that the association will always
+ be eagerly fetched.
+ </para>
+ </callout>
+ <callout arearefs="manytoone14">
+ <para>
+ <literal>not-found</literal> (optional - defaults to <literal>exception</literal>):
+ Specifies how foreign keys that reference missing rows will be handled:
+ <literal>ignore</literal> will treat a missing row as a null association.
+ </para>
+ </callout>
+ <callout arearefs="manytoone15">
+ <para>
+ <literal>entity-name</literal> (optional): The entity name of the associated class.
+ </para>
+ </callout>
+ </calloutlist>
+ <callout arearefs="manytoone16">
+ <para>
+ <literal>formula</literal> (optional): an SQL expression that defines the value for a
+ <emphasis>computed</emphasis> foreign key.
+ </para>
+ </callout>
+ </programlistingco>
+
+ <para>
+ Setting a value of the <literal>cascade</literal> attribute to any meaningful
+ value other than <literal>none</literal> will propagate certain operations to the
+ associated object. The meaningful values are the names of Hibernate's basic
+ operations, <literal>persist, merge, delete, save-update, evict, replicate, lock,
+ refresh</literal>, as well as the special values <literal>delete-orphan</literal>
+ and <literal>all</literal> and comma-separated combinations of operation
+ names, for example, <literal>cascade="persist,merge,evict"</literal> or
+ <literal>cascade="all,delete-orphan"</literal>. See <xref linkend="objectstate-transitive"/>
+ for a full explanation. Note that single valued associations (many-to-one and
+ one-to-one associations) do not support orphan delete.
+ </para>
+
+ <para>
+ A typical <literal>many-to-one</literal> declaration looks as simple as this:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="product" class="Product" column="PRODUCT_ID"/>]]></programlisting>
+
+ <para>
+ The <literal>property-ref</literal> attribute should only be used for mapping legacy
+ data where a foreign key refers to a unique key of the associated table other than
+ the primary key. This is an ugly relational model. For example, suppose the
+ <literal>Product</literal> class had a unique serial number, that is not the primary
+ key. (The <literal>unique</literal> attribute controls Hibernate's DDL generation with
+ the SchemaExport tool.)
+ </para>
+
+ <programlisting><![CDATA[<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>]]></programlisting>
+
+ <para>
+ Then the mapping for <literal>OrderItem</literal> might use:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>]]></programlisting>
+
+ <para>
+ This is certainly not encouraged, however.
+ </para>
+
+ <para>
+ If the referenced unique key comprises multiple properties of the associated entity, you should
+ map the referenced properties inside a named <literal><properties></literal> element.
+ </para>
+
+ <para>
+ If the referenced unique key is the property of a component, you may specify a property path:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="owner" property-ref="identity.ssn" column="OWNER_SSN"/>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-onetoone" revision="3">
+ <title>one-to-one</title>
+
+ <para>
+ A one-to-one association to another persistent class is declared using a
+ <literal>one-to-one</literal> element.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="onetoone1" coords="2 70"/>
+ <area id="onetoone2" coords="3 70"/>
+ <area id="onetoone3" coords="4 70"/>
+ <area id="onetoone4" coords="5 70"/>
+ <area id="onetoone5" coords="6 70"/>
+ <area id="onetoone6" coords="7 70"/>
+ <area id="onetoone7" coords="8 70"/>
+ <area id="onetoone8" coords="9 70"/>
+ <area id="onetoone9" coords="10 70"/>
+ <area id="onetoone10" coords="11 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<one-to-one
+ name="propertyName"
+ class="ClassName"
+ cascade="cascade_style"
+ constrained="true|false"
+ fetch="join|select"
+ property-ref="propertyNameFromAssociatedClass"
+ access="field|property|ClassName"
+ formula="any SQL expression"
+ lazy="proxy|no-proxy|false"
+ entity-name="EntityName"
+ node="element-name|@attribute-name|element/@attribute|."
+ embed-xml="true|false"
+ foreign-key="foreign_key_name"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="onetoone1">
+ <para>
+ <literal>name</literal>: The name of the property.
+ </para>
+ </callout>
+ <callout arearefs="onetoone2">
+ <para>
+ <literal>class</literal> (optional - defaults to the property type
+ determined by reflection): The name of the associated class.
+ </para>
+ </callout>
+ <callout arearefs="onetoone3">
+ <para>
+ <literal>cascade</literal> (optional) specifies which operations should
+ be cascaded from the parent object to the associated object.
+ </para>
+ </callout>
+ <callout arearefs="onetoone4">
+ <para>
+ <literal>constrained</literal> (optional) specifies that a foreign key constraint
+ on the primary key of the mapped table references the table of the associated
+ class. This option affects the order in which <literal>save()</literal> and
+ <literal>delete()</literal> are cascaded, and determines whether the association
+ may be proxied (it is also used by the schema export tool).
+ </para>
+ </callout>
+ <callout arearefs="onetoone5">
+ <para>
+ <literal>fetch</literal> (optional - defaults to <literal>select</literal>):
+ Chooses between outer-join fetching or sequential select fetching.
+ </para>
+ </callout>
+ <callout arearefs="onetoone6">
+ <para>
+ <literal>property-ref</literal>: (optional) The name of a property of the associated class
+ that is joined to the primary key of this class. If not specified, the primary key of
+ the associated class is used.
+ </para>
+ </callout>
+ <callout arearefs="onetoone7">
+ <para>
+ <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+ strategy Hibernate should use for accessing the property value.
+ </para>
+ </callout>
+ <callout arearefs="onetoone8">
+ <para>
+ <literal>formula</literal> (optional): Almost all one to one associations map to the
+ primary key of the owning entity. In the rare case that this is not the case, you may
+ specify a some other column, columns or expression to join on using an SQL formula. (See
+ <literal>org.hibernate.test.onetooneformula</literal> for an example.)
+ </para>
+ </callout>
+ <callout arearefs="onetoone9">
+ <para>
+ <literal>lazy</literal> (optional - defaults to <literal>proxy</literal>):
+ By default, single point associations are proxied. <literal>lazy="no-proxy"</literal>
+ specifies that the property should be fetched lazily when the instance variable
+ is first accessed (requires build-time bytecode instrumentation).
+ <literal>lazy="false"</literal> specifies that the association will always
+ be eagerly fetched. <emphasis>Note that if <literal>constrained="false"</literal>,
+ proxying is impossible and Hibernate will eager fetch the association!</emphasis>
+ </para>
+ </callout>
+ <callout arearefs="onetoone10">
+ <para>
+ <literal>entity-name</literal> (optional): The entity name of the associated class.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ There are two varieties of one-to-one association:
+ </para>
+ <itemizedlist>
+ <listitem><para>
+ primary key associations
+ </para></listitem>
+ <listitem><para>
+ unique foreign key associations
+ </para></listitem>
+ </itemizedlist>
+
+ <para>
+ Primary key associations don't need an extra table column; if two rows are related by
+ the association then the two table rows share the same primary key value. So if you want
+ two objects to be related by a primary key association, you must make sure that they
+ are assigned the same identifier value!
+ </para>
+
+ <para>
+ For a primary key association, add the following mappings to <literal>Employee</literal> and
+ <literal>Person</literal>, respectively.
+ </para>
+
+ <programlisting><![CDATA[<one-to-one name="person" class="Person"/>]]></programlisting>
+ <programlisting><![CDATA[<one-to-one name="employee" class="Employee" constrained="true"/>]]></programlisting>
+
+ <para>
+ Now we must ensure that the primary keys of related rows in the PERSON and
+ EMPLOYEE tables are equal. We use a special Hibernate identifier generation strategy
+ called <literal>foreign</literal>:
+ </para>
+
+ <programlisting><![CDATA[<class name="person" table="PERSON">
+ <id name="id" column="PERSON_ID">
+ <generator class="foreign">
+ <param name="property">employee</param>
+ </generator>
+ </id>
+ ...
+ <one-to-one name="employee"
+ class="Employee"
+ constrained="true"/>
+</class>]]></programlisting>
+
+ <para>
+ A newly saved instance of <literal>Person</literal> is then assigned the same primary
+ key value as the <literal>Employee</literal> instance refered with the <literal>employee</literal>
+ property of that <literal>Person</literal>.
+ </para>
+
+ <para>
+ Alternatively, a foreign key with a unique constraint, from <literal>Employee</literal> to
+ <literal>Person</literal>, may be expressed as:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/>]]></programlisting>
+
+ <para>
+ And this association may be made bidirectional by adding the following to the
+ <literal>Person</literal> mapping:
+ </para>
+
+ <programlisting><![CDATA[<one-to-one name"employee" class="Employee" property-ref="person"/>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-naturalid">
+ <title>natural-id</title>
+
+ <programlisting><![CDATA[<natural-id mutable="true|false"/>
+ <property ... />
+ <many-to-one ... />
+ ......
+</natural-id>]]></programlisting>
+
+ <para>
+ Even though we recommend the use of surrogate keys as primary keys, you should still try
+ to identify natural keys for all entities. A natural key is a property or combination of
+ properties that is unique and non-null. If it is also immutable, even better. Map the
+ properties of the natural key inside the <literal><natural-id></literal> element.
+ Hibernate will generate the necessary unique key and nullability constraints, and your
+ mapping will be more self-documenting.
+ </para>
+
+ <para>
+ We strongly recommend that you implement <literal>equals()</literal> and
+ <literal>hashCode()</literal> to compare the natural key properties of the entity.
+ </para>
+
+ <para>
+ This mapping is not intended for use with entities with natural primary keys.
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>mutable</literal> (optional, defaults to <literal>false</literal>):
+ By default, natural identifier properties as assumed to be immutable (constant).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-component" revision="2">
+ <title>component, dynamic-component</title>
+
+ <para>
+ The <literal><component></literal> element maps properties of a
+ child object to columns of the table of a parent class. Components may, in
+ turn, declare their own properties, components or collections. See
+ "Components" below.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="component1" coords="2 45"/>
+ <area id="component2" coords="3 45"/>
+ <area id="component3" coords="4 45"/>
+ <area id="component4" coords="5 45"/>
+ <area id="component5" coords="6 45"/>
+ <area id="component6" coords="7 45"/>
+ <area id="component7" coords="8 45"/>
+ <area id="component8" coords="9 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<component
+ name="propertyName"
+ class="className"
+ insert="true|false"
+ update="true|false"
+ access="field|property|ClassName"
+ lazy="true|false"
+ optimistic-lock="true|false"
+ unique="true|false"
+ node="element-name|."
+>
+
+ <property ...../>
+ <many-to-one .... />
+ ........
+</component>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="component1">
+ <para>
+ <literal>name</literal>: The name of the property.
+ </para>
+ </callout>
+ <callout arearefs="component2">
+ <para>
+ <literal>class</literal> (optional - defaults to the property type
+ determined by reflection): The name of the component (child) class.
+ </para>
+ </callout>
+ <callout arearefs="component3">
+ <para>
+ <literal>insert</literal>: Do the mapped columns appear in SQL
+ <literal>INSERT</literal>s?
+ </para>
+ </callout>
+ <callout arearefs="component4">
+ <para>
+ <literal>update</literal>: Do the mapped columns appear in SQL
+ <literal>UPDATE</literal>s?
+ </para>
+ </callout>
+ <callout arearefs="component5">
+ <para>
+ <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+ strategy Hibernate should use for accessing the property value.
+ </para>
+ </callout>
+ <callout arearefs="component6">
+ <para>
+ <literal>lazy</literal> (optional - defaults to <literal>false</literal>): Specifies
+ that this component should be fetched lazily when the instance variable is first
+ accessed (requires build-time bytecode instrumentation).
+ </para>
+ </callout>
+ <callout arearefs="component7">
+ <para>
+ <literal>optimistic-lock</literal> (optional - defaults to <literal>true</literal>):
+ Specifies that updates to this component do or do not require acquisition of the
+ optimistic lock. In other words, determines if a version increment should occur when
+ this property is dirty.
+ </para>
+ </callout>
+ <callout arearefs="component8">
+ <para>
+ <literal>unique</literal> (optional - defaults to <literal>false</literal>):
+ Specifies that a unique constraint exists upon all mapped columns of the
+ component.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ The child <literal><property></literal> tags map properties of the
+ child class to table columns.
+ </para>
+
+ <para>
+ The <literal><component></literal> element allows a <literal><parent></literal>
+ subelement that maps a property of the component class as a reference back to the
+ containing entity.
+ </para>
+
+ <para>
+ The <literal><dynamic-component></literal> element allows a <literal>Map</literal>
+ to be mapped as a component, where the property names refer to keys of the map, see
+ <xref linkend="components-dynamic"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-properties" revision="2">
+ <title>properties</title>
+
+ <para>
+ The <literal><properties></literal> element allows the definition of a named,
+ logical grouping of properties of a class. The most important use of the construct
+ is that it allows a combination of properties to be the target of a
+ <literal>property-ref</literal>. It is also a convenient way to define a multi-column
+ unique constraint.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="properties1" coords="2 45"/>
+ <area id="properties2" coords="3 45"/>
+ <area id="properties3" coords="4 45"/>
+ <area id="properties4" coords="5 45"/>
+ <area id="properties5" coords="6 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<properties
+ name="logicalName"
+ insert="true|false"
+ update="true|false"
+ optimistic-lock="true|false"
+ unique="true|false"
+>
+
+ <property ...../>
+ <many-to-one .... />
+ ........
+</properties>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="properties1">
+ <para>
+ <literal>name</literal>: The logical name of the grouping -
+ <emphasis>not</emphasis> an actual property name.
+ </para>
+ </callout>
+ <callout arearefs="properties2">
+ <para>
+ <literal>insert</literal>: Do the mapped columns appear in SQL
+ <literal>INSERT</literal>s?
+ </para>
+ </callout>
+ <callout arearefs="properties3">
+ <para>
+ <literal>update</literal>: Do the mapped columns appear in SQL
+ <literal>UPDATE</literal>s?
+ </para>
+ </callout>
+ <callout arearefs="properties4">
+ <para>
+ <literal>optimistic-lock</literal> (optional - defaults to <literal>true</literal>):
+ Specifies that updates to these properties do or do not require acquisition of the
+ optimistic lock. In other words, determines if a version increment should occur when
+ these properties are dirty.
+ </para>
+ </callout>
+ <callout arearefs="properties5">
+ <para>
+ <literal>unique</literal> (optional - defaults to <literal>false</literal>):
+ Specifies that a unique constraint exists upon all mapped columns of the
+ component.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ For example, if we have the following <literal><properties></literal> mapping:
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="personNumber"/>
+ ...
+ <properties name="name"
+ unique="true" update="false">
+ <property name="firstName"/>
+ <property name="initial"/>
+ <property name="lastName"/>
+ </properties>
+</class>]]></programlisting>
+
+ <para>
+ Then we might have some legacy data association which refers to this unique key of
+ the <literal>Person</literal> table, instead of to the primary key:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="person"
+ class="Person" property-ref="name">
+ <column name="firstName"/>
+ <column name="initial"/>
+ <column name="lastName"/>
+</many-to-one>]]></programlisting>
+
+ <para>
+ We don't recommend the use of this kind of thing outside the context of mapping
+ legacy data.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-subclass" revision="4">
+ <title>subclass</title>
+
+ <para>
+ Finally, polymorphic persistence requires the declaration of each subclass of
+ the root persistent class. For the table-per-class-hierarchy
+ mapping strategy, the <literal><subclass></literal> declaration is used.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="subclass1" coords="2 55"/>
+ <area id="subclass2" coords="3 55"/>
+ <area id="subclass3" coords="4 55"/>
+ <area id="subclass4" coords="5 55"/>
+ </areaspec>
+ <programlisting><![CDATA[<subclass
+ name="ClassName"
+ discriminator-value="discriminator_value"
+ proxy="ProxyInterface"
+ lazy="true|false"
+ dynamic-update="true|false"
+ dynamic-insert="true|false"
+ entity-name="EntityName"
+ node="element-name"
+ extends="SuperclassName">
+
+ <property .... />
+ .....
+</subclass>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="subclass1">
+ <para>
+ <literal>name</literal>: The fully qualified class name of the subclass.
+ </para>
+ </callout>
+ <callout arearefs="subclass2">
+ <para>
+ <literal>discriminator-value</literal> (optional - defaults to the class name): A
+ value that distiguishes individual subclasses.
+ </para>
+ </callout>
+ <callout arearefs="subclass3">
+ <para>
+ <literal>proxy</literal> (optional): Specifies a class or interface to use for
+ lazy initializing proxies.
+ </para>
+ </callout>
+ <callout arearefs="subclass4">
+ <para>
+ <literal>lazy</literal> (optional, defaults to <literal>true</literal>): Setting
+ <literal>lazy="false"</literal> disables the use of lazy fetching.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Each subclass should declare its own persistent properties and subclasses.
+ <literal><version></literal> and <literal><id></literal> properties
+ are assumed to be inherited from the root class. Each subclass in a heirarchy must
+ define a unique <literal>discriminator-value</literal>. If none is specified, the
+ fully qualified Java class name is used.
+ </para>
+
+ <para>
+ For information about inheritance mappings, see <xref linkend="inheritance"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-joinedsubclass" revision="3">
+ <title>joined-subclass</title>
+
+ <para>
+ Alternatively, each subclass may be mapped to its own table (table-per-subclass
+ mapping strategy). Inherited state is retrieved by joining with the table of the
+ superclass. We use the <literal><joined-subclass></literal> element.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="joinedsubclass1" coords="2 45"/>
+ <area id="joinedsubclass2" coords="3 45"/>
+ <area id="joinedsubclass3" coords="4 45"/>
+ <area id="joinedsubclass4" coords="5 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<joined-subclass
+ name="ClassName"
+ table="tablename"
+ proxy="ProxyInterface"
+ lazy="true|false"
+ dynamic-update="true|false"
+ dynamic-insert="true|false"
+ schema="schema"
+ catalog="catalog"
+ extends="SuperclassName"
+ persister="ClassName"
+ subselect="SQL expression"
+ entity-name="EntityName"
+ node="element-name">
+
+ <key .... >
+
+ <property .... />
+ .....
+</joined-subclass>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="joinedsubclass1">
+ <para>
+ <literal>name</literal>: The fully qualified class name of the subclass.
+ </para>
+ </callout>
+ <callout arearefs="joinedsubclass2">
+ <para>
+ <literal>table</literal>: The name of the subclass table.
+ </para>
+ </callout>
+ <callout arearefs="joinedsubclass3">
+ <para>
+ <literal>proxy</literal> (optional): Specifies a class or interface to use
+ for lazy initializing proxies.
+ </para>
+ </callout>
+ <callout arearefs="joinedsubclass4">
+ <para>
+ <literal>lazy</literal> (optional, defaults to <literal>true</literal>): Setting
+ <literal>lazy="false"</literal> disables the use of lazy fetching.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ No discriminator column is required for this mapping strategy. Each subclass must,
+ however, declare a table column holding the object identifier using the
+ <literal><key></literal> element. The mapping at the start of the chapter
+ would be re-written as:
+ </para>
+
+ <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+ <class name="Cat" table="CATS">
+ <id name="id" column="uid" type="long">
+ <generator class="hilo"/>
+ </id>
+ <property name="birthdate" type="date"/>
+ <property name="color" not-null="true"/>
+ <property name="sex" not-null="true"/>
+ <property name="weight"/>
+ <many-to-one name="mate"/>
+ <set name="kittens">
+ <key column="MOTHER"/>
+ <one-to-many class="Cat"/>
+ </set>
+ <joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
+ <key column="CAT"/>
+ <property name="name" type="string"/>
+ </joined-subclass>
+ </class>
+
+ <class name="eg.Dog">
+ <!-- mapping for Dog could go here -->
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ For information about inheritance mappings, see <xref linkend="inheritance"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-unionsubclass" revision="2">
+ <title>union-subclass</title>
+
+ <para>
+ A third option is to map only the concrete classes of an inheritance hierarchy
+ to tables, (the table-per-concrete-class strategy) where each table defines all
+ persistent state of the class, including inherited state. In Hibernate, it is
+ not absolutely necessary to explicitly map such inheritance hierarchies. You
+ can simply map each class with a separate <literal><class></literal>
+ declaration. However, if you wish use polymorphic associations (e.g. an association
+ to the superclass of your hierarchy), you need to
+ use the <literal><union-subclass></literal> mapping.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="unionsubclass1" coords="2 45"/>
+ <area id="unionsubclass2" coords="3 45"/>
+ <area id="unionsubclass3" coords="4 45"/>
+ <area id="unionsubclass4" coords="5 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<union-subclass
+ name="ClassName"
+ table="tablename"
+ proxy="ProxyInterface"
+ lazy="true|false"
+ dynamic-update="true|false"
+ dynamic-insert="true|false"
+ schema="schema"
+ catalog="catalog"
+ extends="SuperclassName"
+ abstract="true|false"
+ persister="ClassName"
+ subselect="SQL expression"
+ entity-name="EntityName"
+ node="element-name">
+
+ <property .... />
+ .....
+</union-subclass>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="unionsubclass1">
+ <para>
+ <literal>name</literal>: The fully qualified class name of the subclass.
+ </para>
+ </callout>
+ <callout arearefs="unionsubclass2">
+ <para>
+ <literal>table</literal>: The name of the subclass table.
+ </para>
+ </callout>
+ <callout arearefs="unionsubclass3">
+ <para>
+ <literal>proxy</literal> (optional): Specifies a class or interface to use
+ for lazy initializing proxies.
+ </para>
+ </callout>
+ <callout arearefs="unionsubclass4">
+ <para>
+ <literal>lazy</literal> (optional, defaults to <literal>true</literal>): Setting
+ <literal>lazy="false"</literal> disables the use of lazy fetching.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ No discriminator column or key column is required for this mapping strategy.
+ </para>
+
+ <para>
+ For information about inheritance mappings, see <xref linkend="inheritance"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-join" revision="3">
+ <title>join</title>
+
+ <para>
+ Using the <literal><join></literal> element, it is possible to map
+ properties of one class to several tables, when there's a 1-to-1 relationship between the tables.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="join1" coords="2 50"/>
+ <area id="join2" coords="3 50"/>
+ <area id="join3" coords="4 50"/>
+ <area id="join4" coords="5 50"/>
+ <area id="join5" coords="6 50"/>
+ <area id="join6" coords="7 50"/>
+ </areaspec>
+ <programlisting><![CDATA[<join
+ table="tablename"
+ schema="owner"
+ catalog="catalog"
+ fetch="join|select"
+ inverse="true|false"
+ optional="true|false">
+
+ <key ... />
+
+ <property ... />
+ ...
+</join>]]></programlisting>
+
+ <calloutlist>
+ <callout arearefs="join1">
+ <para>
+ <literal>table</literal>: The name of the joined table.
+ </para>
+ </callout>
+ <callout arearefs="join2">
+ <para>
+ <literal>schema</literal> (optional): Override the schema name specified by
+ the root <literal><hibernate-mapping></literal> element.
+ </para>
+ </callout>
+ <callout arearefs="join3">
+ <para>
+ <literal>catalog</literal> (optional): Override the catalog name specified by
+ the root <literal><hibernate-mapping></literal> element.
+ </para>
+ </callout>
+ <callout arearefs="join4">
+ <para>
+ <literal>fetch</literal> (optional - defaults to <literal>join</literal>):
+ If set to <literal>join</literal>, the default, Hibernate will use an inner join
+ to retrieve a <literal><join></literal> defined by a class or its superclasses
+ and an outer join for a <literal><join></literal> defined by a subclass.
+ If set to <literal>select</literal> then Hibernate will use a sequential select for
+ a <literal><join></literal> defined on a subclass, which will be issued only
+ if a row turns out to represent an instance of the subclass. Inner joins will still
+ be used to retrieve a <literal><join></literal> defined by the class and its
+ superclasses.
+ </para>
+ </callout>
+ <callout arearefs="join5">
+ <para>
+ <literal>inverse</literal> (optional - defaults to <literal>false</literal>):
+ If enabled, Hibernate will not try to insert or update the properties defined
+ by this join.
+ </para>
+ </callout>
+ <callout arearefs="join6">
+ <para>
+ <literal>optional</literal> (optional - defaults to <literal>false</literal>):
+ If enabled, Hibernate will insert a row only if the properties defined by this
+ join are non-null and will always use an outer join to retrieve the properties.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ For example, the address information for a person can be mapped to a separate
+ table (while preserving value type semantics for all properties):
+ </para>
+
+ <programlisting><![CDATA[<class name="Person"
+ table="PERSON">
+
+ <id name="id" column="PERSON_ID">...</id>
+
+ <join table="ADDRESS">
+ <key column="ADDRESS_ID"/>
+ <property name="address"/>
+ <property name="zip"/>
+ <property name="country"/>
+ </join>
+ ...]]></programlisting>
+
+ <para>
+ This feature is often only useful for legacy data models, we recommend fewer
+ tables than classes and a fine-grained domain model. However, it is useful
+ for switching between inheritance mapping strategies in a single hierarchy, as
+ explained later.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-key">
+ <title>key</title>
+
+ <para>
+ We've seen the <literal><key></literal> element crop up a few times
+ now. It appears anywhere the parent mapping element defines a join to
+ a new table, and defines the foreign key in the joined table, that references
+ the primary key of the original table.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="key1" coords="2 50"/>
+ <area id="key2" coords="3 50"/>
+ <area id="key3" coords="4 50"/>
+ <area id="key4" coords="5 50"/>
+ <area id="key5" coords="6 50"/>
+ <area id="key6" coords="7 50"/>
+ </areaspec>
+ <programlisting><![CDATA[<key
+ column="columnname"
+ on-delete="noaction|cascade"
+ property-ref="propertyName"
+ not-null="true|false"
+ update="true|false"
+ unique="true|false"
+/>]]></programlisting>
+
+ <calloutlist>
+ <callout arearefs="key1">
+ <para>
+ <literal>column</literal> (optional): The name of the foreign key column.
+ This may also be specified by nested <literal><column></literal>
+ element(s).
+ </para>
+ </callout>
+ <callout arearefs="key2">
+ <para>
+ <literal>on-delete</literal> (optional, defaults to <literal>noaction</literal>):
+ Specifies whether the foreign key constraint has database-level cascade delete
+ enabled.
+ </para>
+ </callout>
+ <callout arearefs="key3">
+ <para>
+ <literal>property-ref</literal> (optional): Specifies that the foreign key refers
+ to columns that are not the primary key of the orginal table. (Provided for
+ legacy data.)
+ </para>
+ </callout>
+ <callout arearefs="key4">
+ <para>
+ <literal>not-null</literal> (optional): Specifies that the foreign key columns
+ are not nullable (this is implied whenever the foreign key is also part of the
+ primary key).
+ </para>
+ </callout>
+ <callout arearefs="key5">
+ <para>
+ <literal>update</literal> (optional): Specifies that the foreign key should never
+ be updated (this is implied whenever the foreign key is also part of the primary
+ key).
+ </para>
+ </callout>
+ <callout arearefs="key6">
+ <para>
+ <literal>unique</literal> (optional): Specifies that the foreign key should have
+ a unique constraint (this is implied whenever the foreign key is also the primary key).
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ We recommend that for systems where delete performance is important, all keys should be
+ defined <literal>on-delete="cascade"</literal>, and Hibernate will use a database-level
+ <literal>ON CASCADE DELETE</literal> constraint, instead of many individual
+ <literal>DELETE</literal> statements. Be aware that this feature bypasses Hibernate's
+ usual optimistic locking strategy for versioned data.
+ </para>
+
+ <para>
+ The <literal>not-null</literal> and <literal>update</literal> attributes are useful when
+ mapping a unidirectional one to many association. If you map a unidirectional one to many
+ to a non-nullable foreign key, you <emphasis>must</emphasis> declare the key column using
+ <literal><key not-null="true"></literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-column" revision="4">
+ <title>column and formula elements</title>
+ <para>
+ Any mapping element which accepts a <literal>column</literal> attribute will alternatively
+ accept a <literal><column></literal> subelement. Likewise, <literal><formula></literal>
+ is an alternative to the <literal>formula</literal> attribute.
+ </para>
+
+ <programlisting><![CDATA[<column
+ name="column_name"
+ length="N"
+ precision="N"
+ scale="N"
+ not-null="true|false"
+ unique="true|false"
+ unique-key="multicolumn_unique_key_name"
+ index="index_name"
+ sql-type="sql_type_name"
+ check="SQL expression"
+ default="SQL expression"/>]]></programlisting>
+
+ <programlisting><![CDATA[<formula>SQL expression</formula>]]></programlisting>
+
+ <para>
+ <literal>column</literal> and <literal>formula</literal> attributes may even be combined
+ within the same property or association mapping to express, for example, exotic join
+ conditions.
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="homeAddress" class="Address"
+ insert="false" update="false">
+ <column name="person_id" not-null="true" length="10"/>
+ <formula>'MAILING'</formula>
+</many-to-one>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-import">
+ <title>import</title>
+
+ <para>
+ Suppose your application has two persistent classes with the same name, and you don't want to
+ specify the fully qualified (package) name in Hibernate queries. Classes may be "imported"
+ explicitly, rather than relying upon <literal>auto-import="true"</literal>. You may even import
+ classes and interfaces that are not explicitly mapped.
+ </para>
+
+ <programlisting><![CDATA[<import class="java.lang.Object" rename="Universe"/>]]></programlisting>
+
+ <programlistingco>
+ <areaspec>
+ <area id="import1" coords="2 40"/>
+ <area id="import2" coords="3 40"/>
+ </areaspec>
+ <programlisting><![CDATA[<import
+ class="ClassName"
+ rename="ShortName"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="import1">
+ <para>
+ <literal>class</literal>: The fully qualified class name of of any Java class.
+ </para>
+ </callout>
+ <callout arearefs="import2">
+ <para>
+ <literal>rename</literal> (optional - defaults to the unqualified class name):
+ A name that may be used in the query language.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ </sect2>
+
+ <sect2 id="mapping-types-anymapping" revision="2">
+ <title>any</title>
+
+ <para>
+ There is one further type of property mapping. The <literal><any></literal> mapping element
+ defines a polymorphic association to classes from multiple tables. This type of mapping always
+ requires more than one column. The first column holds the type of the associated entity.
+ The remaining columns hold the identifier. It is impossible to specify a foreign key constraint
+ for this kind of association, so this is most certainly not meant as the usual way of mapping
+ (polymorphic) associations. You should use this only in very special cases (eg. audit logs,
+ user session data, etc).
+ </para>
+
+ <para>
+ The <literal>meta-type</literal> attribute lets the application specify a custom type that
+ maps database column values to persistent classes which have identifier properties of the
+ type specified by <literal>id-type</literal>. You must specify the mapping from values of
+ the meta-type to class names.
+ </para>
+
+ <programlisting><![CDATA[<any name="being" id-type="long" meta-type="string">
+ <meta-value value="TBL_ANIMAL" class="Animal"/>
+ <meta-value value="TBL_HUMAN" class="Human"/>
+ <meta-value value="TBL_ALIEN" class="Alien"/>
+ <column name="table_name"/>
+ <column name="id"/>
+</any>]]></programlisting>
+
+ <programlistingco>
+ <areaspec>
+ <area id="any1" coords="2 50"/>
+ <area id="any2" coords="3 50"/>
+ <area id="any3" coords="4 50"/>
+ <area id="any4" coords="5 50"/>
+ <area id="any5" coords="6 50"/>
+ <area id="any6" coords="7 50"/>
+ </areaspec>
+ <programlisting><![CDATA[<any
+ name="propertyName"
+ id-type="idtypename"
+ meta-type="metatypename"
+ cascade="cascade_style"
+ access="field|property|ClassName"
+ optimistic-lock="true|false"
+>
+ <meta-value ... />
+ <meta-value ... />
+ .....
+ <column .... />
+ <column .... />
+ .....
+</any>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="any1">
+ <para>
+ <literal>name</literal>: the property name.
+ </para>
+ </callout>
+ <callout arearefs="any2">
+ <para>
+ <literal>id-type</literal>: the identifier type.
+ </para>
+ </callout>
+ <callout arearefs="any3">
+ <para>
+ <literal>meta-type</literal> (optional - defaults to <literal>string</literal>):
+ Any type that is allowed for a discriminator mapping.
+ </para>
+ </callout>
+ <callout arearefs="any4">
+ <para>
+ <literal>cascade</literal> (optional- defaults to <literal>none</literal>):
+ the cascade style.
+ </para>
+ </callout>
+ <callout arearefs="any5">
+ <para>
+ <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+ strategy Hibernate should use for accessing the property value.
+ </para>
+ </callout>
+ <callout arearefs="any6">
+ <para>
+ <literal>optimistic-lock</literal> (optional - defaults to <literal>true</literal>):
+ Specifies that updates to this property do or do not require acquisition of the
+ optimistic lock. In other words, define if a version increment should occur if this
+ property is dirty.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="mapping-types">
+ <title>Hibernate Types</title>
+
+ <sect2 id="mapping-types-entitiesvalues" revision="1">
+ <title>Entities and values</title>
+
+ <para>
+ To understand the behaviour of various Java language-level objects with respect
+ to the persistence service, we need to classify them into two groups:
+ </para>
+
+ <para>
+ An <emphasis>entity</emphasis> exists independently of any other objects holding
+ references to the entity. Contrast this with the usual Java model where an
+ unreferenced object is garbage collected. Entities must be explicitly saved and
+ deleted (except that saves and deletions may be <emphasis>cascaded</emphasis>
+ from a parent entity to its children). This is different from the ODMG model of
+ object persistence by reachablity - and corresponds more closely to how
+ application objects are usually used in large systems. Entities support
+ circular and shared references. They may also be versioned.
+ </para>
+
+ <para>
+ An entity's persistent state consists of references to other entities and
+ instances of <emphasis>value</emphasis> types. Values are primitives,
+ collections (not what's inside a collection), components and certain immutable
+ objects. Unlike entities, values (in particular collections and components)
+ <emphasis>are</emphasis> persisted and deleted by reachability. Since value
+ objects (and primitives) are persisted and deleted along with their containing
+ entity they may not be independently versioned. Values have no independent
+ identity, so they cannot be shared by two entities or collections.
+ </para>
+
+ <para>
+ Up until now, we've been using the term "persistent class" to refer to
+ entities. We will continue to do that. Strictly speaking, however, not all
+ user-defined classes with persistent state are entities. A
+ <emphasis>component</emphasis> is a user defined class with value semantics.
+ A Java property of type <literal>java.lang.String</literal> also has value
+ semantics. Given this definition, we can say that all types (classes) provided
+ by the JDK have value type semantics in Java, while user-defined types may
+ be mapped with entity or value type semantics. This decision is up to the
+ application developer. A good hint for an entity class in a domain model are
+ shared references to a single instance of that class, while composition or
+ aggregation usually translates to a value type.
+ </para>
+
+ <para>
+ We'll revisit both concepts throughout the documentation.
+ </para>
+
+ <para>
+ The challenge is to map the Java type system (and the developers' definition of
+ entities and value types) to the SQL/database type system. The bridge between
+ both systems is provided by Hibernate: for entities we use
+ <literal><class></literal>, <literal><subclass></literal> and so on.
+ For value types we use <literal><property></literal>,
+ <literal><component></literal>, etc, usually with a <literal>type</literal>
+ attribute. The value of this attribute is the name of a Hibernate
+ <emphasis>mapping type</emphasis>. Hibernate provides many mappings (for standard
+ JDK value types) out of the box. You can write your own mapping types and implement your
+ custom conversion strategies as well, as you'll see later.
+ </para>
+
+ <para>
+ All built-in Hibernate types except collections support null semantics.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-types-basictypes" revision="3">
+ <title>Basic value types</title>
+
+ <para>
+ The built-in <emphasis>basic mapping types</emphasis> may be roughly categorized into
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>integer, long, short, float, double, character, byte,
+ boolean, yes_no, true_false</literal></term>
+ <listitem>
+ <para>
+ Type mappings from Java primitives or wrapper classes to appropriate
+ (vendor-specific) SQL column types. <literal>boolean, yes_no</literal>
+ and <literal>true_false</literal> are all alternative encodings for
+ a Java <literal>boolean</literal> or <literal>java.lang.Boolean</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>string</literal></term>
+ <listitem>
+ <para>
+ A type mapping from <literal>java.lang.String</literal> to
+ <literal>VARCHAR</literal> (or Oracle <literal>VARCHAR2</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>date, time, timestamp</literal></term>
+ <listitem>
+ <para>
+ Type mappings from <literal>java.util.Date</literal> and its subclasses
+ to SQL types <literal>DATE</literal>, <literal>TIME</literal> and
+ <literal>TIMESTAMP</literal> (or equivalent).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>calendar, calendar_date</literal></term>
+ <listitem>
+ <para>
+ Type mappings from <literal>java.util.Calendar</literal> to
+ SQL types <literal>TIMESTAMP</literal> and <literal>DATE</literal>
+ (or equivalent).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>big_decimal, big_integer</literal></term>
+ <listitem>
+ <para>
+ Type mappings from <literal>java.math.BigDecimal</literal> and
+ <literal>java.math.BigInteger</literal> to <literal>NUMERIC</literal>
+ (or Oracle <literal>NUMBER</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>locale, timezone, currency</literal></term>
+ <listitem>
+ <para>
+ Type mappings from <literal>java.util.Locale</literal>,
+ <literal>java.util.TimeZone</literal> and
+ <literal>java.util.Currency</literal>
+ to <literal>VARCHAR</literal> (or Oracle <literal>VARCHAR2</literal>).
+ Instances of <literal>Locale</literal> and <literal>Currency</literal> are
+ mapped to their ISO codes. Instances of <literal>TimeZone</literal> are
+ mapped to their <literal>ID</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>class</literal></term>
+ <listitem>
+ <para>
+ A type mapping from <literal>java.lang.Class</literal> to
+ <literal>VARCHAR</literal> (or Oracle <literal>VARCHAR2</literal>).
+ A <literal>Class</literal> is mapped to its fully qualified name.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>binary</literal></term>
+ <listitem>
+ <para>
+ Maps byte arrays to an appropriate SQL binary type.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>text</literal></term>
+ <listitem>
+ <para>
+ Maps long Java strings to a SQL <literal>CLOB</literal> or
+ <literal>TEXT</literal> type.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>serializable</literal></term>
+ <listitem>
+ <para>
+ Maps serializable Java types to an appropriate SQL binary type. You
+ may also indicate the Hibernate type <literal>serializable</literal> with
+ the name of a serializable Java class or interface that does not default
+ to a basic type.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>clob, blob</literal></term>
+ <listitem>
+ <para>
+ Type mappings for the JDBC classes <literal>java.sql.Clob</literal> and
+ <literal>java.sql.Blob</literal>. These types may be inconvenient for some
+ applications, since the blob or clob object may not be reused outside of
+ a transaction. (Furthermore, driver support is patchy and inconsistent.)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>imm_date, imm_time, imm_timestamp, imm_calendar, imm_calendar_date,
+ imm_serializable, imm_binary</literal>
+ </term>
+ <listitem>
+ <para>
+ Type mappings for what are usually considered mutable Java types, where
+ Hibernate makes certain optimizations appropriate only for immutable
+ Java types, and the application treats the object as immutable. For
+ example, you should not call <literal>Date.setTime()</literal> for an
+ instance mapped as <literal>imm_timestamp</literal>. To change the
+ value of the property, and have that change made persistent, the
+ application must assign a new (nonidentical) object to the property.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </para>
+
+ <para>
+ Unique identifiers of entities and collections may be of any basic type except
+ <literal>binary</literal>, <literal>blob</literal> and <literal>clob</literal>.
+ (Composite identifiers are also allowed, see below.)
+ </para>
+
+ <para>
+ The basic value types have corresponding <literal>Type</literal> constants defined on
+ <literal>org.hibernate.Hibernate</literal>. For example, <literal>Hibernate.STRING</literal>
+ represents the <literal>string</literal> type.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-types-custom" revision="2">
+ <title>Custom value types</title>
+
+ <para>
+ It is relatively easy for developers to create their own value types. For example,
+ you might want to persist properties of type <literal>java.lang.BigInteger</literal>
+ to <literal>VARCHAR</literal> columns. Hibernate does not provide a built-in type
+ for this. But custom types are not limited to mapping a property (or collection element)
+ to a single table column. So, for example, you might have a Java property
+ <literal>getName()</literal>/<literal>setName()</literal> of type
+ <literal>java.lang.String</literal> that is persisted to the columns
+ <literal>FIRST_NAME</literal>, <literal>INITIAL</literal>, <literal>SURNAME</literal>.
+ </para>
+
+ <para>
+ To implement a custom type, implement either <literal>org.hibernate.UserType</literal>
+ or <literal>org.hibernate.CompositeUserType</literal> and declare properties using the
+ fully qualified classname of the type. Check out
+ <literal>org.hibernate.test.DoubleStringType</literal> to see the kind of things that
+ are possible.
+ </para>
+
+ <programlisting><![CDATA[<property name="twoStrings" type="org.hibernate.test.DoubleStringType">
+ <column name="first_string"/>
+ <column name="second_string"/>
+</property>]]></programlisting>
+
+ <para>
+ Notice the use of <literal><column></literal> tags to map a property to multiple
+ columns.
+ </para>
+
+ <para>
+ The <literal>CompositeUserType</literal>, <literal>EnhancedUserType</literal>,
+ <literal>UserCollectionType</literal>, and <literal>UserVersionType</literal>
+ interfaces provide support for more specialized uses.
+ </para>
+
+ <para>
+ You may even supply parameters to a <literal>UserType</literal> in the mapping file. To
+ do this, your <literal>UserType</literal> must implement the
+ <literal>org.hibernate.usertype.ParameterizedType</literal> interface. To supply parameters
+ to your custom type, you can use the <literal><type></literal> element in your mapping
+ files.
+ </para>
+
+ <programlisting><![CDATA[<property name="priority">
+ <type name="com.mycompany.usertypes.DefaultValueIntegerType">
+ <param name="default">0</param>
+ </type>
+</property>]]></programlisting>
+
+ <para>
+ The <literal>UserType</literal> can now retrieve the value for the parameter named
+ <literal>default</literal> from the <literal>Properties</literal> object passed to it.
+ </para>
+
+ <para>
+ If you use a certain <literal>UserType</literal> very often, it may be useful to define a
+ shorter name for it. You can do this using the <literal><typedef></literal> element.
+ Typedefs assign a name to a custom type, and may also contain a list of default
+ parameter values if the type is parameterized.
+ </para>
+
+ <programlisting><![CDATA[<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
+ <param name="default">0</param>
+</typedef>]]></programlisting>
+
+ <programlisting><![CDATA[<property name="priority" type="default_zero"/>]]></programlisting>
+
+ <para>
+ It is also possible to override the parameters supplied in a typedef on a case-by-case basis
+ by using type parameters on the property mapping.
+ </para>
+
+ <para>
+ Even though Hibernate's rich range of built-in types and support for components means you
+ will very rarely <emphasis>need</emphasis> to use a custom type, it is nevertheless
+ considered good form to use custom types for (non-entity) classes that occur frequently
+ in your application. For example, a <literal>MonetaryAmount</literal> class is a good
+ candidate for a <literal>CompositeUserType</literal>, even though it could easily be mapped
+ as a component. One motivation for this is abstraction. With a custom type, your mapping
+ documents would be future-proofed against possible changes in your way of representing
+ monetary values.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="mapping-entityname">
+ <title>Mapping a class more than once</title>
+ <para>
+ It is possible to provide more than one mapping for a particular persistent class. In this
+ case you must specify an <emphasis>entity name</emphasis> do disambiguate between instances
+ of the two mapped entities. (By default, the entity name is the same as the class name.)
+ Hibernate lets you specify the entity name when working with persistent objects, when writing
+ queries, or when mapping associations to the named entity.
+ </para>
+
+ <programlisting><![CDATA[<class name="Contract" table="Contracts"
+ entity-name="CurrentContract">
+ ...
+ <set name="history" inverse="true"
+ order-by="effectiveEndDate desc">
+ <key column="currentContractId"/>
+ <one-to-many entity-name="HistoricalContract"/>
+ </set>
+</class>
+
+<class name="Contract" table="ContractHistory"
+ entity-name="HistoricalContract">
+ ...
+ <many-to-one name="currentContract"
+ column="currentContractId"
+ entity-name="CurrentContract"/>
+</class>]]></programlisting>
+
+ <para>
+ Notice how associations are now specified using <literal>entity-name</literal> instead of
+ <literal>class</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="mapping-quotedidentifiers">
+ <title>SQL quoted identifiers</title>
+ <para>
+ You may force Hibernate to quote an identifier in the generated SQL by enclosing the table or
+ column name in backticks in the mapping document. Hibernate will use the correct quotation
+ style for the SQL <literal>Dialect</literal> (usually double quotes, but brackets for SQL
+ Server and backticks for MySQL).
+ </para>
+
+ <programlisting><![CDATA[<class name="LineItem" table="`Line Item`">
+ <id name="id" column="`Item Id`"/><generator class="assigned"/></id>
+ <property name="itemNumber" column="`Item #`"/>
+ ...
+</class>]]></programlisting>
+
+ </sect1>
+
+
+ <sect1 id="mapping-alternatives">
+ <title>Metadata alternatives</title>
+
+ <para>
+ XML isn't for everyone, and so there are some alternative ways to define O/R mapping metadata in Hibernate.
+ </para>
+
+ <sect2 id="mapping-xdoclet">
+ <title>Using XDoclet markup</title>
+
+ <para>
+ Many Hibernate users prefer to embed mapping information directly in sourcecode using
+ XDoclet <literal>@hibernate.tags</literal>. We will not cover this approach in this
+ document, since strictly it is considered part of XDoclet. However, we include the
+ following example of the <literal>Cat</literal> class with XDoclet mappings.
+ </para>
+
+ <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+/**
+ * @hibernate.class
+ * table="CATS"
+ */
+public class Cat {
+ private Long id; // identifier
+ private Date birthdate;
+ private Cat mother;
+ private Set kittens
+ private Color color;
+ private char sex;
+ private float weight;
+
+ /*
+ * @hibernate.id
+ * generator-class="native"
+ * column="CAT_ID"
+ */
+ public Long getId() {
+ return id;
+ }
+ private void setId(Long id) {
+ this.id=id;
+ }
+
+ /**
+ * @hibernate.many-to-one
+ * column="PARENT_ID"
+ */
+ public Cat getMother() {
+ return mother;
+ }
+ void setMother(Cat mother) {
+ this.mother = mother;
+ }
+
+ /**
+ * @hibernate.property
+ * column="BIRTH_DATE"
+ */
+ public Date getBirthdate() {
+ return birthdate;
+ }
+ void setBirthdate(Date date) {
+ birthdate = date;
+ }
+ /**
+ * @hibernate.property
+ * column="WEIGHT"
+ */
+ public float getWeight() {
+ return weight;
+ }
+ void setWeight(float weight) {
+ this.weight = weight;
+ }
+
+ /**
+ * @hibernate.property
+ * column="COLOR"
+ * not-null="true"
+ */
+ public Color getColor() {
+ return color;
+ }
+ void setColor(Color color) {
+ this.color = color;
+ }
+ /**
+ * @hibernate.set
+ * inverse="true"
+ * order-by="BIRTH_DATE"
+ * @hibernate.collection-key
+ * column="PARENT_ID"
+ * @hibernate.collection-one-to-many
+ */
+ public Set getKittens() {
+ return kittens;
+ }
+ void setKittens(Set kittens) {
+ this.kittens = kittens;
+ }
+ // addKitten not needed by Hibernate
+ public void addKitten(Cat kitten) {
+ kittens.add(kitten);
+ }
+
+ /**
+ * @hibernate.property
+ * column="SEX"
+ * not-null="true"
+ * update="false"
+ */
+ public char getSex() {
+ return sex;
+ }
+ void setSex(char sex) {
+ this.sex=sex;
+ }
+}]]></programlisting>
+
+ <para>
+ See the Hibernate web site for more examples of XDoclet and Hibernate.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-annotations" revision="2">
+ <title>Using JDK 5.0 Annotations</title>
+
+ <para>
+ JDK 5.0 introduced XDoclet-style annotations at the language level, type-safe and
+ checked at compile time. This mechnism is more powerful than XDoclet annotations and
+ better supported by tools and IDEs. IntelliJ IDEA, for example, supports auto-completion
+ and syntax highlighting of JDK 5.0 annotations. The new revision of the EJB specification
+ (JSR-220) uses JDK 5.0 annotations as the primary metadata mechanism for entity beans.
+ Hibernate3 implements the <literal>EntityManager</literal> of JSR-220 (the persistence API),
+ support for mapping metadata is available via the <emphasis>Hibernate Annotations</emphasis>
+ package, as a separate download. Both EJB3 (JSR-220) and Hibernate3 metadata is supported.
+ </para>
+
+ <para>
+ This is an example of a POJO class annotated as an EJB entity bean:
+ </para>
+
+ <programlisting><![CDATA[@Entity(access = AccessType.FIELD)
+public class Customer implements Serializable {
+
+ @Id;
+ Long id;
+
+ String firstName;
+ String lastName;
+ Date birthday;
+
+ @Transient
+ Integer age;
+
+ @Embedded
+ private Address homeAddress;
+
+ @OneToMany(cascade=CascadeType.ALL)
+ @JoinColumn(name="CUSTOMER_ID")
+ Set<Order> orders;
+
+ // Getter/setter and business methods
+}]]></programlisting>
+
+ <para>
+ Note that support for JDK 5.0 Annotations (and JSR-220) is still work in progress and
+ not completed. Please refer to the Hibernate Annotations module for more details.
+ </para>
+
+ </sect2>
+ </sect1>
+
+ <sect1 id="mapping-generated" revision="1">
+ <title>Generated Properties</title>
+ <para>
+ Generated properties are properties which have their values generated by the
+ database. Typically, Hibernate applications needed to <literal>refresh</literal>
+ objects which contain any properties for which the database was generating values.
+ Marking properties as generated, however, lets the application delegate this
+ responsibility to Hibernate. Essentially, whenever Hibernate issues an SQL INSERT
+ or UPDATE for an entity which has defined generated properties, it immediately
+ issues a select afterwards to retrieve the generated values.
+ </para>
+ <para>
+ Properties marked as generated must additionally be non-insertable and non-updateable.
+ Only <xref linkend="mapping-declaration-version">versions</xref>,
+ <xref linkend="mapping-declaration-timestamp">timestamps</xref>, and
+ <xref linkend="mapping-declaration-property">simple properties</xref> can be marked as
+ generated.
+ </para>
+ <para>
+ <literal>never</literal> (the default) - means that the given property value
+ is not generated within the database.
+ </para>
+ <para>
+ <literal>insert</literal> - states that the given property value is generated on
+ insert, but is not regenerated on subsequent updates. Things like created-date would
+ fall into this category. Note that even thought
+ <xref linkend="mapping-declaration-version">version</xref> and
+ <xref linkend="mapping-declaration-timestamp">timestamp</xref> properties can
+ be marked as generated, this option is not available there...
+ </para>
+ <para>
+ <literal>always</literal> - states that the property value is generated both
+ on insert and on update.
+ </para>
+ </sect1>
+
+ <sect1 id="mapping-database-object">
+ <title>Auxiliary Database Objects</title>
+ <para>
+ Allows CREATE and DROP of arbitrary database objects, in conjunction with
+ Hibernate's schema evolution tools, to provide the ability to fully define
+ a user schema within the Hibernate mapping files. Although designed specifically
+ for creating and dropping things like triggers or stored procedures, really any
+ SQL command that can be run via a <literal>java.sql.Statement.execute()</literal>
+ method is valid here (ALTERs, INSERTS, etc). There are essentially two modes for
+ defining auxiliary database objects...
+ </para>
+ <para>
+ The first mode is to explicitly list the CREATE and DROP commands out in the mapping
+ file:
+ </para>
+ <programlisting><![CDATA[<hibernate-mapping>
+ ...
+ <database-object>
+ <create>CREATE TRIGGER my_trigger ...</create>
+ <drop>DROP TRIGGER my_trigger</drop>
+ </database-object>
+</hibernate-mapping>]]></programlisting>
+ <para>
+ The second mode is to supply a custom class which knows how to construct the
+ CREATE and DROP commands. This custom class must implement the
+ <literal>org.hibernate.mapping.AuxiliaryDatabaseObject</literal> interface.
+ </para>
+ <programlisting><![CDATA[<hibernate-mapping>
+ ...
+ <database-object>
+ <definition class="MyTriggerDefinition"/>
+ </database-object>
+</hibernate-mapping>]]></programlisting>
+ <para>
+ Additionally, these database objects can be optionally scoped such that they only
+ apply when certain dialects are used.
+ </para>
+ <programlisting><![CDATA[<hibernate-mapping>
+ ...
+ <database-object>
+ <definition class="MyTriggerDefinition"/>
+ <dialect-scope name="org.hibernate.dialect.Oracle9Dialect"/>
+ <dialect-scope name="org.hibernate.dialect.OracleDialect"/>
+ </database-object>
+</hibernate-mapping>]]></programlisting>
+ </sect1>
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/batch.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/batch.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/batch.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,344 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="batch">
+ <title>Batch processing</title>
+
+ <para>
+ A naive approach to inserting 100 000 rows in the database using Hibernate might
+ look like this:
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+for ( int i=0; i<100000; i++ ) {
+ Customer customer = new Customer(.....);
+ session.save(customer);
+}
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ This would fall over with an <literal>OutOfMemoryException</literal> somewhere
+ around the 50 000th row. That's because Hibernate caches all the newly inserted
+ <literal>Customer</literal> instances in the session-level cache.
+ </para>
+
+ <para>
+ In this chapter we'll show you how to avoid this problem. First, however, if you
+ are doing batch processing, it is absolutely critical that you enable the use of
+ JDBC batching, if you intend to achieve reasonable performance. Set the JDBC batch
+ size to a reasonable number (say, 10-50):
+ </para>
+
+<programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
+
+ <para>
+ You also might like to do this kind of work in a process where interaction with
+ the second-level cache is completely disabled:
+ </para>
+
+<programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
+
+ <para>
+ However, this is not absolutely necessary, since we can explicitly set the
+ <literal>CacheMode</literal> to disable interaction with the second-level cache.
+ </para>
+
+ <sect1 id="batch-inserts">
+ <title>Batch inserts</title>
+
+ <para>
+ When making new objects persistent, you must <literal>flush()</literal> and
+ then <literal>clear()</literal> the session regularly, to control the size of
+ the first-level cache.
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+for ( int i=0; i<100000; i++ ) {
+ Customer customer = new Customer(.....);
+ session.save(customer);
+ if ( i % 20 == 0 ) { //20, same as the JDBC batch size
+ //flush a batch of inserts and release memory:
+ session.flush();
+ session.clear();
+ }
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="batch-update" >
+ <title>Batch updates</title>
+
+ <para>
+ For retrieving and updating data the same ideas apply. In addition, you need to
+ use <literal>scroll()</literal> to take advantage of server-side cursors for
+ queries that return many rows of data.
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+ .setCacheMode(CacheMode.IGNORE)
+ .scroll(ScrollMode.FORWARD_ONLY);
+int count=0;
+while ( customers.next() ) {
+ Customer customer = (Customer) customers.get(0);
+ customer.updateStuff(...);
+ if ( ++count % 20 == 0 ) {
+ //flush a batch of updates and release memory:
+ session.flush();
+ session.clear();
+ }
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="batch-statelesssession">
+ <title>The StatelessSession interface</title>
+ <para>
+ Alternatively, Hibernate provides a command-oriented API that may be used for
+ streaming data to and from the database in the form of detached objects. A
+ <literal>StatelessSession</literal> has no persistence context associated
+ with it and does not provide many of the higher-level lifecycle semantics.
+ In particular, a stateless session does not implement a first-level cache nor
+ interact with any second-level or query cache. It does not implement
+ transactional write-behind or automatic dirty checking. Operations performed
+ using a stateless session do not ever cascade to associated instances. Collections
+ are ignored by a stateless session. Operations performed via a stateless session
+ bypass Hibernate's event model and interceptors. Stateless sessions are vulnerable
+ to data aliasing effects, due to the lack of a first-level cache. A stateless
+ session is a lower-level abstraction, much closer to the underlying JDBC.
+ </para>
+
+<programlisting><![CDATA[StatelessSession session = sessionFactory.openStatelessSession();
+Transaction tx = session.beginTransaction();
+
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+ .scroll(ScrollMode.FORWARD_ONLY);
+while ( customers.next() ) {
+ Customer customer = (Customer) customers.get(0);
+ customer.updateStuff(...);
+ session.update(customer);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ Note that in this code example, the <literal>Customer</literal> instances returned
+ by the query are immediately detached. They are never associated with any persistence
+ context.
+ </para>
+
+ <para>
+ The <literal>insert(), update()</literal> and <literal>delete()</literal> operations
+ defined by the <literal>StatelessSession</literal> interface are considered to be
+ direct database row-level operations, which result in immediate execution of a SQL
+ <literal>INSERT, UPDATE</literal> or <literal>DELETE</literal> respectively. Thus,
+ they have very different semantics to the <literal>save(), saveOrUpdate()</literal>
+ and <literal>delete()</literal> operations defined by the <literal>Session</literal>
+ interface.
+ </para>
+
+ </sect1>
+
+ <sect1 id="batch-direct" revision="3">
+ <title>DML-style operations</title>
+
+ <para>
+ As already discussed, automatic and transparent object/relational mapping is concerned
+ with the management of object state. This implies that the object state is available
+ in memory, hence manipulating (using the SQL <literal>Data Manipulation Language</literal>
+ (DML) statements: <literal>INSERT</literal>, <literal>UPDATE</literal>, <literal>DELETE</literal>)
+ data directly in the database will not affect in-memory state. However, Hibernate provides methods
+ for bulk SQL-style DML statement execution which are performed through the
+ Hibernate Query Language (<xref linkend="queryhql">HQL</xref>).
+ </para>
+
+ <para>
+ The pseudo-syntax for <literal>UPDATE</literal> and <literal>DELETE</literal> statements
+ is: <literal>( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?</literal>. Some
+ points to note:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ In the from-clause, the FROM keyword is optional
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ There can only be a single entity named in the from-clause; it can optionally be
+ aliased. If the entity name is aliased, then any property references must
+ be qualified using that alias; if the entity name is not aliased, then it is
+ illegal for any property references to be qualified.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ No <xref linkend="queryhql-joins-forms">joins</xref> (either implicit or explicit)
+ can be specified in a bulk HQL query. Sub-queries may be used in the where-clause;
+ the subqueries, themselves, may contain joins.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The where-clause is also optional.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ As an example, to execute an HQL <literal>UPDATE</literal>, use the
+ <literal>Query.executeUpdate()</literal> method (the method is named for
+ those familiar with JDBC's <literal>PreparedStatement.executeUpdate()</literal>):
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
+// or String hqlUpdate = "update Customer set name = :newName where name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+ .setString( "newName", newName )
+ .setString( "oldName", oldName )
+ .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ HQL <literal>UPDATE</literal> statements, by default do not effect the
+ <xref linkend="mapping-declaration-version">version</xref>
+ or the <xref linkend="mapping-declaration-timestamp">timestamp</xref> property values
+ for the affected entities; this is in keeping with the EJB3 specification. However,
+ you can force Hibernate to properly reset the <literal>version</literal> or
+ <literal>timestamp</literal> property values through the use of a <literal>versioned update</literal>.
+ This is achieved by adding the <literal>VERSIONED</literal> keyword after the <literal>UPDATE</literal>
+ keyword.
+ </para>
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+ .setString( "newName", newName )
+ .setString( "oldName", oldName )
+ .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ Note that custom version types (<literal>org.hibernate.usertype.UserVersionType</literal>)
+ are not allowed in conjunction with a <literal>update versioned</literal> statement.
+ </para>
+
+ <para>
+ To execute an HQL <literal>DELETE</literal>, use the same <literal>Query.executeUpdate()</literal>
+ method:
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlDelete = "delete Customer c where c.name = :oldName";
+// or String hqlDelete = "delete Customer where name = :oldName";
+int deletedEntities = s.createQuery( hqlDelete )
+ .setString( "oldName", oldName )
+ .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ The <literal>int</literal> value returned by the <literal>Query.executeUpdate()</literal>
+ method indicate the number of entities effected by the operation. Consider this may or may not
+ correlate to the number of rows effected in the database. An HQL bulk operation might result in
+ multiple actual SQL statements being executed, for joined-subclass, for example. The returned
+ number indicates the number of actual entities affected by the statement. Going back to the
+ example of joined-subclass, a delete against one of the subclasses may actually result
+ in deletes against not just the table to which that subclass is mapped, but also the "root"
+ table and potentially joined-subclass tables further down the inheritence hierarchy.
+ </para>
+
+ <para>
+ The pseudo-syntax for <literal>INSERT</literal> statements is:
+ <literal>INSERT INTO EntityName properties_list select_statement</literal>. Some
+ points to note:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Only the INSERT INTO ... SELECT ... form is supported; not the INSERT INTO ... VALUES ... form.
+ </para>
+ <para>
+ The properties_list is analogous to the <literal>column speficiation</literal>
+ in the SQL <literal>INSERT</literal> statement. For entities involved in mapped
+ inheritence, only properties directly defined on that given class-level can be
+ used in the properties_list. Superclass properties are not allowed; and subclass
+ properties do not make sense. In other words, <literal>INSERT</literal>
+ statements are inherently non-polymorphic.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ select_statement can be any valid HQL select query, with the caveat that the return types
+ must match the types expected by the insert. Currently, this is checked during query
+ compilation rather than allowing the check to relegate to the database. Note however
+ that this might cause problems between Hibernate <literal>Type</literal>s which are
+ <emphasis>equivalent</emphasis> as opposed to <emphasis>equal</emphasis>. This might cause
+ issues with mismatches between a property defined as a <literal>org.hibernate.type.DateType</literal>
+ and a property defined as a <literal>org.hibernate.type.TimestampType</literal>, even though the
+ database might not make a distinction or might be able to handle the conversion.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ For the id property, the insert statement gives you two options. You can either
+ explicitly specify the id property in the properties_list (in which case its value
+ is taken from the corresponding select expression) or omit it from the properties_list
+ (in which case a generated value is used). This later option is only available when
+ using id generators that operate in the database; attempting to use this option with
+ any "in memory" type generators will cause an exception during parsing. Note that
+ for the purposes of this discussion, in-database generators are considered to be
+ <literal>org.hibernate.id.SequenceGenerator</literal> (and its subclasses) and
+ any implementors of <literal>org.hibernate.id.PostInsertIdentifierGenerator</literal>.
+ The most notable exception here is <literal>org.hibernate.id.TableHiLoGenerator</literal>,
+ which cannot be used because it does not expose a selectable way to get its values.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ For properties mapped as either <literal>version</literal> or <literal>timestamp</literal>,
+ the insert statement gives you two options. You can either specify the property in the
+ properties_list (in which case its value is taken from the corresponding select expressions)
+ or omit it from the properties_list (in which case the <literal>seed value</literal> defined
+ by the <literal>org.hibernate.type.VersionType</literal> is used).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ An example HQL <literal>INSERT</literal> statement execution:
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
+int createdEntities = s.createQuery( hqlInsert )
+ .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/best_practices.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/best_practices.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/best_practices.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,225 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="best-practices" revision="3">
+ <title>Best Practices</title>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>Write fine-grained classes and map them using <literal><component></literal>.</term>
+ <listitem>
+ <para>
+ Use an <literal>Address</literal> class to encapsulate <literal>street</literal>,
+ <literal>suburb</literal>, <literal>state</literal>, <literal>postcode</literal>.
+ This encourages code reuse and simplifies refactoring.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Declare identifier properties on persistent classes.</term>
+ <listitem>
+ <para>
+ Hibernate makes identifier properties optional. There are all sorts of reasons why
+ you should use them. We recommend that identifiers be 'synthetic' (generated, with
+ no business meaning).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Identify natural keys.</term>
+ <listitem>
+ <para>
+ Identify natural keys for all entities, and map them using
+ <literal><natural-id></literal>. Implement <literal>equals()</literal> and
+ <literal>hashCode()</literal> to compare the properties that make up the natural key.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Place each class mapping in its own file.</term>
+ <listitem>
+ <para>
+ Don't use a single monolithic mapping document. Map <literal>com.eg.Foo</literal> in
+ the file <literal>com/eg/Foo.hbm.xml</literal>. This makes particularly good sense in
+ a team environment.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Load mappings as resources.</term>
+ <listitem>
+ <para>
+ Deploy the mappings along with the classes they map.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Consider externalising query strings.</term>
+ <listitem>
+ <para>
+ This is a good practice if your queries call non-ANSI-standard SQL functions.
+ Externalising the query strings to mapping files will make the application more
+ portable.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Use bind variables.</term>
+ <listitem>
+ <para>
+ As in JDBC, always replace non-constant values by "?". Never use string manipulation to
+ bind a non-constant value in a query! Even better, consider using named parameters in
+ queries.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Don't manage your own JDBC connections.</term>
+ <listitem>
+ <para>
+ Hibernate lets the application manage JDBC connections. This approach should be considered
+ a last-resort. If you can't use the built-in connections providers, consider providing your
+ own implementation of <literal>org.hibernate.connection.ConnectionProvider</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Consider using a custom type.</term>
+ <listitem>
+ <para>
+ Suppose you have a Java type, say from some library, that needs to be persisted but doesn't
+ provide the accessors needed to map it as a component. You should consider implementing
+ <literal>org.hibernate.UserType</literal>. This approach frees the application
+ code from implementing transformations to / from a Hibernate type.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Use hand-coded JDBC in bottlenecks.</term>
+ <listitem>
+ <para>
+ In performance-critical areas of the system, some kinds of operations might benefit from
+ direct JDBC. But please, wait until you <emphasis>know</emphasis> something is a bottleneck.
+ And don't assume that direct JDBC is necessarily faster. If you need to use direct JDBC, it might
+ be worth opening a Hibernate <literal>Session</literal> and using that JDBC connection. That
+ way you can still use the same transaction strategy and underlying connection provider.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Understand <literal>Session</literal> flushing.</term>
+ <listitem>
+ <para>
+ From time to time the Session synchronizes its persistent state with the database. Performance will
+ be affected if this process occurs too often. You may sometimes minimize unnecessary flushing by
+ disabling automatic flushing or even by changing the order of queries and other operations within a
+ particular transaction.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>In a three tiered architecture, consider using detached objects.</term>
+ <listitem>
+ <para>
+ When using a servlet / session bean architecture, you could pass persistent objects loaded in
+ the session bean to and from the servlet / JSP layer. Use a new session to service each request.
+ Use <literal>Session.merge()</literal> or <literal>Session.saveOrUpdate()</literal> to
+ synchronize objects with the database.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>In a two tiered architecture, consider using long persistence contexts.</term>
+ <listitem>
+ <para>
+ Database Transactions have to be as short as possible for best scalability. However, it is often
+ neccessary to implement long running <emphasis>application transactions</emphasis>, a single
+ unit-of-work from the point of view of a user. An application transaction might span several
+ client request/response cycles. It is common to use detached objects to implement application
+ transactions. An alternative, extremely appropriate in two tiered architecture, is to maintain
+ a single open persistence contact (session) for the whole lifecycle of the application transaction
+ and simply disconnect from the JDBC connection at the end of each request and reconnect at the
+ beginning of the subsequent request. Never share a single session across more than one application
+ transaction, or you will be working with stale data.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Don't treat exceptions as recoverable.</term>
+ <listitem>
+ <para>
+ This is more of a necessary practice than a "best" practice. When an exception occurs, roll back
+ the <literal>Transaction</literal> and close the <literal>Session</literal>. If you don't, Hibernate
+ can't guarantee that in-memory state accurately represents persistent state. As a special case of this,
+ do not use <literal>Session.load()</literal> to determine if an instance with the given identifier
+ exists on the database; use <literal>Session.get()</literal> or a query instead.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Prefer lazy fetching for associations.</term>
+ <listitem>
+ <para>
+ Use eager fetching sparingly. Use proxies and lazy collections for most associations to classes that
+ are not likely to be completely held in the second-level cache. For associations to cached classes,
+ where there is an a extremely high probability of a cache hit, explicitly disable eager fetching using
+ <literal>lazy="false"</literal>. When an join fetching is appropriate to a particular use
+ case, use a query with a <literal>left join fetch</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ Use the <emphasis>open session in view</emphasis> pattern, or a disciplined
+ <emphasis>assembly phase</emphasis> to avoid problems with unfetched data.
+ </term>
+ <listitem>
+ <para>
+ Hibernate frees the developer from writing tedious <emphasis>Data Transfer Objects</emphasis> (DTO).
+ In a traditional EJB architecture, DTOs serve dual purposes: first, they work around the problem
+ that entity beans are not serializable; second, they implicitly define an assembly phase where
+ all data to be used by the view is fetched and marshalled into the DTOs before returning control
+ to the presentation tier. Hibernate eliminates the first purpose. However, you will still need
+ an assembly phase (think of your business methods as having a strict contract with the presentation
+ tier about what data is available in the detached objects) unless you are prepared to hold the
+ persistence context (the session) open across the view rendering process. This is not a limitation
+ of Hibernate! It is a fundamental requirement of safe transactional data access.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Consider abstracting your business logic from Hibernate.</term>
+ <listitem>
+ <para>
+ Hide (Hibernate) data-access code behind an interface. Combine the <emphasis>DAO</emphasis> and
+ <emphasis>Thread Local Session</emphasis> patterns. You can even have some classes persisted by
+ handcoded JDBC, associated to Hibernate via a <literal>UserType</literal>. (This advice is
+ intended for "sufficiently large" applications; it is not appropriate for an application with
+ five tables!)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Don't use exotic association mappings.</term>
+ <listitem>
+ <para>
+ Good usecases for a real many-to-many associations are rare. Most of the time you need
+ additional information stored in the "link table". In this case, it is much better to
+ use two one-to-many associations to an intermediate link class. In fact, we think that
+ most associations are one-to-many and many-to-one, you should be careful when using any
+ other association style and ask yourself if it is really neccessary.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Prefer bidirectional associations.</term>
+ <listitem>
+ <para>
+ Unidirectional associations are more difficult to query. In a large application, almost
+ all associations must be navigable in both directions in queries.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/collection_mapping.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/collection_mapping.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/collection_mapping.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,1233 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="collections">
+ <title>Collection Mapping</title>
+
+ <sect1 id="collections-persistent" revision="3">
+ <title>Persistent collections</title>
+
+ <para>
+ Hibernate requires that persistent collection-valued fields be declared
+ as an interface type, for example:
+ </para>
+
+ <programlisting><![CDATA[public class Product {
+ private String serialNumber;
+ private Set parts = new HashSet();
+
+ public Set getParts() { return parts; }
+ void setParts(Set parts) { this.parts = parts; }
+ public String getSerialNumber() { return serialNumber; }
+ void setSerialNumber(String sn) { serialNumber = sn; }
+}]]></programlisting>
+
+ <para>
+ The actual interface might be <literal>java.util.Set</literal>,
+ <literal>java.util.Collection</literal>, <literal>java.util.List</literal>,
+ <literal>java.util.Map</literal>, <literal>java.util.SortedSet</literal>,
+ <literal>java.util.SortedMap</literal> or ... anything you like! (Where
+ "anything you like" means you will have to write an implementation of
+ <literal>org.hibernate.usertype.UserCollectionType</literal>.)
+ </para>
+
+ <para>
+ Notice how we initialized the instance variable with an instance of
+ <literal>HashSet</literal>. This is the best way to initialize collection
+ valued properties of newly instantiated (non-persistent) instances. When
+ you make the instance persistent - by calling <literal>persist()</literal>,
+ for example - Hibernate will actually replace the <literal>HashSet</literal>
+ with an instance of Hibernate's own implementation of <literal>Set</literal>.
+ Watch out for errors like this:
+ </para>
+
+ <programlisting><![CDATA[Cat cat = new DomesticCat();
+Cat kitten = new DomesticCat();
+....
+Set kittens = new HashSet();
+kittens.add(kitten);
+cat.setKittens(kittens);
+session.persist(cat);
+kittens = cat.getKittens(); // Okay, kittens collection is a Set
+(HashSet) cat.getKittens(); // Error!]]></programlisting>
+
+ <para>
+ The persistent collections injected by Hibernate behave like
+ <literal>HashMap</literal>, <literal>HashSet</literal>,
+ <literal>TreeMap</literal>, <literal>TreeSet</literal> or
+ <literal>ArrayList</literal>, depending upon the interface type.
+ </para>
+
+ <para>
+ Collections instances have the usual behavior of value types. They are
+ automatically persisted when referenced by a persistent object and
+ automatically deleted when unreferenced. If a collection is passed from one
+ persistent object to another, its elements might be moved from one table to
+ another. Two entities may not share a reference to the same collection
+ instance. Due to the underlying relational model, collection-valued properties
+ do not support null value semantics; Hibernate does not distinguish between
+ a null collection reference and an empty collection.
+ </para>
+
+ <para>
+ You shouldn't have to worry much about any of this. Use persistent collections
+ the same way you use ordinary Java collections. Just make sure you understand
+ the semantics of bidirectional associations (discussed later).
+ </para>
+
+ </sect1>
+
+ <sect1 id="collections-mapping" revision="4">
+ <title>Collection mappings</title>
+
+ <para>
+ The Hibernate mapping element used for mapping a collection depends upon
+ the type of the interface. For example, a <literal><set></literal>
+ element is used for mapping properties of type <literal>Set</literal>.
+ </para>
+
+ <programlisting><![CDATA[<class name="Product">
+ <id name="serialNumber" column="productSerialNumber"/>
+ <set name="parts">
+ <key column="productSerialNumber" not-null="true"/>
+ <one-to-many class="Part"/>
+ </set>
+</class>]]></programlisting>
+
+ <para>
+ Apart from <literal><set></literal>, there is also
+ <literal><list></literal>, <literal><map></literal>,
+ <literal><bag></literal>, <literal><array></literal> and
+ <literal><primitive-array></literal> mapping elements. The
+ <literal><map></literal> element is representative:
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="mappingcollection1" coords="2 65"/>
+ <area id="mappingcollection2" coords="3 65"/>
+ <area id="mappingcollection3" coords="4 65"/>
+ <area id="mappingcollection4" coords="5 65"/>
+ <area id="mappingcollection5" coords="6 65"/>
+ <area id="mappingcollection6" coords="7 65"/>
+ <area id="mappingcollection7" coords="8 65"/>
+ <area id="mappingcollection8" coords="9 65"/>
+ <area id="mappingcollection9" coords="10 65"/>
+ <area id="mappingcollection10" coords="11 65"/>
+ <area id="mappingcollection11" coords="12 65"/>
+ <area id="mappingcollection12" coords="13 65"/>
+ <area id="mappingcollection13" coords="14 65"/>
+ <area id="mappingcollection14" coords="15 65"/>
+ </areaspec>
+ <programlisting><![CDATA[<map
+ name="propertyName"
+ table="table_name"
+ schema="schema_name"
+ lazy="true|extra|false"
+ inverse="true|false"
+ cascade="all|none|save-update|delete|all-delete-orphan|delete-orphan"
+ sort="unsorted|natural|comparatorClass"
+ order-by="column_name asc|desc"
+ where="arbitrary sql where condition"
+ fetch="join|select|subselect"
+ batch-size="N"
+ access="field|property|ClassName"
+ optimistic-lock="true|false"
+ mutable="true|false"
+ node="element-name|."
+ embed-xml="true|false"
+>
+
+ <key .... />
+ <map-key .... />
+ <element .... />
+</map>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="mappingcollection1">
+ <para>
+ <literal>name</literal> the collection property name
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection2">
+ <para>
+ <literal>table</literal> (optional - defaults to property name) the
+ name of the collection table (not used for one-to-many associations)
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection3">
+ <para>
+ <literal>schema</literal> (optional) the name of a table schema to
+ override the schema declared on the root element
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection4">
+ <para>
+ <literal>lazy</literal> (optional - defaults to <literal>true</literal>)
+ may be used to disable lazy fetching and specify that the association is
+ always eagerly fetched, or to enable "extra-lazy" fetching where most
+ operations do not initialize the collection (suitable for very large
+ collections)
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection5">
+ <para>
+ <literal>inverse</literal> (optional - defaults to <literal>false</literal>)
+ mark this collection as the "inverse" end of a bidirectional association
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection6">
+ <para>
+ <literal>cascade</literal> (optional - defaults to <literal>none</literal>)
+ enable operations to cascade to child entities
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection7">
+ <para>
+ <literal>sort</literal> (optional) specify a sorted collection with
+ <literal>natural</literal> sort order, or a given comparator class
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection8">
+ <para>
+ <literal>order-by</literal> (optional, JDK1.4 only) specify a table column (or columns)
+ that define the iteration order of the <literal>Map</literal>, <literal>Set</literal>
+ or bag, together with an optional <literal>asc</literal> or <literal>desc</literal>
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection9">
+ <para>
+ <literal>where</literal> (optional) specify an arbitrary SQL <literal>WHERE</literal>
+ condition to be used when retrieving or removing the collection (useful if the
+ collection should contain only a subset of the available data)
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection10">
+ <para>
+ <literal>fetch</literal> (optional, defaults to <literal>select</literal>) Choose
+ between outer-join fetching, fetching by sequential select, and fetching by sequential
+ subselect.
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection11">
+ <para>
+ <literal>batch-size</literal> (optional, defaults to <literal>1</literal>) specify a
+ "batch size" for lazily fetching instances of this collection.
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection12">
+ <para>
+ <literal>access</literal> (optional - defaults to <literal>property</literal>): The
+ strategy Hibernate should use for accessing the collection property value.
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection13">
+ <para>
+ <literal>optimistic-lock</literal> (optional - defaults to <literal>true</literal>):
+ Species that changes to the state of the collection results in increment of the
+ owning entity's version. (For one to many associations, it is often reasonable to
+ disable this setting.)
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection14">
+ <para>
+ <literal>mutable</literal> (optional - defaults to <literal>true</literal>):
+ A value of <literal>false</literal> specifies that the elements of the
+ collection never change (a minor performance optimization in some cases).
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <sect2 id="collections-foreignkeys" >
+ <title>Collection foreign keys</title>
+
+ <para>
+ Collection instances are distinguished in the database by the foreign key of
+ the entity that owns the collection. This foreign key is referred to as the
+ <emphasis>collection key column</emphasis> (or columns) of the collection
+ table. The collection key column is mapped by the <literal><key></literal>
+ element.
+ </para>
+
+ <para>
+ There may be a nullability constraint on the foreign key column. For most
+ collections, this is implied. For unidirectional one to many associations,
+ the foreign key column is nullable by default, so you might need to specify
+ <literal>not-null="true"</literal>.
+ </para>
+
+ <programlisting><![CDATA[<key column="productSerialNumber" not-null="true"/>]]></programlisting>
+
+ <para>
+ The foreign key constraint may use <literal>ON DELETE CASCADE</literal>.
+ </para>
+
+ <programlisting><![CDATA[<key column="productSerialNumber" on-delete="cascade"/>]]></programlisting>
+
+ <para>
+ See the previous chapter for a full definition of the <literal><key></literal>
+ element.
+ </para>
+
+ </sect2>
+
+ <sect2 id="collections-elements" >
+ <title>Collection elements</title>
+
+ <para>
+ Collections may contain almost any other Hibernate type, including all basic types,
+ custom types, components, and of course, references to other entities. This is an
+ important distinction: an object in a collection might be handled with "value"
+ semantics (its lifecycle fully depends on the collection owner) or it might be a
+ reference to another entity, with its own lifecycle. In the latter case, only the
+ "link" between the two objects is considered to be state held by the collection.
+ </para>
+
+ <para>
+ The contained type is referred to as the <emphasis>collection element type</emphasis>.
+ Collection elements are mapped by <literal><element></literal> or
+ <literal><composite-element></literal>, or in the case of entity references,
+ with <literal><one-to-many></literal> or <literal><many-to-many></literal>.
+ The first two map elements with value semantics, the next two are used to map entity
+ associations.
+ </para>
+
+ </sect2>
+
+ <sect2 id="collections-indexed">
+ <title>Indexed collections</title>
+
+ <para>
+ All collection mappings, except those with set and bag semantics, need an
+ <emphasis>index column</emphasis> in the collection table - a column that maps to an
+ array index, or <literal>List</literal> index, or <literal>Map</literal> key. The
+ index of a <literal>Map</literal> may be of any basic type, mapped with
+ <literal><map-key></literal>, it may be an entity reference mapped with
+ <literal><map-key-many-to-many></literal>, or it may be a composite type,
+ mapped with <literal><composite-map-key></literal>. The index of an array or
+ list is always of type <literal>integer</literal> and is mapped using the
+ <literal><list-index></literal> element. The mapped column contains
+ sequential integers (numbered from zero, by default).
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="index1" coords="2 45"/>
+ <area id="index2" coords="3 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<list-index
+ column="column_name"
+ base="0|1|..."/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="index1">
+ <para>
+ <literal>column_name</literal> (required): The name of the column holding the
+ collection index values.
+ </para>
+ </callout>
+ <callout arearefs="index1">
+ <para>
+ <literal>base</literal> (optional, defaults to <literal>0</literal>): The value
+ of the index column that corresponds to the first element of the list or array.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <programlistingco>
+ <areaspec>
+ <area id="mapkey1" coords="2 45"/>
+ <area id="mapkey2" coords="3 45"/>
+ <area id="mapkey3" coords="4 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<map-key
+ column="column_name"
+ formula="any SQL expression"
+ type="type_name"
+ node="@attribute-name"
+ length="N"/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="mapkey1">
+ <para>
+ <literal>column</literal> (optional): The name of the column holding the
+ collection index values.
+ </para>
+ </callout>
+ <callout arearefs="mapkey2">
+ <para>
+ <literal>formula</literal> (optional): A SQL formula used to evaluate the
+ key of the map.
+ </para>
+ </callout>
+ <callout arearefs="mapkey3">
+ <para>
+ <literal>type</literal> (reguired): The type of the map keys.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <programlistingco>
+ <areaspec>
+ <area id="indexmanytomany1" coords="2 45"/>
+ <area id="indexmanytomany2" coords="3 45"/>
+ <area id="indexmanytomany3" coords="3 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<map-key-many-to-many
+ column="column_name"
+ formula="any SQL expression"
+ class="ClassName"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="indexmanytomany1">
+ <para>
+ <literal>column</literal> (optional): The name of the foreign key
+ column for the collection index values.
+ </para>
+ </callout>
+ <callout arearefs="indexmanytomany2">
+ <para>
+ <literal>formula</literal> (optional): A SQL formula used to evaluate the
+ foreign key of the map key.
+ </para>
+ </callout>
+ <callout arearefs="indexmanytomany3">
+ <para>
+ <literal>class</literal> (required): The entity class used as the map key.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+
+ <para>
+ If your table doesn't have an index column, and you still wish to use <literal>List</literal>
+ as the property type, you should map the property as a Hibernate <emphasis><bag></emphasis>.
+ A bag does not retain its order when it is retrieved from the database, but it may be
+ optionally sorted or ordered.
+ </para>
+
+ </sect2>
+
+ <para>
+ There are quite a range of mappings that can be generated for collections, covering
+ many common relational models. We suggest you experiment with the schema generation tool
+ to get a feeling for how various mapping declarations translate to database tables.
+ </para>
+
+ <sect2 id="collections-ofvalues" revision="2">
+ <title>Collections of values and many-to-many associations</title>
+
+ <para>
+ Any collection of values or many-to-many association requires a dedicated
+ <emphasis>collection table</emphasis> with a foreign key column or columns,
+ <emphasis>collection element column</emphasis> or columns and possibly
+ an index column or columns.
+ </para>
+
+ <para>
+ For a collection of values, we use the <literal><element></literal> tag.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="element1b" coords="2 50"/>
+ <area id="element2b" coords="3 50"/>
+ <area id="element3b" coords="4 50"/>
+ </areaspec>
+ <programlisting><![CDATA[<element
+ column="column_name"
+ formula="any SQL expression"
+ type="typename"
+ length="L"
+ precision="P"
+ scale="S"
+ not-null="true|false"
+ unique="true|false"
+ node="element-name"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="element1b">
+ <para>
+ <literal>column</literal> (optional): The name of the column holding the
+ collection element values.
+ </para>
+ </callout>
+ <callout arearefs="element2b">
+ <para>
+ <literal>formula</literal> (optional): An SQL formula used to evaluate the
+ element.
+ </para>
+ </callout>
+ <callout arearefs="element3b">
+ <para>
+ <literal>type</literal> (required): The type of the collection element.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ A <emphasis>many-to-many association</emphasis> is specified using the
+ <literal><many-to-many></literal> element.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="manytomany1" coords="2 60"/>
+ <area id="manytomany2" coords="3 60"/>
+ <area id="manytomany3" coords="4 60"/>
+ <area id="manytomany4" coords="5 60"/>
+ <area id="manytomany5" coords="6 60"/>
+ <area id="manytomany6" coords="7 60"/>
+ <area id="manytomany7" coords="8 60"/>
+ <area id="manytomany8" coords="9 60"/>
+ </areaspec>
+ <programlisting><![CDATA[<many-to-many
+ column="column_name"
+ formula="any SQL expression"
+ class="ClassName"
+ fetch="select|join"
+ unique="true|false"
+ not-found="ignore|exception"
+ entity-name="EntityName"
+ property-ref="propertyNameFromAssociatedClass"
+ node="element-name"
+ embed-xml="true|false"
+ />]]></programlisting>
+ <calloutlist>
+ <callout arearefs="manytomany1">
+ <para>
+ <literal>column</literal> (optional): The name of the element foreign key column.
+ </para>
+ </callout>
+ <callout arearefs="manytomany2">
+ <para>
+ <literal>formula</literal> (optional): An SQL formula used to evaluate the element
+ foreign key value.
+ </para>
+ </callout>
+ <callout arearefs="manytomany3">
+ <para>
+ <literal>class</literal> (required): The name of the associated class.
+ </para>
+ </callout>
+ <callout arearefs="manytomany4">
+ <para>
+ <literal>fetch</literal> (optional - defaults to <literal>join</literal>):
+ enables outer-join or sequential select fetching for this association. This
+ is a special case; for full eager fetching (in a single <literal>SELECT</literal>)
+ of an entity and its many-to-many relationships to other entities, you would
+ enable <literal>join</literal> fetching not only of the collection itself,
+ but also with this attribute on the <literal><many-to-many></literal>
+ nested element.
+ </para>
+ </callout>
+ <callout arearefs="manytomany5">
+ <para>
+ <literal>unique</literal> (optional): Enable the DDL generation of a unique
+ constraint for the foreign-key column. This makes the association multiplicity
+ effectively one to many.
+ </para>
+ </callout>
+ <callout arearefs="manytomany6">
+ <para>
+ <literal>not-found</literal> (optional - defaults to <literal>exception</literal>):
+ Specifies how foreign keys that reference missing rows will be handled:
+ <literal>ignore</literal> will treat a missing row as a null association.
+ </para>
+ </callout>
+ <callout arearefs="manytomany7">
+ <para>
+ <literal>entity-name</literal> (optional): The entity name of the associated class,
+ as an alternative to <literal>class</literal>.
+ </para>
+ </callout>
+ <callout arearefs="manytomany8">
+ <para>
+ <literal>property-ref</literal>: (optional) The name of a property of the associated
+ class that is joined to this foreign key. If not specified, the primary key of
+ the associated class is used.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Some examples, first, a set of strings:
+ </para>
+
+ <programlisting><![CDATA[<set name="names" table="person_names">
+ <key column="person_id"/>
+ <element column="person_name" type="string"/>
+</set>]]></programlisting>
+
+ <para>
+ A bag containing integers (with an iteration order determined by the
+ <literal>order-by</literal> attribute):
+ </para>
+
+ <programlisting><![CDATA[<bag name="sizes"
+ table="item_sizes"
+ order-by="size asc">
+ <key column="item_id"/>
+ <element column="size" type="integer"/>
+</bag>]]></programlisting>
+
+ <para>
+ An array of entities - in this case, a many to many association:
+ </para>
+
+ <programlisting><![CDATA[<array name="addresses"
+ table="PersonAddress"
+ cascade="persist">
+ <key column="personId"/>
+ <list-index column="sortOrder"/>
+ <many-to-many column="addressId" class="Address"/>
+</array>]]></programlisting>
+
+ <para>
+ A map from string indices to dates:
+ </para>
+
+ <programlisting><![CDATA[<map name="holidays"
+ table="holidays"
+ schema="dbo"
+ order-by="hol_name asc">
+ <key column="id"/>
+ <map-key column="hol_name" type="string"/>
+ <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+ <para>
+ A list of components (discussed in the next chapter):
+ </para>
+
+ <programlisting><![CDATA[<list name="carComponents"
+ table="CarComponents">
+ <key column="carId"/>
+ <list-index column="sortOrder"/>
+ <composite-element class="CarComponent">
+ <property name="price"/>
+ <property name="type"/>
+ <property name="serialNumber" column="serialNum"/>
+ </composite-element>
+</list>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="collections-onetomany">
+ <title>One-to-many associations</title>
+
+ <para>
+ A <emphasis>one to many association</emphasis> links the tables of two classes
+ via a foreign key, with no intervening collection table. This mapping loses
+ certain semantics of normal Java collections:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ An instance of the contained entity class may not belong to more than
+ one instance of the collection
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ An instance of the contained entity class may not appear at more than
+ one value of the collection index
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ An association from <literal>Product</literal> to <literal>Part</literal> requires
+ existence of a foreign key column and possibly an index column to the <literal>Part</literal>
+ table. A <literal><one-to-many></literal> tag indicates that this is a one to many
+ association.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="onetomany1" coords="2 60"/>
+ <area id="onetomany2" coords="3 60"/>
+ <area id="onetomany3" coords="4 60"/>
+ </areaspec>
+ <programlisting><![CDATA[<one-to-many
+ class="ClassName"
+ not-found="ignore|exception"
+ entity-name="EntityName"
+ node="element-name"
+ embed-xml="true|false"
+ />]]></programlisting>
+ <calloutlist>
+ <callout arearefs="onetomany1">
+ <para>
+ <literal>class</literal> (required): The name of the associated class.
+ </para>
+ </callout>
+ <callout arearefs="onetomany2">
+ <para>
+ <literal>not-found</literal> (optional - defaults to <literal>exception</literal>):
+ Specifies how cached identifiers that reference missing rows will be handled:
+ <literal>ignore</literal> will treat a missing row as a null association.
+ </para>
+ </callout>
+ <callout arearefs="onetomany3">
+ <para>
+ <literal>entity-name</literal> (optional): The entity name of the associated class,
+ as an alternative to <literal>class</literal>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Notice that the <literal><one-to-many></literal> element does not need to
+ declare any columns. Nor is it necessary to specify the <literal>table</literal>
+ name anywhere.
+ </para>
+
+ <para>
+ <emphasis>Very important note:</emphasis> If the foreign key column of a
+ <literal><one-to-many></literal> association is declared <literal>NOT NULL</literal>,
+ you must declare the <literal><key></literal> mapping
+ <literal>not-null="true"</literal> or <emphasis>use a bidirectional association</emphasis>
+ with the collection mapping marked <literal>inverse="true"</literal>. See the discussion
+ of bidirectional associations later in this chapter.
+ </para>
+
+ <para>
+ This example shows a map of <literal>Part</literal> entities by name (where
+ <literal>partName</literal> is a persistent property of <literal>Part</literal>).
+ Notice the use of a formula-based index.
+ </para>
+
+ <programlisting><![CDATA[<map name="parts"
+ cascade="all">
+ <key column="productId" not-null="true"/>
+ <map-key formula="partName"/>
+ <one-to-many class="Part"/>
+</map>]]></programlisting>
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="collections-advancedmappings">
+ <title>Advanced collection mappings</title>
+
+ <sect2 id="collections-sorted" revision="2">
+ <title>Sorted collections</title>
+
+ <para>
+ Hibernate supports collections implementing <literal>java.util.SortedMap</literal> and
+ <literal>java.util.SortedSet</literal>. You must specify a comparator in the mapping file:
+ </para>
+
+ <programlisting><![CDATA[<set name="aliases"
+ table="person_aliases"
+ sort="natural">
+ <key column="person"/>
+ <element column="name" type="string"/>
+</set>
+
+<map name="holidays" sort="my.custom.HolidayComparator">
+ <key column="year_id"/>
+ <map-key column="hol_name" type="string"/>
+ <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+ <para>
+ Allowed values of the <literal>sort</literal> attribute are <literal>unsorted</literal>,
+ <literal>natural</literal> and the name of a class implementing
+ <literal>java.util.Comparator</literal>.
+ </para>
+
+ <para>
+ Sorted collections actually behave like <literal>java.util.TreeSet</literal> or
+ <literal>java.util.TreeMap</literal>.
+ </para>
+
+ <para>
+ If you want the database itself to order the collection elements use the
+ <literal>order-by</literal> attribute of <literal>set</literal>, <literal>bag</literal>
+ or <literal>map</literal> mappings. This solution is only available under
+ JDK 1.4 or higher (it is implemented using <literal>LinkedHashSet</literal> or
+ <literal>LinkedHashMap</literal>). This performs the ordering in the SQL query,
+ not in memory.
+ </para>
+
+ <programlisting><![CDATA[<set name="aliases" table="person_aliases" order-by="lower(name) asc">
+ <key column="person"/>
+ <element column="name" type="string"/>
+</set>
+
+<map name="holidays" order-by="hol_date, hol_name">
+ <key column="year_id"/>
+ <map-key column="hol_name" type="string"/>
+ <element column="hol_date type="date"/>
+</map>]]></programlisting>
+
+ <para>
+ Note that the value of the <literal>order-by</literal> attribute is an SQL ordering, not
+ a HQL ordering!
+ </para>
+
+ <para>
+ Associations may even be sorted by some arbitrary criteria at runtime using a collection
+ <literal>filter()</literal>.
+ </para>
+
+ <programlisting><![CDATA[sortedUsers = s.createFilter( group.getUsers(), "order by this.name" ).list();]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="collections-bidirectional" revision="1">
+ <title>Bidirectional associations</title>
+
+ <para>
+ A <emphasis>bidirectional association</emphasis> allows navigation from both
+ "ends" of the association. Two kinds of bidirectional association are
+ supported:
+
+ <variablelist>
+ <varlistentry>
+ <term>one-to-many</term>
+ <listitem>
+ <para>
+ set or bag valued at one end, single-valued at the other
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>many-to-many</term>
+ <listitem>
+ <para>
+ set or bag valued at both ends
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </para>
+
+ <para>
+ You may specify a bidirectional many-to-many association simply by mapping two
+ many-to-many associations to the same database table and declaring one end as
+ <emphasis>inverse</emphasis> (which one is your choice, but it can not be an
+ indexed collection).
+ </para>
+
+ <para>
+ Here's an example of a bidirectional many-to-many association; each category can
+ have many items and each item can be in many categories:
+ </para>
+
+ <programlisting><![CDATA[<class name="Category">
+ <id name="id" column="CATEGORY_ID"/>
+ ...
+ <bag name="items" table="CATEGORY_ITEM">
+ <key column="CATEGORY_ID"/>
+ <many-to-many class="Item" column="ITEM_ID"/>
+ </bag>
+</class>
+
+<class name="Item">
+ <id name="id" column="CATEGORY_ID"/>
+ ...
+
+ <!-- inverse end -->
+ <bag name="categories" table="CATEGORY_ITEM" inverse="true">
+ <key column="ITEM_ID"/>
+ <many-to-many class="Category" column="CATEGORY_ID"/>
+ </bag>
+</class>]]></programlisting>
+
+ <para>
+ Changes made only to the inverse end of the association are <emphasis>not</emphasis>
+ persisted. This means that Hibernate has two representations in memory for every
+ bidirectional association, one link from A to B and another link from B to A. This
+ is easier to understand if you think about the Java object model and how we create
+ a many-to-many relationship in Java:
+ </para>
+
+ <programlisting><![CDATA[
+category.getItems().add(item); // The category now "knows" about the relationship
+item.getCategories().add(category); // The item now "knows" about the relationship
+
+session.persist(item); // The relationship won't be saved!
+session.persist(category); // The relationship will be saved]]></programlisting>
+
+ <para>
+ The non-inverse side is used to save the in-memory representation to the database.
+ </para>
+
+ <para>
+ You may define a bidirectional one-to-many association by mapping a one-to-many association
+ to the same table column(s) as a many-to-one association and declaring the many-valued
+ end <literal>inverse="true"</literal>.
+ </para>
+
+ <programlisting><![CDATA[<class name="Parent">
+ <id name="id" column="parent_id"/>
+ ....
+ <set name="children" inverse="true">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+ </set>
+</class>
+
+<class name="Child">
+ <id name="id" column="child_id"/>
+ ....
+ <many-to-one name="parent"
+ class="Parent"
+ column="parent_id"
+ not-null="true"/>
+</class>]]></programlisting>
+
+ <para>
+ Mapping one end of an association with <literal>inverse="true"</literal> doesn't
+ affect the operation of cascades, these are orthogonal concepts!
+ </para>
+
+ </sect2>
+
+ <sect2 id="collections-indexedbidirectional">
+ <title>Bidirectional associations with indexed collections</title>
+ <para>
+ A bidirectional association where one end is represented as a <literal><list></literal>
+ or <literal><map></literal> requires special consideration. If there is a property of
+ the child class which maps to the index column, no problem, we can continue using
+ <literal>inverse="true"</literal> on the collection mapping:
+ </para>
+
+ <programlisting><![CDATA[<class name="Parent">
+ <id name="id" column="parent_id"/>
+ ....
+ <map name="children" inverse="true">
+ <key column="parent_id"/>
+ <map-key column="name"
+ type="string"/>
+ <one-to-many class="Child"/>
+ </map>
+</class>
+
+<class name="Child">
+ <id name="id" column="child_id"/>
+ ....
+ <property name="name"
+ not-null="true"/>
+ <many-to-one name="parent"
+ class="Parent"
+ column="parent_id"
+ not-null="true"/>
+</class>]]></programlisting>
+
+ <para>
+ But, if there is no such property on the child class, we can't think of the association as
+ truly bidirectional (there is information available at one end of the association that is
+ not available at the other end). In this case, we can't map the collection
+ <literal>inverse="true"</literal>. Instead, we could use the following mapping:
+ </para>
+
+ <programlisting><![CDATA[<class name="Parent">
+ <id name="id" column="parent_id"/>
+ ....
+ <map name="children">
+ <key column="parent_id"
+ not-null="true"/>
+ <map-key column="name"
+ type="string"/>
+ <one-to-many class="Child"/>
+ </map>
+</class>
+
+<class name="Child">
+ <id name="id" column="child_id"/>
+ ....
+ <many-to-one name="parent"
+ class="Parent"
+ column="parent_id"
+ insert="false"
+ update="false"
+ not-null="true"/>
+</class>]]></programlisting>
+
+ <para>
+ Note that in this mapping, the collection-valued end of the association is responsible for
+ updates to the foreign key. TODO: Does this really result in some unnecessary update statements?
+ </para>
+
+ </sect2>
+
+ <sect2 id="collections-ternary">
+ <title>Ternary associations</title>
+
+ <para>
+ There are three possible approaches to mapping a ternary association. One is to use a
+ <literal>Map</literal> with an association as its index:
+ </para>
+
+ <programlisting><![CDATA[<map name="contracts">
+ <key column="employer_id" not-null="true"/>
+ <map-key-many-to-many column="employee_id" class="Employee"/>
+ <one-to-many class="Contract"/>
+</map>]]></programlisting>
+
+ <programlisting><![CDATA[<map name="connections">
+ <key column="incoming_node_id"/>
+ <map-key-many-to-many column="outgoing_node_id" class="Node"/>
+ <many-to-many column="connection_id" class="Connection"/>
+</map>]]></programlisting>
+
+ <para>
+ A second approach is to simply remodel the association as an entity class. This
+ is the approach we use most commonly.
+ </para>
+
+ <para>
+ A final alternative is to use composite elements, which we will discuss later.
+ </para>
+
+ </sect2>
+
+ <sect2 id="collections-idbag" revision="1">
+ <title><literal>Using an <idbag></literal></title>
+
+ <para>
+ If you've fully embraced our view that composite keys are a bad thing and that
+ entities should have synthetic identifiers (surrogate keys), then you might
+ find it a bit odd that the many to many associations and collections of values
+ that we've shown so far all map to tables with composite keys! Now, this point
+ is quite arguable; a pure association table doesn't seem to benefit much from
+ a surrogate key (though a collection of composite values <emphasis>might</emphasis>).
+ Nevertheless, Hibernate provides a feature that allows you to map many to many
+ associations and collections of values to a table with a surrogate key.
+ </para>
+
+ <para>
+ The <literal><idbag></literal> element lets you map a <literal>List</literal>
+ (or <literal>Collection</literal>) with bag semantics.
+ </para>
+
+<programlisting><![CDATA[<idbag name="lovers" table="LOVERS">
+ <collection-id column="ID" type="long">
+ <generator class="sequence"/>
+ </collection-id>
+ <key column="PERSON1"/>
+ <many-to-many column="PERSON2" class="Person" fetch="join"/>
+</idbag>]]></programlisting>
+
+ <para>
+ As you can see, an <literal><idbag></literal> has a synthetic id generator,
+ just like an entity class! A different surrogate key is assigned to each collection
+ row. Hibernate does not provide any mechanism to discover the surrogate key value
+ of a particular row, however.
+ </para>
+
+ <para>
+ Note that the update performance of an <literal><idbag></literal> is
+ <emphasis>much</emphasis> better than a regular <literal><bag></literal>!
+ Hibernate can locate individual rows efficiently and update or delete them
+ individually, just like a list, map or set.
+ </para>
+
+ <para>
+ In the current implementation, the <literal>native</literal> identifier generation
+ strategy is not supported for <literal><idbag></literal> collection identifiers.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <!--undocumenting this stuff -->
+
+ <!--sect1 id="collections-heterogeneous">
+ <title>Heterogeneous Associations</title>
+
+ <para>
+ The <literal><many-to-any></literal> and <literal><index-many-to-any></literal>
+ elements provide for true heterogeneous associations. These mapping elements work in the
+ same way as the <literal><any></literal> element - and should also be used
+ rarely, if ever.
+ </para>
+
+ </sect1-->
+
+ <sect1 id="collections-example" revision="1">
+ <title>Collection examples</title>
+
+ <para>
+ The previous sections are pretty confusing. So lets look at an example. This
+ class:
+ </para>
+
+ <programlisting><![CDATA[package eg;
+import java.util.Set;
+
+public class Parent {
+ private long id;
+ private Set children;
+
+ public long getId() { return id; }
+ private void setId(long id) { this.id=id; }
+
+ private Set getChildren() { return children; }
+ private void setChildren(Set children) { this.children=children; }
+
+ ....
+ ....
+}]]></programlisting>
+
+ <para>
+ has a collection of <literal>Child</literal> instances. If each
+ child has at most one parent, the most natural mapping is a
+ one-to-many association:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Parent">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <set name="children">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+ </set>
+ </class>
+
+ <class name="Child">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <property name="name"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ This maps to the following table definitions:
+ </para>
+
+ <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255), parent_id bigint )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+ <para>
+ If the parent is <emphasis>required</emphasis>, use a bidirectional one-to-many
+ association:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Parent">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <set name="children" inverse="true">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+ </set>
+ </class>
+
+ <class name="Child">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <property name="name"/>
+ <many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Notice the <literal>NOT NULL</literal> constraint:
+ </para>
+
+ <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null
+ primary key,
+ name varchar(255),
+ parent_id bigint not null )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+ <para>
+ Alternatively, if you absolutely insist that this association should be unidirectional,
+ you can declare the <literal>NOT NULL</literal> constraint on the <literal><key></literal>
+ mapping:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Parent">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <set name="children">
+ <key column="parent_id" not-null="true"/>
+ <one-to-many class="Child"/>
+ </set>
+ </class>
+
+ <class name="Child">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <property name="name"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ On the other hand, if a child might have multiple parents, a many-to-many
+ association is appropriate:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Parent">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <set name="children" table="childset">
+ <key column="parent_id"/>
+ <many-to-many class="Child" column="child_id"/>
+ </set>
+ </class>
+
+ <class name="Child">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <property name="name"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Table definitions:
+ </para>
+
+ <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255) )
+create table childset ( parent_id bigint not null,
+ child_id bigint not null,
+ primary key ( parent_id, child_id ) )
+alter table childset add constraint childsetfk0 (parent_id) references parent
+alter table childset add constraint childsetfk1 (child_id) references child]]></programlisting>
+
+ <para>
+ For more examples and a complete walk-through a parent/child relationship mapping,
+ see <xref linkend="example-parentchild"/>.
+ </para>
+
+ <para>
+ Even more exotic association mappings are possible, we will catalog all possibilities
+ in the next chapter.
+ </para>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/component_mapping.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/component_mapping.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/component_mapping.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,404 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="components">
+ <title>Component Mapping</title>
+
+ <para>
+ The notion of a <emphasis>component</emphasis> is re-used in several different contexts,
+ for different purposes, throughout Hibernate.
+ </para>
+
+ <sect1 id="components-dependentobjects" revision="2" >
+ <title>Dependent objects</title>
+
+ <para>
+ A component is a contained object that is persisted as a value type, not an entity
+ reference. The term "component" refers to the object-oriented notion of composition
+ (not to architecture-level components). For example, you might model a person like this:
+ </para>
+
+ <programlisting><![CDATA[public class Person {
+ private java.util.Date birthday;
+ private Name name;
+ private String key;
+ public String getKey() {
+ return key;
+ }
+ private void setKey(String key) {
+ this.key=key;
+ }
+ public java.util.Date getBirthday() {
+ return birthday;
+ }
+ public void setBirthday(java.util.Date birthday) {
+ this.birthday = birthday;
+ }
+ public Name getName() {
+ return name;
+ }
+ public void setName(Name name) {
+ this.name = name;
+ }
+ ......
+ ......
+}]]></programlisting>
+
+<programlisting><![CDATA[public class Name {
+ char initial;
+ String first;
+ String last;
+ public String getFirst() {
+ return first;
+ }
+ void setFirst(String first) {
+ this.first = first;
+ }
+ public String getLast() {
+ return last;
+ }
+ void setLast(String last) {
+ this.last = last;
+ }
+ public char getInitial() {
+ return initial;
+ }
+ void setInitial(char initial) {
+ this.initial = initial;
+ }
+}]]></programlisting>
+
+ <para>
+ Now <literal>Name</literal> may be persisted as a component of
+ <literal>Person</literal>. Notice that <literal>Name</literal> defines getter
+ and setter methods for its persistent properties, but doesn't need to declare
+ any interfaces or identifier properties.
+ </para>
+
+ <para>
+ Our Hibernate mapping would look like:
+ </para>
+
+ <programlisting><![CDATA[<class name="eg.Person" table="person">
+ <id name="Key" column="pid" type="string">
+ <generator class="uuid"/>
+ </id>
+ <property name="birthday" type="date"/>
+ <component name="Name" class="eg.Name"> <!-- class attribute optional -->
+ <property name="initial"/>
+ <property name="first"/>
+ <property name="last"/>
+ </component>
+</class>]]></programlisting>
+
+ <para>
+ The person table would have the columns <literal>pid</literal>,
+ <literal>birthday</literal>,
+ <literal>initial</literal>,
+ <literal>first</literal> and
+ <literal>last</literal>.
+ </para>
+
+ <para>
+ Like all value types, components do not support shared references. In other words, two
+ persons could have the same name, but the two person objects would contain two independent
+ name ojects, only "the same" by value. The null value semantics of a component are
+ <emphasis>ad hoc</emphasis>. When reloading the containing object, Hibernate will assume
+ that if all component columns are null, then the entire component is null. This should
+ be okay for most purposes.
+ </para>
+
+ <para>
+ The properties of a component may be of any Hibernate type (collections, many-to-one
+ associations, other components, etc). Nested components should <emphasis>not</emphasis>
+ be considered an exotic usage. Hibernate is intended to support a very fine-grained
+ object model.
+ </para>
+
+ <para>
+ The <literal><component></literal> element allows a <literal><parent></literal>
+ subelement that maps a property of the component class as a reference back to the
+ containing entity.
+ </para>
+
+ <programlisting><![CDATA[<class name="eg.Person" table="person">
+ <id name="Key" column="pid" type="string">
+ <generator class="uuid"/>
+ </id>
+ <property name="birthday" type="date"/>
+ <component name="Name" class="eg.Name" unique="true">
+ <parent name="namedPerson"/> <!-- reference back to the Person -->
+ <property name="initial"/>
+ <property name="first"/>
+ <property name="last"/>
+ </component>
+</class>]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="components-incollections" revision="1">
+ <title>Collections of dependent objects</title>
+
+ <para>
+ Collections of components are supported (eg. an array of type
+ <literal>Name</literal>). Declare your component collection by
+ replacing the <literal><element></literal> tag with a
+ <literal><composite-element></literal> tag.
+ </para>
+
+ <programlisting><![CDATA[<set name="someNames" table="some_names" lazy="true">
+ <key column="id"/>
+ <composite-element class="eg.Name"> <!-- class attribute required -->
+ <property name="initial"/>
+ <property name="first"/>
+ <property name="last"/>
+ </composite-element>
+</set>]]></programlisting>
+
+ <para>
+ Note: if you define a <literal>Set</literal> of composite elements, it is
+ very important to implement <literal>equals()</literal> and
+ <literal>hashCode()</literal> correctly.
+ </para>
+
+ <para>
+ Composite elements may contain components but not collections. If your
+ composite element itself contains
+ components, use the <literal><nested-composite-element></literal>
+ tag. This is a pretty exotic case - a collection of components which
+ themselves have components. By this stage you should be asking yourself
+ if a one-to-many association is more appropriate. Try remodelling the
+ composite element as an entity - but note that even though the Java model
+ is the same, the relational model and persistence semantics are still
+ slightly different.
+ </para>
+
+ <para>
+ Please note that a composite element mapping doesn't support null-able properties
+ if you're using a <literal><set></literal>. Hibernate
+ has to use each columns value to identify a record when deleting objects
+ (there is no separate primary key column in the composite element table),
+ which is not possible with null values. You have to either use only
+ not-null properties in a composite-element or choose a
+ <literal><list></literal>, <literal><map></literal>,
+ <literal><bag></literal> or <literal><idbag></literal>.
+ </para>
+
+ <para>
+ A special case of a composite element is a composite element with a nested
+ <literal><many-to-one></literal> element. A mapping like this allows
+ you to map extra columns of a many-to-many association table to the
+ composite element class. The following is a many-to-many association
+ from <literal>Order</literal> to <literal>Item</literal> where
+ <literal>purchaseDate</literal>, <literal>price</literal> and
+ <literal>quantity</literal> are properties of the association:
+ </para>
+
+ <programlisting><![CDATA[<class name="eg.Order" .... >
+ ....
+ <set name="purchasedItems" table="purchase_items" lazy="true">
+ <key column="order_id">
+ <composite-element class="eg.Purchase">
+ <property name="purchaseDate"/>
+ <property name="price"/>
+ <property name="quantity"/>
+ <many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
+ </composite-element>
+ </set>
+</class>]]></programlisting>
+
+ <para>
+ Of course, there can't be a reference to the purchae on the other side, for
+ bidirectional association navigation. Remember that components are value types and
+ don't allow shared references. A single <literal>Purchase</literal> can be in the
+ set of an <literal>Order</literal>, but it can't be referenced by the <literal>Item</literal>
+ at the same time.
+ </para>
+
+ <para>Even ternary (or quaternary, etc) associations are possible:</para>
+
+ <programlisting><![CDATA[<class name="eg.Order" .... >
+ ....
+ <set name="purchasedItems" table="purchase_items" lazy="true">
+ <key column="order_id">
+ <composite-element class="eg.OrderLine">
+ <many-to-one name="purchaseDetails class="eg.Purchase"/>
+ <many-to-one name="item" class="eg.Item"/>
+ </composite-element>
+ </set>
+</class>]]></programlisting>
+
+ <para>
+ Composite elements may appear in queries using the same syntax as
+ associations to other entities.
+ </para>
+
+ </sect1>
+
+ <sect1 id="components-asmapindex">
+ <title>Components as Map indices</title>
+
+ <para>
+ The <literal><composite-map-key></literal> element lets you map a
+ component class as the key of a <literal>Map</literal>. Make sure you override
+ <literal>hashCode()</literal> and <literal>equals()</literal> correctly on
+ the component class.
+ </para>
+ </sect1>
+
+ <sect1 id="components-compositeid" revision="1">
+ <title>Components as composite identifiers</title>
+
+ <para>
+ You may use a component as an identifier of an entity class. Your component
+ class must satisfy certain requirements:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ It must implement <literal>java.io.Serializable</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ It must re-implement <literal>equals()</literal> and
+ <literal>hashCode()</literal>, consistently with the database's
+ notion of composite key equality.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ <emphasis>Note: in Hibernate3, the second requirement is not an absolutely hard
+ requirement of Hibernate. But do it anyway.</emphasis>
+ </para>
+
+ <para>
+ You can't use an <literal>IdentifierGenerator</literal> to generate composite keys.
+ Instead the application must assign its own identifiers.
+ </para>
+
+ <para>
+ Use the <literal><composite-id></literal> tag (with nested
+ <literal><key-property></literal> elements) in place of the usual
+ <literal><id></literal> declaration. For example, the
+ <literal>OrderLine</literal> class has a primary key that depends upon
+ the (composite) primary key of <literal>Order</literal>.
+ </para>
+
+ <programlisting><![CDATA[<class name="OrderLine">
+
+ <composite-id name="id" class="OrderLineId">
+ <key-property name="lineId"/>
+ <key-property name="orderId"/>
+ <key-property name="customerId"/>
+ </composite-id>
+
+ <property name="name"/>
+
+ <many-to-one name="order" class="Order"
+ insert="false" update="false">
+ <column name="orderId"/>
+ <column name="customerId"/>
+ </many-to-one>
+ ....
+
+</class>]]></programlisting>
+
+ <para>
+ Now, any foreign keys referencing the <literal>OrderLine</literal> table are also
+ composite. You must declare this in your mappings for other classes. An association
+ to <literal>OrderLine</literal> would be mapped like this:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
+<!-- the "class" attribute is optional, as usual -->
+ <column name="lineId"/>
+ <column name="orderId"/>
+ <column name="customerId"/>
+</many-to-one>]]></programlisting>
+
+ <para>
+ (Note that the <literal><column></literal> tag is an alternative to the
+ <literal>column</literal> attribute everywhere.)
+ </para>
+
+ <para>
+ A <literal>many-to-many</literal> association to <literal>OrderLine</literal> also
+ uses the composite foreign key:
+ </para>
+
+ <programlisting><![CDATA[<set name="undeliveredOrderLines">
+ <key column name="warehouseId"/>
+ <many-to-many class="OrderLine">
+ <column name="lineId"/>
+ <column name="orderId"/>
+ <column name="customerId"/>
+ </many-to-many>
+</set>]]></programlisting>
+
+ <para>
+ The collection of <literal>OrderLine</literal>s in <literal>Order</literal> would
+ use:
+ </para>
+
+ <programlisting><![CDATA[<set name="orderLines" inverse="true">
+ <key>
+ <column name="orderId"/>
+ <column name="customerId"/>
+ </key>
+ <one-to-many class="OrderLine"/>
+</set>]]></programlisting>
+
+ <para>
+ (The <literal><one-to-many></literal> element, as usual, declares no columns.)
+ </para>
+
+ <para>
+ If <literal>OrderLine</literal> itself owns a collection, it also has a composite
+ foreign key.
+ </para>
+
+ <programlisting><![CDATA[<class name="OrderLine">
+ ....
+ ....
+ <list name="deliveryAttempts">
+ <key> <!-- a collection inherits the composite key type -->
+ <column name="lineId"/>
+ <column name="orderId"/>
+ <column name="customerId"/>
+ </key>
+ <list-index column="attemptId" base="1"/>
+ <composite-element class="DeliveryAttempt">
+ ...
+ </composite-element>
+ </set>
+</class>]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="components-dynamic" revision="1">
+ <title>Dynamic components</title>
+
+ <para>
+ You may even map a property of type <literal>Map</literal>:
+ </para>
+
+ <programlisting><![CDATA[<dynamic-component name="userAttributes">
+ <property name="foo" column="FOO" type="string"/>
+ <property name="bar" column="BAR" type="integer"/>
+ <many-to-one name="baz" class="Baz" column="BAZ_ID"/>
+</dynamic-component>]]></programlisting>
+
+ <para>
+ The semantics of a <literal><dynamic-component></literal> mapping are identical
+ to <literal><component></literal>. The advantage of this kind of mapping is
+ the ability to determine the actual properties of the bean at deployment time, just
+ by editing the mapping document. Runtime manipulation of the mapping document is
+ also possible, using a DOM parser. Even better, you can access (and change) Hibernate's
+ configuration-time metamodel via the <literal>Configuration</literal> object.
+ </para>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/configuration.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/configuration.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/configuration.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,1740 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="session-configuration" revision="1">
+
+ <title>Configuration</title>
+
+ <para>
+ Because Hibernate is designed to operate in many different environments, there
+ are a large number of configuration parameters. Fortunately, most have sensible
+ default values and Hibernate is distributed with an example
+ <literal>hibernate.properties</literal> file in <literal>etc/</literal> that shows
+ the various options. Just put the example file in your classpath and customize it.
+ </para>
+
+ <sect1 id="configuration-programmatic" revision="1">
+ <title>Programmatic configuration</title>
+
+ <para>
+ An instance of <literal>org.hibernate.cfg.Configuration</literal>
+ represents an entire set of mappings of an application's Java types to an
+ SQL database. The <literal>Configuration</literal> is used to build an
+ (immutable) <literal>SessionFactory</literal>. The mappings are compiled
+ from various XML mapping files.
+ </para>
+
+ <para>
+ You may obtain a <literal>Configuration</literal> instance by instantiating
+ it directly and specifying XML mapping documents. If the mapping files are
+ in the classpath, use <literal>addResource()</literal>:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = new Configuration()
+ .addResource("Item.hbm.xml")
+ .addResource("Bid.hbm.xml");]]></programlisting>
+
+ <para>
+ An alternative (sometimes better) way is to specify the mapped class, and
+ let Hibernate find the mapping document for you:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = new Configuration()
+ .addClass(org.hibernate.auction.Item.class)
+ .addClass(org.hibernate.auction.Bid.class);]]></programlisting>
+
+ <para>
+ Then Hibernate will look for mapping files named
+ <literal>/org/hibernate/auction/Item.hbm.xml</literal> and
+ <literal>/org/hibernate/auction/Bid.hbm.xml</literal> in the classpath.
+ This approach eliminates any hardcoded filenames.
+ </para>
+
+ <para>
+ A <literal>Configuration</literal> also allows you to specify configuration
+ properties:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = new Configuration()
+ .addClass(org.hibernate.auction.Item.class)
+ .addClass(org.hibernate.auction.Bid.class)
+ .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
+ .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
+ .setProperty("hibernate.order_updates", "true");]]></programlisting>
+
+ <para>
+ This is not the only way to pass configuration properties to Hibernate.
+ The various options include:
+ </para>
+
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ Pass an instance of <literal>java.util.Properties</literal> to
+ <literal>Configuration.setProperties()</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Place <literal>hibernate.properties</literal> in a root directory
+ of the classpath.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Set <literal>System</literal> properties using
+ <literal>java -Dproperty=value</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Include <literal><property></literal> elements in
+ <literal>hibernate.cfg.xml</literal> (discussed later).
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ <literal>hibernate.properties</literal> is the easiest approach if you
+ want to get started quickly.
+ </para>
+
+ <para>
+ The <literal>Configuration</literal> is intended as a startup-time object,
+ to be discarded once a <literal>SessionFactory</literal> is created.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-sessionfactory">
+ <title>Obtaining a SessionFactory</title>
+
+ <para>
+ When all mappings have been parsed by the <literal>Configuration</literal>,
+ the application must obtain a factory for <literal>Session</literal> instances.
+ This factory is intended to be shared by all application threads:
+ </para>
+
+ <programlisting><![CDATA[SessionFactory sessions = cfg.buildSessionFactory();]]></programlisting>
+
+ <para>
+ Hibernate does allow your application to instantiate more than one
+ <literal>SessionFactory</literal>. This is useful if you are using more than
+ one database.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-hibernatejdbc" revision="1">
+ <title>JDBC connections</title>
+
+ <para>
+ Usually, you want to have the <literal>SessionFactory</literal> create and pool JDBC
+ connections for you. If you take this approach, opening a <literal>Session</literal>
+ is as simple as:
+ </para>
+
+ <programlisting><![CDATA[Session session = sessions.openSession(); // open a new Session]]></programlisting>
+
+ <para>
+ As soon as you do something that requires access to the database, a JDBC connection
+ will be obtained from the pool.
+ </para>
+
+ <para>
+ For this to work, we need to pass some JDBC connection properties to Hibernate.
+ All Hibernate property names and semantics are defined on the class
+ <literal>org.hibernate.cfg.Environment</literal>. We will now describe the most
+ important settings for JDBC connection configuration.
+ </para>
+
+ <para>
+ Hibernate will obtain (and pool) connections using <literal>java.sql.DriverManager</literal>
+ if you set the following properties:
+ </para>
+
+ <table frame="topbot">
+ <title>Hibernate JDBC Properties</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Property name</entry>
+ <entry>Purpose</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.connection.driver_class</literal>
+ </entry>
+ <entry>
+ <emphasis>jdbc driver class</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.url</literal>
+ </entry>
+ <entry>
+ <emphasis>jdbc URL</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.username</literal>
+ </entry>
+ <entry>
+ <emphasis>database user</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.password</literal>
+ </entry>
+ <entry>
+ <emphasis>database user password</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.pool_size</literal>
+ </entry>
+ <entry>
+ <emphasis>maximum number of pooled connections</emphasis>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ Hibernate's own connection pooling algorithm is however quite rudimentary.
+ It is intended to help you get started and is <emphasis>not intended for use
+ in a production system</emphasis> or even for performance testing. You should
+ use a third party pool for best performance and stability. Just replace the
+ <literal>hibernate.connection.pool_size</literal> property with connection
+ pool specific settings. This will turn off Hibernate's internal pool. For
+ example, you might like to use C3P0.
+ </para>
+
+ <para>
+ C3P0 is an open source JDBC connection pool distributed along with
+ Hibernate in the <literal>lib</literal> directory. Hibernate will use its
+ <literal>C3P0ConnectionProvider</literal> for connection pooling if you set
+ <literal>hibernate.c3p0.*</literal> properties. If you'd like to use Proxool
+ refer to the packaged <literal>hibernate.properties</literal> and the Hibernate
+ web site for more information.
+ </para>
+
+ <para>
+ Here is an example <literal>hibernate.properties</literal> file for C3P0:
+ </para>
+
+ <programlisting id="c3p0-configuration" revision="1"><![CDATA[hibernate.connection.driver_class = org.postgresql.Driver
+hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
+hibernate.connection.username = myuser
+hibernate.connection.password = secret
+hibernate.c3p0.min_size=5
+hibernate.c3p0.max_size=20
+hibernate.c3p0.timeout=1800
+hibernate.c3p0.max_statements=50
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+ <para>
+ For use inside an application server, you should almost always configure
+ Hibernate to obtain connections from an application server
+ <literal>Datasource</literal> registered in JNDI. You'll need to set at
+ least one of the following properties:
+ </para>
+
+ <table frame="topbot">
+ <title>Hibernate Datasource Properties</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Propery name</entry>
+ <entry>Purpose</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.connection.datasource</literal>
+ </entry>
+ <entry>
+ <emphasis>datasource JNDI name</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jndi.url</literal>
+ </entry>
+ <entry>
+ <emphasis>URL of the JNDI provider</emphasis> (optional)
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jndi.class</literal>
+ </entry>
+ <entry>
+ <emphasis>class of the JNDI <literal>InitialContextFactory</literal></emphasis> (optional)
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.username</literal>
+ </entry>
+ <entry>
+ <emphasis>database user</emphasis> (optional)
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.password</literal>
+ </entry>
+ <entry>
+ <emphasis>database user password</emphasis> (optional)
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ Here's an example <literal>hibernate.properties</literal> file for an
+ application server provided JNDI datasource:
+ </para>
+
+ <programlisting><![CDATA[hibernate.connection.datasource = java:/comp/env/jdbc/test
+hibernate.transaction.factory_class = \
+ org.hibernate.transaction.JTATransactionFactory
+hibernate.transaction.manager_lookup_class = \
+ org.hibernate.transaction.JBossTransactionManagerLookup
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+ <para>
+ JDBC connections obtained from a JNDI datasource will automatically participate
+ in the container-managed transactions of the application server.
+ </para>
+
+ <para>
+ Arbitrary connection properties may be given by prepending
+ "<literal>hibernate.connnection</literal>" to the property name. For example, you
+ may specify a <literal>charSet</literal> using <literal>hibernate.connection.charSet</literal>.
+ </para>
+
+ <para>
+ You may define your own plugin strategy for obtaining JDBC connections by implementing the
+ interface <literal>org.hibernate.connection.ConnectionProvider</literal>. You may select
+ a custom implementation by setting <literal>hibernate.connection.provider_class</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-optional" revision="1">
+ <title>Optional configuration properties</title>
+
+ <para>
+ There are a number of other properties that control the behaviour of Hibernate
+ at runtime. All are optional and have reasonable default values.
+ </para>
+
+ <para>
+ <emphasis>Warning: some of these properties are "system-level" only.</emphasis>
+ System-level properties can be set only via <literal>java -Dproperty=value</literal> or
+ <literal>hibernate.properties</literal>. They may <emphasis>not</emphasis> be set by
+ the other techniques described above.
+ </para>
+
+ <table frame="topbot" id="configuration-optional-properties" revision="8">
+ <title>Hibernate Configuration Properties</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Property name</entry>
+ <entry>Purpose</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.dialect</literal>
+ </entry>
+ <entry>
+ The classname of a Hibernate <literal>Dialect</literal> which
+ allows Hibernate to generate SQL optimized for a particular
+ relational database.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>full.classname.of.Dialect</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.show_sql</literal>
+ </entry>
+ <entry>
+ Write all SQL statements to console. This is an alternative
+ to setting the log category <literal>org.hibernate.SQL</literal>
+ to <literal>debug</literal>.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.format_sql</literal>
+ </entry>
+ <entry>
+ Pretty print the SQL in the log and console.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.default_schema</literal>
+ </entry>
+ <entry>
+ Qualify unqualified tablenames with the given schema/tablespace
+ in generated SQL.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>SCHEMA_NAME</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.default_catalog</literal>
+ </entry>
+ <entry>
+ Qualify unqualified tablenames with the given catalog
+ in generated SQL.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>CATALOG_NAME</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.session_factory_name</literal>
+ </entry>
+ <entry>
+ The <literal>SessionFactory</literal> will be automatically
+ bound to this name in JNDI after it has been created.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>jndi/composite/name</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.max_fetch_depth</literal>
+ </entry>
+ <entry>
+ Set a maximum "depth" for the outer join fetch tree
+ for single-ended associations (one-to-one, many-to-one).
+ A <literal>0</literal> disables default outer join fetching.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ recommended values between <literal>0</literal> and
+ <literal>3</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.default_batch_fetch_size</literal>
+ </entry>
+ <entry>
+ Set a default size for Hibernate batch fetching of associations.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ recommended values <literal>4</literal>, <literal>8</literal>,
+ <literal>16</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.default_entity_mode</literal>
+ </entry>
+ <entry>
+ Set a default mode for entity representation for all sessions
+ opened from this <literal>SessionFactory</literal>
+ <para>
+ <literal>dynamic-map</literal>, <literal>dom4j</literal>,
+ <literal>pojo</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.order_updates</literal>
+ </entry>
+ <entry>
+ Force Hibernate to order SQL updates by the primary key value
+ of the items being updated. This will result in fewer transaction
+ deadlocks in highly concurrent systems.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.generate_statistics</literal>
+ </entry>
+ <entry>
+ If enabled, Hibernate will collect statistics useful for
+ performance tuning.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.use_identifer_rollback</literal>
+ </entry>
+ <entry>
+ If enabled, generated identifier properties will be
+ reset to default values when objects are deleted.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.use_sql_comments</literal>
+ </entry>
+ <entry>
+ If turned on, Hibernate will generate comments inside the SQL, for
+ easier debugging, defaults to <literal>false</literal>.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot" id="configuration-jdbc-properties" revision="8">
+ <title>Hibernate JDBC and Connection Properties</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Property name</entry>
+ <entry>Purpose</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.fetch_size</literal>
+ </entry>
+ <entry>
+ A non-zero value determines the JDBC fetch size (calls
+ <literal>Statement.setFetchSize()</literal>).
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.batch_size</literal>
+ </entry>
+ <entry>
+ A non-zero value enables use of JDBC2 batch updates by Hibernate.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ recommended values between <literal>5</literal> and <literal>30</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.batch_versioned_data</literal>
+ </entry>
+ <entry>
+ Set this property to <literal>true</literal> if your JDBC driver returns
+ correct row counts from <literal>executeBatch()</literal> (it is usually
+ safe to turn this option on). Hibernate will then use batched DML for
+ automatically versioned data. Defaults to <literal>false</literal>.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.factory_class</literal>
+ </entry>
+ <entry>
+ Select a custom <literal>Batcher</literal>. Most applications
+ will not need this configuration property.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>classname.of.Batcher</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.use_scrollable_resultset</literal>
+ </entry>
+ <entry>
+ Enables use of JDBC2 scrollable resultsets by Hibernate.
+ This property is only necessary when using user supplied
+ JDBC connections, Hibernate uses connection metadata otherwise.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.use_streams_for_binary</literal>
+ </entry>
+ <entry>
+ Use streams when writing/reading <literal>binary</literal>
+ or <literal>serializable</literal> types to/from JDBC
+ (system-level property).
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.use_get_generated_keys</literal>
+ </entry>
+ <entry>
+ Enable use of JDBC3 <literal>PreparedStatement.getGeneratedKeys()</literal>
+ to retrieve natively generated keys after insert. Requires JDBC3+ driver
+ and JRE1.4+, set to false if your driver has problems with the Hibernate
+ identifier generators. By default, tries to determine the driver capabilites
+ using connection metadata.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.provider_class</literal>
+ </entry>
+ <entry>
+ The classname of a custom <literal>ConnectionProvider</literal> which provides
+ JDBC connections to Hibernate.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>classname.of.ConnectionProvider</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.isolation</literal>
+ </entry>
+ <entry>
+ Set the JDBC transaction isolation level. Check
+ <literal>java.sql.Connection</literal> for meaningful values but
+ note that most databases do not support all isolation levels.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>1, 2, 4, 8</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.autocommit</literal>
+ </entry>
+ <entry>
+ Enables autocommit for JDBC pooled connections (not recommended).
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.release_mode</literal>
+ </entry>
+ <entry>
+ Specify when Hibernate should release JDBC connections. By default,
+ a JDBC connection is held until the session is explicitly closed or
+ disconnected. For an application server JTA datasource, you should use
+ <literal>after_statement</literal> to aggressively release connections
+ after every JDBC call. For a non-JTA connection, it often makes sense to
+ release the connection at the end of each transaction, by using
+ <literal>after_transaction</literal>. <literal>auto</literal> will
+ choose <literal>after_statement</literal> for the JTA and CMT transaction
+ strategies and <literal>after_transaction</literal> for the JDBC
+ transaction strategy.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>auto</literal> (default) | <literal>on_close</literal> |
+ <literal>after_transaction</literal> | <literal>after_statement</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><propertyName></emphasis></literal>
+ </entry>
+ <entry>
+ Pass the JDBC property <literal>propertyName</literal>
+ to <literal>DriverManager.getConnection()</literal>.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jndi.<emphasis><propertyName></emphasis></literal>
+ </entry>
+ <entry>
+ Pass the property <literal>propertyName</literal> to
+ the JNDI <literal>InitialContextFactory</literal>.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot" id="configuration-cache-properties" revision="7">
+ <title>Hibernate Cache Properties</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Property name</entry>
+ <entry>Purpose</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.cache.provider_class</literal>
+ </entry>
+ <entry>
+ The classname of a custom <literal>CacheProvider</literal>.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>classname.of.CacheProvider</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.use_minimal_puts</literal>
+ </entry>
+ <entry>
+ Optimize second-level cache operation to minimize writes, at the
+ cost of more frequent reads. This setting is most useful for
+ clustered caches and, in Hibernate3, is enabled by default for
+ clustered cache implementations.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.use_query_cache</literal>
+ </entry>
+ <entry>
+ Enable the query cache, individual queries still have to be set cachable.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.use_second_level_cache</literal>
+ </entry>
+ <entry>
+ May be used to completely disable the second level cache, which is enabled
+ by default for classes which specify a <literal><cache></literal>
+ mapping.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.query_cache_factory</literal>
+ </entry>
+ <entry>
+ The classname of a custom <literal>QueryCache</literal> interface,
+ defaults to the built-in <literal>StandardQueryCache</literal>.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>classname.of.QueryCache</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.region_prefix</literal>
+ </entry>
+ <entry>
+ A prefix to use for second-level cache region names.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>prefix</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.use_structured_entries</literal>
+ </entry>
+ <entry>
+ Forces Hibernate to store data in the second-level cache
+ in a more human-friendly format.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot" id="configuration-transaction-properties" revision="9">
+ <title>Hibernate Transaction Properties</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Property name</entry>
+ <entry>Purpose</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.transaction.factory_class</literal>
+ </entry>
+ <entry>
+ The classname of a <literal>TransactionFactory</literal>
+ to use with Hibernate <literal>Transaction</literal> API
+ (defaults to <literal>JDBCTransactionFactory</literal>).
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>classname.of.TransactionFactory</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>jta.UserTransaction</literal>
+ </entry>
+ <entry>
+ A JNDI name used by <literal>JTATransactionFactory</literal> to
+ obtain the JTA <literal>UserTransaction</literal> from the
+ application server.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>jndi/composite/name</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.transaction.manager_lookup_class</literal>
+ </entry>
+ <entry>
+ The classname of a <literal>TransactionManagerLookup</literal>
+ - required when JVM-level caching is enabled or when using hilo
+ generator in a JTA environment.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>classname.of.TransactionManagerLookup</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.transaction.flush_before_completion</literal>
+ </entry>
+ <entry>
+ If enabled, the session will be automatically flushed during the
+ before completion phase of the transaction. Built-in and
+ automatic session context management is preferred, see
+ <xref linkend="architecture-current-session"/>.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.transaction.auto_close_session</literal>
+ </entry>
+ <entry>
+ If enabled, the session will be automatically closed during the
+ after completion phase of the transaction. Built-in and
+ utomatic session context management is preferred, see
+ <xref linkend="architecture-current-session"/>.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot" id="configuration-misc-properties" revision="10">
+ <title>Miscellaneous Properties</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Property name</entry>
+ <entry>Purpose</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.current_session_context_class</literal>
+ </entry>
+ <entry>
+ Supply a (custom) strategy for the scoping of the "current"
+ <literal>Session</literal>. See
+ <xref linkend="architecture-current-session"/> for more
+ information about the built-in strategies.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>jta</literal> | <literal>thread</literal> |
+ <literal>managed</literal> | <literal>custom.Class</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.query.factory_class</literal>
+ </entry>
+ <entry>
+ Chooses the HQL parser implementation.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> or
+ <literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.query.substitutions</literal>
+ </entry>
+ <entry>
+ Mapping from tokens in Hibernate queries to SQL tokens
+ (tokens might be function or literal names, for example).
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.hbm2ddl.auto</literal>
+ </entry>
+ <entry>
+ Automatically validate or export schema DDL to the database
+ when the <literal>SessionFactory</literal> is created. With
+ <literal>create-drop</literal>, the database schema will be
+ dropped when the <literal>SessionFactory</literal> is closed
+ explicitly.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>validate</literal> | <literal>update</literal> |
+ <literal>create</literal> | <literal>create-drop</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cglib.use_reflection_optimizer</literal>
+ </entry>
+ <entry>
+ Enables use of CGLIB instead of runtime reflection (System-level
+ property). Reflection can sometimes be useful when troubleshooting,
+ note that Hibernate always requires CGLIB even if you turn off the
+ optimizer. You can not set this property in <literal>hibernate.cfg.xml</literal>.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <sect2 id="configuration-optional-dialects" revision="1">
+ <title>SQL Dialects</title>
+
+ <para>
+ You should always set the <literal>hibernate.dialect</literal> property to the correct
+ <literal>org.hibernate.dialect.Dialect</literal> subclass for your database. If you
+ specify a dialect, Hibernate will use sensible defaults for some of the
+ other properties listed above, saving you the effort of specifying them manually.
+ </para>
+
+ <table frame="topbot" id="sql-dialects" revision="2">
+ <title>Hibernate SQL Dialects (<literal>hibernate.dialect</literal>)</title>
+ <tgroup cols="2">
+ <colspec colwidth="1*"/>
+ <colspec colwidth="2.5*"/>
+ <thead>
+ <row>
+ <entry>RDBMS</entry>
+ <entry>Dialect</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>DB2</entry> <entry><literal>org.hibernate.dialect.DB2Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>DB2 AS/400</entry> <entry><literal>org.hibernate.dialect.DB2400Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>DB2 OS390</entry> <entry><literal>org.hibernate.dialect.DB2390Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>PostgreSQL</entry> <entry><literal>org.hibernate.dialect.PostgreSQLDialect</literal></entry>
+ </row>
+ <row>
+ <entry>MySQL</entry> <entry><literal>org.hibernate.dialect.MySQLDialect</literal></entry>
+ </row>
+ <row>
+ <entry>MySQL with InnoDB</entry> <entry><literal>org.hibernate.dialect.MySQLInnoDBDialect</literal></entry>
+ </row>
+ <row>
+ <entry>MySQL with MyISAM</entry> <entry><literal>org.hibernate.dialect.MySQLMyISAMDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Oracle (any version)</entry> <entry><literal>org.hibernate.dialect.OracleDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Oracle 9i/10g</entry> <entry><literal>org.hibernate.dialect.Oracle9Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>Sybase</entry> <entry><literal>org.hibernate.dialect.SybaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Sybase Anywhere</entry> <entry><literal>org.hibernate.dialect.SybaseAnywhereDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Microsoft SQL Server</entry> <entry><literal>org.hibernate.dialect.SQLServerDialect</literal></entry>
+ </row>
+ <row>
+ <entry>SAP DB</entry> <entry><literal>org.hibernate.dialect.SAPDBDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Informix</entry> <entry><literal>org.hibernate.dialect.InformixDialect</literal></entry>
+ </row>
+ <row>
+ <entry>HypersonicSQL</entry> <entry><literal>org.hibernate.dialect.HSQLDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Ingres</entry> <entry><literal>org.hibernate.dialect.IngresDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Progress</entry> <entry><literal>org.hibernate.dialect.ProgressDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Mckoi SQL</entry> <entry><literal>org.hibernate.dialect.MckoiDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Interbase</entry> <entry><literal>org.hibernate.dialect.InterbaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Pointbase</entry> <entry><literal>org.hibernate.dialect.PointbaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>FrontBase</entry> <entry><literal>org.hibernate.dialect.FrontbaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Firebird</entry> <entry><literal>org.hibernate.dialect.FirebirdDialect</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-outerjoin" revision="4">
+ <title>Outer Join Fetching</title>
+
+ <para>
+ If your database supports ANSI, Oracle or Sybase style outer joins, <emphasis>outer join
+ fetching</emphasis> will often increase performance by limiting the number of round
+ trips to and from the database (at the cost of possibly more work performed by
+ the database itself). Outer join fetching allows a whole graph of objects connected
+ by many-to-one, one-to-many, many-to-many and one-to-one associations to be retrieved
+ in a single SQL <literal>SELECT</literal>.
+ </para>
+
+ <para>
+ Outer join fetching may be disabled <emphasis>globally</emphasis> by setting
+ the property <literal>hibernate.max_fetch_depth</literal> to <literal>0</literal>.
+ A setting of <literal>1</literal> or higher enables outer join fetching for
+ one-to-one and many-to-one associations which have been mapped with
+ <literal>fetch="join"</literal>.
+ </para>
+
+ <para>
+ See <xref linkend="performance-fetching"/> for more information.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-binarystreams" revision="1">
+ <title>Binary Streams</title>
+
+ <para>
+ Oracle limits the size of <literal>byte</literal> arrays that may
+ be passed to/from its JDBC driver. If you wish to use large instances of
+ <literal>binary</literal> or <literal>serializable</literal> type, you should
+ enable <literal>hibernate.jdbc.use_streams_for_binary</literal>.
+ <emphasis>This is a system-level setting only.</emphasis>
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-cacheprovider" revision="2">
+ <title>Second-level and query cache</title>
+
+ <para>
+ The properties prefixed by <literal>hibernate.cache</literal>
+ allow you to use a process or cluster scoped second-level cache system
+ with Hibernate. See the <xref linkend="performance-cache"/> for
+ more details.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-querysubstitution">
+ <title>Query Language Substitution</title>
+
+ <para>
+ You may define new Hibernate query tokens using <literal>hibernate.query.substitutions</literal>.
+ For example:
+ </para>
+
+ <programlisting>hibernate.query.substitutions true=1, false=0</programlisting>
+
+ <para>
+ would cause the tokens <literal>true</literal> and <literal>false</literal> to be translated to
+ integer literals in the generated SQL.
+ </para>
+
+ <programlisting>hibernate.query.substitutions toLowercase=LOWER</programlisting>
+
+ <para>
+ would allow you to rename the SQL <literal>LOWER</literal> function.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-statistics" revision="2">
+ <title>Hibernate statistics</title>
+
+ <para>
+ If you enable <literal>hibernate.generate_statistics</literal>, Hibernate will
+ expose a number of metrics that are useful when tuning a running system via
+ <literal>SessionFactory.getStatistics()</literal>. Hibernate can even be configured
+ to expose these statistics via JMX. Read the Javadoc of the interfaces in
+ <literal>org.hibernate.stats</literal> for more information.
+ </para>
+
+ </sect2>
+ </sect1>
+
+ <sect1 id="configuration-logging">
+ <title>Logging</title>
+
+ <para>
+ Hibernate logs various events using Apache commons-logging.
+ </para>
+
+ <para>
+ The commons-logging service will direct output to either Apache Log4j
+ (if you include <literal>log4j.jar</literal> in your classpath) or
+ JDK1.4 logging (if running under JDK1.4 or above). You may download
+ Log4j from <literal>http://jakarta.apache.org</literal>.
+ To use Log4j you will need to place a <literal>log4j.properties</literal>
+ file in your classpath, an example properties file is distributed with
+ Hibernate in the <literal>src/</literal> directory.
+ </para>
+
+ <para>
+ We strongly recommend that you familiarize yourself with Hibernate's log
+ messages. A lot of work has been put into making the Hibernate log as
+ detailed as possible, without making it unreadable. It is an essential
+ troubleshooting device. The most interesting log categories are the
+ following:
+ </para>
+
+ <table frame="topbot" id="log-categories" revision="2">
+ <title>Hibernate Log Categories</title>
+ <tgroup cols="2">
+ <colspec colwidth="1*"/>
+ <colspec colwidth="2.5*"/>
+ <thead>
+ <row>
+ <entry>Category</entry>
+ <entry>Function</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>org.hibernate.SQL</literal></entry>
+ <entry>Log all SQL DML statements as they are executed</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.type</literal></entry>
+ <entry>Log all JDBC parameters</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.tool.hbm2ddl</literal></entry>
+ <entry>Log all SQL DDL statements as they are executed</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.pretty</literal></entry>
+ <entry>
+ Log the state of all entities (max 20 entities) associated
+ with the session at flush time
+ </entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.cache</literal></entry>
+ <entry>Log all second-level cache activity</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction</literal></entry>
+ <entry>Log transaction related activity</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.jdbc</literal></entry>
+ <entry>Log all JDBC resource acquisition</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.hql.ast.AST</literal></entry>
+ <entry>
+ Log HQL and SQL ASTs during query parsing
+ </entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.secure</literal></entry>
+ <entry>Log all JAAS authorization requests</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate</literal></entry>
+ <entry>
+ Log everything (a lot of information, but very useful for
+ troubleshooting)
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ When developing applications with Hibernate, you should almost always work with
+ <literal>debug</literal> enabled for the category <literal>org.hibernate.SQL</literal>,
+ or, alternatively, the property <literal>hibernate.show_sql</literal> enabled.
+ </para>
+
+
+ </sect1>
+
+ <sect1 id="configuration-namingstrategy">
+ <title>Implementing a <literal>NamingStrategy</literal></title>
+
+ <para>
+ The interface <literal>org.hibernate.cfg.NamingStrategy</literal> allows you
+ to specify a "naming standard" for database objects and schema elements.
+ </para>
+
+ <para>
+ You may provide rules for automatically generating database identifiers from
+ Java identifiers or for processing "logical" column and table names given in
+ the mapping file into "physical" table and column names. This feature helps
+ reduce the verbosity of the mapping document, eliminating repetitive noise
+ (<literal>TBL_</literal> prefixes, for example). The default strategy used by
+ Hibernate is quite minimal.
+ </para>
+
+ <para>
+ You may specify a different strategy by calling
+ <literal>Configuration.setNamingStrategy()</literal> before adding mappings:
+ </para>
+
+ <programlisting><![CDATA[SessionFactory sf = new Configuration()
+ .setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
+ .addFile("Item.hbm.xml")
+ .addFile("Bid.hbm.xml")
+ .buildSessionFactory();]]></programlisting>
+
+ <para>
+ <literal>org.hibernate.cfg.ImprovedNamingStrategy</literal> is a built-in
+ strategy that might be a useful starting point for some applications.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-xmlconfig" revision="2">
+ <title>XML configuration file</title>
+
+ <para>
+ An alternative approach to configuration is to specify a full configuration in
+ a file named <literal>hibernate.cfg.xml</literal>. This file can be used as a
+ replacement for the <literal>hibernate.properties</literal> file or, if both
+ are present, to override properties.
+ </para>
+
+ <para>
+ The XML configuration file is by default expected to be in the root o
+ your <literal>CLASSPATH</literal>. Here is an example:
+ </para>
+
+ <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+ "-//Hibernate/Hibernate Configuration DTD//EN"
+ "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+ <!-- a SessionFactory instance listed as /jndi/name -->
+ <session-factory
+ name="java:hibernate/SessionFactory">
+
+ <!-- properties -->
+ <property name="connection.datasource">java:/comp/env/jdbc/MyDB</property>
+ <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
+ <property name="show_sql">false</property>
+ <property name="transaction.factory_class">
+ org.hibernate.transaction.JTATransactionFactory
+ </property>
+ <property name="jta.UserTransaction">java:comp/UserTransaction</property>
+
+ <!-- mapping files -->
+ <mapping resource="org/hibernate/auction/Item.hbm.xml"/>
+ <mapping resource="org/hibernate/auction/Bid.hbm.xml"/>
+
+ <!-- cache settings -->
+ <class-cache class="org.hibernate.auction.Item" usage="read-write"/>
+ <class-cache class="org.hibernate.auction.Bid" usage="read-only"/>
+ <collection-cache collection="org.hibernate.auction.Item.bids" usage="read-write"/>
+
+ </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+ <para>
+ As you can see, the advantage of this approach is the externalization of the
+ mapping file names to configuration. The <literal>hibernate.cfg.xml</literal>
+ is also more convenient once you have to tune the Hibernate cache. Note that is
+ your choice to use either <literal>hibernate.properties</literal> or
+ <literal>hibernate.cfg.xml</literal>, both are equivalent, except for the above
+ mentioned benefits of using the XML syntax.
+ </para>
+
+ <para>
+ With the XML configuration, starting Hibernate is then as simple as
+ </para>
+
+ <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 id="configuration-j2ee" revision="1">
+ <title>J2EE Application Server integration</title>
+
+ <para>
+ Hibernate has the following integration points for J2EE infrastructure:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Container-managed datasources</emphasis>: Hibernate can use
+ JDBC connections managed by the container and provided through JNDI. Usually,
+ a JTA compatible <literal>TransactionManager</literal> and a
+ <literal>ResourceManager</literal> take care of transaction management (CMT),
+ esp. distributed transaction handling across several datasources. You may
+ of course also demarcate transaction boundaries programatically (BMT) or
+ you might want to use the optional Hibernate <literal>Transaction</literal>
+ API for this to keep your code portable.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Automatic JNDI binding</emphasis>: Hibernate can bind its
+ <literal>SessionFactory</literal> to JNDI after startup.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>JTA Session binding:</emphasis> The Hibernate <literal>Session</literal>
+ may be automatically bound to the scope of JTA transactions. Simply
+ lookup the <literal>SessionFactory</literal> from JNDI and get the current
+ <literal>Session</literal>. Let Hibernate take care of flushing and closing the
+ <literal>Session</literal> when your JTA transaction completes. Transaction
+ demarcation is either declarative (CMT) or programmatic (BMT/UserTransaction).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>JMX deployment:</emphasis> If you have a JMX capable application server
+ (e.g. JBoss AS), you can chose to deploy Hibernate as a managed MBean. This saves
+ you the one line startup code to build your <literal>SessionFactory</literal> from
+ a <literal>Configuration</literal>. The container will startup your
+ <literal>HibernateService</literal>, and ideally also take care of service
+ dependencies (Datasource has to be available before Hibernate starts, etc).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Depending on your environment, you might have to set the configuration option
+ <literal>hibernate.connection.aggressive_release</literal> to true if your
+ application server shows "connection containment" exceptions.
+ </para>
+
+ <sect2 id="configuration-optional-transactionstrategy" revision="3">
+ <title>Transaction strategy configuration</title>
+
+ <para>
+ The Hibernate <literal>Session</literal> API is independent of any transaction
+ demarcation system in your architecture. If you let Hibernate use JDBC directly,
+ through a connection pool, you may begin and end your transactions by calling
+ the JDBC API. If you run in a J2EE application server, you might want to use bean-managed
+ transactions and call the JTA API and <literal>UserTransaction</literal> when needed.
+ </para>
+
+ <para>
+ To keep your code portable between these two (and other) environments we recommend the optional
+ Hibernate <literal>Transaction</literal> API, which wraps and hides the underlying system.
+ You have to specify a factory class for <literal>Transaction</literal> instances by setting the
+ Hibernate configuration property <literal>hibernate.transaction.factory_class</literal>.
+ </para>
+
+ <para>
+ There are three standard (built-in) choices:
+ </para>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term><literal>org.hibernate.transaction.JDBCTransactionFactory</literal></term>
+ <listitem>
+ <para>delegates to database (JDBC) transactions (default)</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>org.hibernate.transaction.JTATransactionFactory</literal></term>
+ <listitem>
+ <para>
+ delegates to container-managed transaction if an existing transaction is
+ underway in this context (e.g. EJB session bean method), otherwise
+ a new transaction is started and bean-managed transaction are used.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>org.hibernate.transaction.CMTTransactionFactory</literal></term>
+ <listitem>
+ <para>delegates to container-managed JTA transactions</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ You may also define your own transaction strategies (for a CORBA transaction service,
+ for example).
+ </para>
+
+ <para>
+ Some features in Hibernate (i.e. the second level cache, Contextual Sessions with JTA, etc.)
+ require access to the JTA <literal>TransactionManager</literal> in a managed environment.
+ In an application server you have to specify how Hibernate should obtain a reference to the
+ <literal>TransactionManager</literal>, since J2EE does not standardize a single mechanism:
+ </para>
+
+ <table frame="topbot" id="jtamanagerlookup" revision="1">
+ <title>JTA TransactionManagers</title>
+ <tgroup cols="2">
+ <colspec colwidth="2.5*"/>
+ <colspec colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Transaction Factory</entry>
+ <entry align="center">Application Server</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>org.hibernate.transaction.JBossTransactionManagerLookup</literal></entry>
+ <entry align="center">JBoss</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.WeblogicTransactionManagerLookup</literal></entry>
+ <entry align="center">Weblogic</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.WebSphereTransactionManagerLookup</literal></entry>
+ <entry align="center">WebSphere</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</literal></entry>
+ <entry align="center">WebSphere 6</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.OrionTransactionManagerLookup</literal></entry>
+ <entry align="center">Orion</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.ResinTransactionManagerLookup</literal></entry>
+ <entry align="center">Resin</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.JOTMTransactionManagerLookup</literal></entry>
+ <entry align="center">JOTM</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.JOnASTransactionManagerLookup</literal></entry>
+ <entry align="center">JOnAS</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.JRun4TransactionManagerLookup</literal></entry>
+ <entry align="center">JRun4</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.BESTransactionManagerLookup</literal></entry>
+ <entry align="center">Borland ES</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-jndi" revision="3">
+ <title>JNDI-bound <literal>SessionFactory</literal></title>
+
+ <para>
+ A JNDI bound Hibernate <literal>SessionFactory</literal> can simplify the lookup
+ of the factory and the creation of new <literal>Session</literal>s. Note that this
+ is not related to a JNDI bound <literal>Datasource</literal>, both simply use the
+ same registry!
+ </para>
+
+ <para>
+ If you wish to have the <literal>SessionFactory</literal> bound to a JNDI namespace, specify
+ a name (eg. <literal>java:hibernate/SessionFactory</literal>) using the property
+ <literal>hibernate.session_factory_name</literal>. If this property is omitted, the
+ <literal>SessionFactory</literal> will not be bound to JNDI. (This is especially useful in
+ environments with a read-only JNDI default implementation, e.g. Tomcat.)
+ </para>
+
+ <para>
+ When binding the <literal>SessionFactory</literal> to JNDI, Hibernate will use the values of
+ <literal>hibernate.jndi.url</literal>, <literal>hibernate.jndi.class</literal> to instantiate
+ an initial context. If they are not specified, the default <literal>InitialContext</literal>
+ will be used.
+ </para>
+
+ <para>
+ Hibernate will automatically place the <literal>SessionFactory</literal> in JNDI after
+ you call <literal>cfg.buildSessionFactory()</literal>. This means you will at least have
+ this call in some startup code (or utility class) in your application, unless you use
+ JMX deployment with the <literal>HibernateService</literal> (discussed later).
+ </para>
+
+ <para>
+ If you use a JNDI <literal>SessionFactory</literal>, an EJB or any other class may
+ obtain the <literal>SessionFactory</literal> using a JNDI lookup.
+ </para>
+
+ <para>
+ We recommend that you bind the <literal>SessionFactory</literal> to JNDI in
+ a managend environment and use a <literal>static</literal> singleton otherwise.
+ To shield your application code from these details, we also recommend to hide the
+ actual lookup code for a <literal>SessionFactory</literal> in a helper class,
+ such as <literal>HibernateUtil.getSessionFactory()</literal>. Note that such a
+ class is also a convenient way to startup Hibernate—see chapter 1.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-j2ee-currentsession" revision="4">
+ <title>Current Session context management with JTA</title>
+
+ <para>
+ The easiest way to handle <literal>Session</literal>s and transactions is
+ Hibernates automatic "current" <literal>Session</literal> management.
+ See the discussion of <xref linkend="architecture-current-session">current sessions</xref>.
+ Using the <literal>"jta"</literal> session context, if there is no Hibernate
+ <literal>Session</literal> associated with the current JTA transaction, one will
+ be started and associated with that JTA transaction the first time you call
+ <literal>sessionFactory.getCurrentSession()</literal>. The <literal>Session</literal>s
+ retrieved via <literal>getCurrentSession()</literal> in <literal>"jta"</literal> context
+ will be set to automatically flush before the transaction completes, close
+ after the transaction completes, and aggressively release JDBC connections
+ after each statement. This allows the <literal>Session</literal>s to
+ be managed by the lifecycle of the JTA transaction to which it is associated,
+ keeping user code clean of such management concerns. Your code can either use
+ JTA programmatically through <literal>UserTransaction</literal>, or (recommended
+ for portable code) use the Hibernate <literal>Transaction</literal> API to set
+ transaction boundaries. If you run in an EJB container, declarative transaction
+ demarcation with CMT is preferred.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-j2ee-jmx" revision="1">
+ <title>JMX deployment</title>
+
+ <para>
+ The line <literal>cfg.buildSessionFactory()</literal> still has to be executed
+ somewhere to get a <literal>SessionFactory</literal> into JNDI. You can do this
+ either in a <literal>static</literal> initializer block (like the one in
+ <literal>HibernateUtil</literal>) or you deploy Hibernate as a <emphasis>managed
+ service</emphasis>.
+ </para>
+
+ <para>
+ Hibernate is distributed with <literal>org.hibernate.jmx.HibernateService</literal>
+ for deployment on an application server with JMX capabilities, such as JBoss AS.
+ The actual deployment and configuration is vendor specific. Here is an example
+ <literal>jboss-service.xml</literal> for JBoss 4.0.x:
+ </para>
+
+ <programlisting><![CDATA[<?xml version="1.0"?>
+<server>
+
+<mbean code="org.hibernate.jmx.HibernateService"
+ name="jboss.jca:service=HibernateFactory,name=HibernateFactory">
+
+ <!-- Required services -->
+ <depends>jboss.jca:service=RARDeployer</depends>
+ <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends>
+
+ <!-- Bind the Hibernate service to JNDI -->
+ <attribute name="JndiName">java:/hibernate/SessionFactory</attribute>
+
+ <!-- Datasource settings -->
+ <attribute name="Datasource">java:HsqlDS</attribute>
+ <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute>
+
+ <!-- Transaction integration -->
+ <attribute name="TransactionStrategy">
+ org.hibernate.transaction.JTATransactionFactory</attribute>
+ <attribute name="TransactionManagerLookupStrategy">
+ org.hibernate.transaction.JBossTransactionManagerLookup</attribute>
+ <attribute name="FlushBeforeCompletionEnabled">true</attribute>
+ <attribute name="AutoCloseSessionEnabled">true</attribute>
+
+ <!-- Fetching options -->
+ <attribute name="MaximumFetchDepth">5</attribute>
+
+ <!-- Second-level caching -->
+ <attribute name="SecondLevelCacheEnabled">true</attribute>
+ <attribute name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute>
+ <attribute name="QueryCacheEnabled">true</attribute>
+
+ <!-- Logging -->
+ <attribute name="ShowSqlEnabled">true</attribute>
+
+ <!-- Mapping files -->
+ <attribute name="MapResources">auction/Item.hbm.xml,auction/Category.hbm.xml</attribute>
+
+</mbean>
+
+</server>]]></programlisting>
+
+ <para>
+ This file is deployed in a directory called <literal>META-INF</literal> and packaged
+ in a JAR file with the extension <literal>.sar</literal> (service archive). You also need
+ to package Hibernate, its required third-party libraries, your compiled persistent classes,
+ as well as your mapping files in the same archive. Your enterprise beans (usually session
+ beans) may be kept in their own JAR file, but you may include this EJB JAR file in the
+ main service archive to get a single (hot-)deployable unit. Consult the JBoss AS
+ documentation for more information about JMX service and EJB deployment.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/events.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/events.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/events.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,267 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="events">
+ <title>Interceptors and events</title>
+
+ <para>
+ It is often useful for the application to react to certain events that occur
+ inside Hibernate. This allows implementation of certain kinds of generic
+ functionality, and extension of Hibernate functionality.
+ </para>
+
+ <sect1 id="objectstate-interceptors" revision="3">
+ <title>Interceptors</title>
+
+ <para>
+ The <literal>Interceptor</literal> interface provides callbacks from the session to the
+ application allowing the application to inspect and/or manipulate properties of a
+ persistent object before it is saved, updated, deleted or loaded. One
+ possible use for this is to track auditing information. For example, the following
+ <literal>Interceptor</literal> automatically sets the <literal>createTimestamp</literal>
+ when an <literal>Auditable</literal> is created and updates the
+ <literal>lastUpdateTimestamp</literal> property when an <literal>Auditable</literal> is
+ updated.
+ </para>
+
+ <para>
+ You may either implement <literal>Interceptor</literal> directly or (better) extend
+ <literal>EmptyInterceptor</literal>.
+ </para>
+
+ <programlisting><![CDATA[package org.hibernate.test;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.Transaction;
+import org.hibernate.type.Type;
+
+public class AuditInterceptor extends EmptyInterceptor {
+
+ private int updates;
+ private int creates;
+ private int loads;
+
+ public void onDelete(Object entity,
+ Serializable id,
+ Object[] state,
+ String[] propertyNames,
+ Type[] types) {
+ // do nothing
+ }
+
+ public boolean onFlushDirty(Object entity,
+ Serializable id,
+ Object[] currentState,
+ Object[] previousState,
+ String[] propertyNames,
+ Type[] types) {
+
+ if ( entity instanceof Auditable ) {
+ updates++;
+ for ( int i=0; i < propertyNames.length; i++ ) {
+ if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
+ currentState[i] = new Date();
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean onLoad(Object entity,
+ Serializable id,
+ Object[] state,
+ String[] propertyNames,
+ Type[] types) {
+ if ( entity instanceof Auditable ) {
+ loads++;
+ }
+ return false;
+ }
+
+ public boolean onSave(Object entity,
+ Serializable id,
+ Object[] state,
+ String[] propertyNames,
+ Type[] types) {
+
+ if ( entity instanceof Auditable ) {
+ creates++;
+ for ( int i=0; i<propertyNames.length; i++ ) {
+ if ( "createTimestamp".equals( propertyNames[i] ) ) {
+ state[i] = new Date();
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public void afterTransactionCompletion(Transaction tx) {
+ if ( tx.wasCommitted() ) {
+ System.out.println("Creations: " + creates + ", Updates: " + updates, "Loads: " + loads);
+ }
+ updates=0;
+ creates=0;
+ loads=0;
+ }
+
+}]]></programlisting>
+
+ <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>
+ 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>
+
+ </sect1>
+
+ <sect1 id="objectstate-events" revision="4">
+ <title>Event system</title>
+
+ <para>
+ If you have to react to particular events in your persistence layer, you may
+ also use the Hibernate3 <emphasis>event</emphasis> architecture. The event
+ system can be used in addition or as a replacement for interceptors.
+ </para>
+
+ <para>
+ Essentially all of the methods of the <literal>Session</literal> interface correlate
+ to an event. You have a <literal>LoadEvent</literal>, a <literal>FlushEvent</literal>, etc
+ (consult the XML configuration-file DTD or the <literal>org.hibernate.event</literal>
+ package for the full list of defined event types). When a request is made of one of
+ these methods, the Hibernate <literal>Session</literal> generates an appropriate
+ event and passes it to the configured event listeners for that type. Out-of-the-box,
+ these listeners implement the same processing in which those methods always resulted.
+ However, you are free to implement a customization of one of the listener interfaces
+ (i.e., the <literal>LoadEvent</literal> is processed by the registered implemenation
+ of the <literal>LoadEventListener</literal> interface), in which case their
+ implementation would be responsible for processing any <literal>load()</literal> requests
+ made of the <literal>Session</literal>.
+ </para>
+
+ <para>
+ The listeners should be considered effectively singletons; meaning, they are shared between
+ requests, and thus should not save any state as instance variables.
+ </para>
+
+ <para>
+ A custom listener should implement the appropriate interface for the event it wants to
+ process and/or extend one of the convenience base classes (or even the default event
+ listeners used by Hibernate out-of-the-box as these are declared non-final for this
+ purpose). Custom listeners can either be registered programmatically through the
+ <literal>Configuration</literal> object, or specified in the Hibernate configuration
+ XML (declarative configuration through the properties file is not supported). Here's an
+ example of a custom load event listener:
+ </para>
+
+ <programlisting><![CDATA[public class MyLoadListener implements LoadEventListener {
+ // this is the single method defined by the LoadEventListener interface
+ public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
+ throws HibernateException {
+ if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
+ throw MySecurityException("Unauthorized access");
+ }
+ }
+}]]></programlisting>
+
+ <para>
+ You also need a configuration entry telling Hibernate to use the listener in addition
+ to the default listener:
+ </para>
+
+<programlisting><![CDATA[<hibernate-configuration>
+ <session-factory>
+ ...
+ <event type="load">
+ <listener class="com.eg.MyLoadListener"/>
+ <listener class="org.hibernate.event.def.DefaultLoadEventListener"/>
+ </event>
+ </session-factory>
+</hibernate-configuration>]]></programlisting>
+
+ <para>
+ Instead, you may register it programmatically:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = new Configuration();
+LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() };
+cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
+
+ <para>
+ Listeners registered declaratively cannot share instances. If the same class name is
+ used in multiple <literal><listener/></literal> elements, each reference will
+ result in a separate instance of that class. If you need the capability to share
+ listener instances between listener types you must use the programmatic registration
+ approach.
+ </para>
+
+ <para>
+ Why implement an interface and define the specific type during configuration? Well, a
+ listener implementation could implement multiple event listener interfaces. Having the
+ type additionally defined during registration makes it easier to turn custom listeners on
+ or off during configuration.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-decl-security" revision="2">
+ <title>Hibernate declarative security</title>
+ <para>
+ Usually, declarative security in Hibernate applications is managed in a session facade
+ layer. Now, Hibernate3 allows certain actions to be permissioned via JACC, and authorized
+ via JAAS. This is optional functionality built on top of the event architecture.
+ </para>
+
+ <para>
+ First, you must configure the appropriate event listeners, to enable the use of JAAS
+ authorization.
+ </para>
+
+ <programlisting><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
+<listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/>
+<listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/>
+<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
+
+ <para>
+ Note that <literal><listener type="..." class="..."/></literal> is just a shorthand
+ for <literal><event type="..."><listener class="..."/></event></literal>
+ when there is exactly one listener for a particular event type.
+ </para>
+
+ <para>
+ Next, still in <literal>hibernate.cfg.xml</literal>, bind the permissions to roles:
+ </para>
+
+ <programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
+<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
+
+ <para>
+ The role names are the roles understood by your JACC provider.
+ </para>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/example_mappings.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/example_mappings.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/example_mappings.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,660 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="example-mappings">
+ <title>Example: Various Mappings</title>
+
+ <para>
+ This chapters shows off some more complex association mappings.
+ </para>
+
+ <sect1 id="example-mappings-emp">
+ <title>Employer/Employee</title>
+
+ <para>
+ The following model of the relationship between <literal>Employer</literal> and
+ <literal>Employee</literal> uses an actual entity class (<literal>Employment</literal>)
+ to represent the association. This is done because there might be more than one
+ period of employment for the same two parties. Components are used to model monetary
+ values and employee names.
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="shared/images/EmployerEmployee.gif" format="GIF" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../shared/images/EmployerEmployee.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ Heres a possible mapping document:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Employer" table="employers">
+ <id name="id">
+ <generator class="sequence">
+ <param name="sequence">employer_id_seq</param>
+ </generator>
+ </id>
+ <property name="name"/>
+ </class>
+
+ <class name="Employment" table="employment_periods">
+
+ <id name="id">
+ <generator class="sequence">
+ <param name="sequence">employment_id_seq</param>
+ </generator>
+ </id>
+ <property name="startDate" column="start_date"/>
+ <property name="endDate" column="end_date"/>
+
+ <component name="hourlyRate" class="MonetaryAmount">
+ <property name="amount">
+ <column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>
+ </property>
+ <property name="currency" length="12"/>
+ </component>
+
+ <many-to-one name="employer" column="employer_id" not-null="true"/>
+ <many-to-one name="employee" column="employee_id" not-null="true"/>
+
+ </class>
+
+ <class name="Employee" table="employees">
+ <id name="id">
+ <generator class="sequence">
+ <param name="sequence">employee_id_seq</param>
+ </generator>
+ </id>
+ <property name="taxfileNumber"/>
+ <component name="name" class="Name">
+ <property name="firstName"/>
+ <property name="initial"/>
+ <property name="lastName"/>
+ </component>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ And heres the table schema generated by <literal>SchemaExport</literal>.
+ </para>
+
+ <programlisting><![CDATA[create table employers (
+ id BIGINT not null,
+ name VARCHAR(255),
+ primary key (id)
+)
+
+create table employment_periods (
+ id BIGINT not null,
+ hourly_rate NUMERIC(12, 2),
+ currency VARCHAR(12),
+ employee_id BIGINT not null,
+ employer_id BIGINT not null,
+ end_date TIMESTAMP,
+ start_date TIMESTAMP,
+ primary key (id)
+)
+
+create table employees (
+ id BIGINT not null,
+ firstName VARCHAR(255),
+ initial CHAR(1),
+ lastName VARCHAR(255),
+ taxfileNumber VARCHAR(255),
+ primary key (id)
+)
+
+alter table employment_periods
+ add constraint employment_periodsFK0 foreign key (employer_id) references employers
+alter table employment_periods
+ add constraint employment_periodsFK1 foreign key (employee_id) references employees
+create sequence employee_id_seq
+create sequence employment_id_seq
+create sequence employer_id_seq]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="example-mappings-authorwork">
+ <title>Author/Work</title>
+
+ <para>
+ Consider the following model of the relationships between <literal>Work</literal>,
+ <literal>Author</literal> and <literal>Person</literal>. We represent the relationship
+ between <literal>Work</literal> and <literal>Author</literal> as a many-to-many
+ association. We choose to represent the relationship between <literal>Author</literal>
+ and <literal>Person</literal> as one-to-one association. Another possibility would be to
+ have <literal>Author</literal> extend <literal>Person</literal>.
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="shared/images/AuthorWork.gif" format="GIF" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../shared/images/AuthorWork.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ The following mapping document correctly represents these relationships:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Work" table="works" discriminator-value="W">
+
+ <id name="id" column="id">
+ <generator class="native"/>
+ </id>
+ <discriminator column="type" type="character"/>
+
+ <property name="title"/>
+ <set name="authors" table="author_work">
+ <key column name="work_id"/>
+ <many-to-many class="Author" column name="author_id"/>
+ </set>
+
+ <subclass name="Book" discriminator-value="B">
+ <property name="text"/>
+ </subclass>
+
+ <subclass name="Song" discriminator-value="S">
+ <property name="tempo"/>
+ <property name="genre"/>
+ </subclass>
+
+ </class>
+
+ <class name="Author" table="authors">
+
+ <id name="id" column="id">
+ <!-- The Author must have the same identifier as the Person -->
+ <generator class="assigned"/>
+ </id>
+
+ <property name="alias"/>
+ <one-to-one name="person" constrained="true"/>
+
+ <set name="works" table="author_work" inverse="true">
+ <key column="author_id"/>
+ <many-to-many class="Work" column="work_id"/>
+ </set>
+
+ </class>
+
+ <class name="Person" table="persons">
+ <id name="id" column="id">
+ <generator class="native"/>
+ </id>
+ <property name="name"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ There are four tables in this mapping. <literal>works</literal>,
+ <literal>authors</literal> and <literal>persons</literal> hold work, author
+ and person data respectively. <literal>author_work</literal> is an association
+ table linking authors to works. Heres the table schema, as generated by
+ <literal>SchemaExport</literal>.
+ </para>
+
+ <programlisting><![CDATA[create table works (
+ id BIGINT not null generated by default as identity,
+ tempo FLOAT,
+ genre VARCHAR(255),
+ text INTEGER,
+ title VARCHAR(255),
+ type CHAR(1) not null,
+ primary key (id)
+)
+
+create table author_work (
+ author_id BIGINT not null,
+ work_id BIGINT not null,
+ primary key (work_id, author_id)
+)
+
+create table authors (
+ id BIGINT not null generated by default as identity,
+ alias VARCHAR(255),
+ primary key (id)
+)
+
+create table persons (
+ id BIGINT not null generated by default as identity,
+ name VARCHAR(255),
+ primary key (id)
+)
+
+alter table authors
+ add constraint authorsFK0 foreign key (id) references persons
+alter table author_work
+ add constraint author_workFK0 foreign key (author_id) references authors
+alter table author_work
+ add constraint author_workFK1 foreign key (work_id) references works]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="example-mappings-customerorderproduct">
+ <title>Customer/Order/Product</title>
+
+ <para>
+ Now consider a model of the relationships between <literal>Customer</literal>,
+ <literal>Order</literal> and <literal>LineItem</literal> and <literal>Product</literal>.
+ There is a one-to-many association between <literal>Customer</literal> and
+ <literal>Order</literal>, but how should we represent <literal>Order</literal> /
+ <literal>LineItem</literal> / <literal>Product</literal>? I've chosen to map
+ <literal>LineItem</literal> as an association class representing the many-to-many
+ association between <literal>Order</literal> and <literal>Product</literal>. In
+ Hibernate, this is called a composite element.
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="shared/images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../shared/images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ The mapping document:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Customer" table="customers">
+ <id name="id">
+ <generator class="native"/>
+ </id>
+ <property name="name"/>
+ <set name="orders" inverse="true">
+ <key column="customer_id"/>
+ <one-to-many class="Order"/>
+ </set>
+ </class>
+
+ <class name="Order" table="orders">
+ <id name="id">
+ <generator class="native"/>
+ </id>
+ <property name="date"/>
+ <many-to-one name="customer" column="customer_id"/>
+ <list name="lineItems" table="line_items">
+ <key column="order_id"/>
+ <list-index column="line_number"/>
+ <composite-element class="LineItem">
+ <property name="quantity"/>
+ <many-to-one name="product" column="product_id"/>
+ </composite-element>
+ </list>
+ </class>
+
+ <class name="Product" table="products">
+ <id name="id">
+ <generator class="native"/>
+ </id>
+ <property name="serialNumber"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ <literal>customers</literal>, <literal>orders</literal>, <literal>line_items</literal> and
+ <literal>products</literal> hold customer, order, order line item and product data
+ respectively. <literal>line_items</literal> also acts as an association table linking
+ orders with products.
+ </para>
+
+ <programlisting><![CDATA[create table customers (
+ id BIGINT not null generated by default as identity,
+ name VARCHAR(255),
+ primary key (id)
+)
+
+create table orders (
+ id BIGINT not null generated by default as identity,
+ customer_id BIGINT,
+ date TIMESTAMP,
+ primary key (id)
+)
+
+create table line_items (
+ line_number INTEGER not null,
+ order_id BIGINT not null,
+ product_id BIGINT,
+ quantity INTEGER,
+ primary key (order_id, line_number)
+)
+
+create table products (
+ id BIGINT not null generated by default as identity,
+ serialNumber VARCHAR(255),
+ primary key (id)
+)
+
+alter table orders
+ add constraint ordersFK0 foreign key (customer_id) references customers
+alter table line_items
+ add constraint line_itemsFK0 foreign key (product_id) references products
+alter table line_items
+ add constraint line_itemsFK1 foreign key (order_id) references orders]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="misc">
+ <title>Miscellaneous example mappings</title>
+
+ <para>
+ These examples are all taken from the Hibernate test suite. You
+ will find many other useful example mappings there. Look in the
+ <literal>test</literal> folder of the Hibernate distribution.
+ </para>
+
+ <para>TODO: put words around this stuff</para>
+
+ <sect2 id="example-mappings-typed-onetone">
+ <title>"Typed" one-to-one association</title>
+<programlisting><![CDATA[<class name="Person">
+ <id name="name"/>
+ <one-to-one name="address"
+ cascade="all">
+ <formula>name</formula>
+ <formula>'HOME'</formula>
+ </one-to-one>
+ <one-to-one name="mailingAddress"
+ cascade="all">
+ <formula>name</formula>
+ <formula>'MAILING'</formula>
+ </one-to-one>
+</class>
+
+<class name="Address" batch-size="2"
+ check="addressType in ('MAILING', 'HOME', 'BUSINESS')">
+ <composite-id>
+ <key-many-to-one name="person"
+ column="personName"/>
+ <key-property name="type"
+ column="addressType"/>
+ </composite-id>
+ <property name="street" type="text"/>
+ <property name="state"/>
+ <property name="zip"/>
+</class>]]></programlisting>
+ </sect2>
+
+ <sect2 id="example-mappings-composite-key">
+ <title>Composite key example</title>
+<programlisting><![CDATA[<class name="Customer">
+
+ <id name="customerId"
+ length="10">
+ <generator class="assigned"/>
+ </id>
+
+ <property name="name" not-null="true" length="100"/>
+ <property name="address" not-null="true" length="200"/>
+
+ <list name="orders"
+ inverse="true"
+ cascade="save-update">
+ <key column="customerId"/>
+ <index column="orderNumber"/>
+ <one-to-many class="Order"/>
+ </list>
+
+</class>
+
+<class name="Order" table="CustomerOrder" lazy="true">
+ <synchronize table="LineItem"/>
+ <synchronize table="Product"/>
+
+ <composite-id name="id"
+ class="Order$Id">
+ <key-property name="customerId" length="10"/>
+ <key-property name="orderNumber"/>
+ </composite-id>
+
+ <property name="orderDate"
+ type="calendar_date"
+ not-null="true"/>
+
+ <property name="total">
+ <formula>
+ ( select sum(li.quantity*p.price)
+ from LineItem li, Product p
+ where li.productId = p.productId
+ and li.customerId = customerId
+ and li.orderNumber = orderNumber )
+ </formula>
+ </property>
+
+ <many-to-one name="customer"
+ column="customerId"
+ insert="false"
+ update="false"
+ not-null="true"/>
+
+ <bag name="lineItems"
+ fetch="join"
+ inverse="true"
+ cascade="save-update">
+ <key>
+ <column name="customerId"/>
+ <column name="orderNumber"/>
+ </key>
+ <one-to-many class="LineItem"/>
+ </bag>
+
+</class>
+
+<class name="LineItem">
+
+ <composite-id name="id"
+ class="LineItem$Id">
+ <key-property name="customerId" length="10"/>
+ <key-property name="orderNumber"/>
+ <key-property name="productId" length="10"/>
+ </composite-id>
+
+ <property name="quantity"/>
+
+ <many-to-one name="order"
+ insert="false"
+ update="false"
+ not-null="true">
+ <column name="customerId"/>
+ <column name="orderNumber"/>
+ </many-to-one>
+
+ <many-to-one name="product"
+ insert="false"
+ update="false"
+ not-null="true"
+ column="productId"/>
+
+</class>
+
+<class name="Product">
+ <synchronize table="LineItem"/>
+
+ <id name="productId"
+ length="10">
+ <generator class="assigned"/>
+ </id>
+
+ <property name="description"
+ not-null="true"
+ length="200"/>
+ <property name="price" length="3"/>
+ <property name="numberAvailable"/>
+
+ <property name="numberOrdered">
+ <formula>
+ ( select sum(li.quantity)
+ from LineItem li
+ where li.productId = productId )
+ </formula>
+ </property>
+
+</class>]]></programlisting>
+ </sect2>
+
+ <sect2 id="example-mappings-composite-key-manytomany">
+ <title>Many-to-many with shared composite key attribute</title>
+<programlisting><![CDATA[<class name="User" table="`User`">
+ <composite-id>
+ <key-property name="name"/>
+ <key-property name="org"/>
+ </composite-id>
+ <set name="groups" table="UserGroup">
+ <key>
+ <column name="userName"/>
+ <column name="org"/>
+ </key>
+ <many-to-many class="Group">
+ <column name="groupName"/>
+ <formula>org</formula>
+ </many-to-many>
+ </set>
+</class>
+
+<class name="Group" table="`Group`">
+ <composite-id>
+ <key-property name="name"/>
+ <key-property name="org"/>
+ </composite-id>
+ <property name="description"/>
+ <set name="users" table="UserGroup" inverse="true">
+ <key>
+ <column name="groupName"/>
+ <column name="org"/>
+ </key>
+ <many-to-many class="User">
+ <column name="userName"/>
+ <formula>org</formula>
+ </many-to-many>
+ </set>
+</class>
+]]></programlisting>
+ </sect2>
+
+ <sect2 id="example-mappings-content-discrimination">
+ <title>Content based discrimination</title>
+<programlisting><![CDATA[<class name="Person"
+ discriminator-value="P">
+
+ <id name="id"
+ column="person_id"
+ unsaved-value="0">
+ <generator class="native"/>
+ </id>
+
+
+ <discriminator
+ type="character">
+ <formula>
+ case
+ when title is not null then 'E'
+ when salesperson is not null then 'C'
+ else 'P'
+ end
+ </formula>
+ </discriminator>
+
+ <property name="name"
+ not-null="true"
+ length="80"/>
+
+ <property name="sex"
+ not-null="true"
+ update="false"/>
+
+ <component name="address">
+ <property name="address"/>
+ <property name="zip"/>
+ <property name="country"/>
+ </component>
+
+ <subclass name="Employee"
+ discriminator-value="E">
+ <property name="title"
+ length="20"/>
+ <property name="salary"/>
+ <many-to-one name="manager"/>
+ </subclass>
+
+ <subclass name="Customer"
+ discriminator-value="C">
+ <property name="comments"/>
+ <many-to-one name="salesperson"/>
+ </subclass>
+
+</class>]]></programlisting>
+ </sect2>
+
+ <sect2 id="example-mappings-association-alternatekeys" revision="2">
+ <title>Associations on alternate keys</title>
+<programlisting><![CDATA[<class name="Person">
+
+ <id name="id">
+ <generator class="hilo"/>
+ </id>
+
+ <property name="name" length="100"/>
+
+ <one-to-one name="address"
+ property-ref="person"
+ cascade="all"
+ fetch="join"/>
+
+ <set name="accounts"
+ inverse="true">
+ <key column="userId"
+ property-ref="userId"/>
+ <one-to-many class="Account"/>
+ </set>
+
+ <property name="userId" length="8"/>
+
+</class>
+
+<class name="Address">
+
+ <id name="id">
+ <generator class="hilo"/>
+ </id>
+
+ <property name="address" length="300"/>
+ <property name="zip" length="5"/>
+ <property name="country" length="25"/>
+ <many-to-one name="person" unique="true" not-null="true"/>
+
+</class>
+
+<class name="Account">
+ <id name="accountId" length="32">
+ <generator class="uuid"/>
+ </id>
+
+ <many-to-one name="user"
+ column="userId"
+ property-ref="userId"/>
+
+ <property name="type" not-null="true"/>
+
+</class>]]></programlisting>
+ </sect2>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/example_parentchild.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/example_parentchild.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/example_parentchild.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,363 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="example-parentchild">
+ <title>Example: Parent/Child</title>
+
+ <para>
+ One of the very first things that new users try to do with Hibernate is to model a parent / child type
+ relationship. There are two different approaches to this. For various reasons the most convenient
+ approach, especially for new users, is to model both <literal>Parent</literal> and <literal>Child</literal>
+ as entity classes with a <literal><one-to-many></literal> association from <literal>Parent</literal>
+ to <literal>Child</literal>. (The alternative approach is to declare the <literal>Child</literal> as a
+ <literal><composite-element></literal>.) Now, it turns out that default semantics of a one to many
+ association (in Hibernate) are much less close to the usual semantics of a parent / child relationship than
+ those of a composite element mapping. We will explain how to use a <emphasis>bidirectional one to many
+ association with cascades</emphasis> to model a parent / child relationship efficiently and elegantly.
+ It's not at all difficult!
+ </para>
+
+ <sect1 id="example-parentchild-collections">
+ <title>A note about collections</title>
+
+ <para>
+ Hibernate collections are considered to be a logical part of their owning entity; never of the
+ contained entities. This is a crucial distinction! It has the following consequences:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ When we remove / add an object from / to a collection, the version number of the collection owner
+ is incremented.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If an object that was removed from a collection is an instance of a value type (eg, a composite
+ element), that object will cease to be persistent and its state will be completely removed from
+ the database. Likewise, adding a value type instance to the collection will cause its state to be
+ immediately persistent.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ On the other hand, if an entity is removed from a collection (a one-to-many or many-to-many
+ association), it will not be deleted, by default. This behaviour is completely consistent - a
+ change to the internal state of another entity should not cause the associated entity to vanish!
+ Likewise, adding an entity to a collection does not cause that entity to become persistent, by
+ default.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Instead, the default behaviour is that adding an entity to a collection merely creates a link between
+ the two entities, while removing it removes the link. This is very appropriate for all sorts of cases.
+ Where it is not appropriate at all is the case of a parent / child relationship, where the life of the
+ child is bound to the lifecycle of the parent.
+ </para>
+
+ </sect1>
+
+ <sect1 id="example-parentchild-bidir">
+ <title>Bidirectional one-to-many</title>
+
+ <para>
+ Suppose we start with a simple <literal><one-to-many></literal> association from
+ <literal>Parent</literal> to <literal>Child</literal>.
+ </para>
+
+ <programlisting><![CDATA[<set name="children">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+ <para>
+ If we were to execute the following code
+ </para>
+
+ <programlisting><![CDATA[Parent p = .....;
+Child c = new Child();
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+ <para>
+ Hibernate would issue two SQL statements:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>an <literal>INSERT</literal> to create the record for <literal>c</literal></para>
+ </listitem>
+ <listitem>
+ <para>
+ an <literal>UPDATE</literal> to create the link from <literal>p</literal> to
+ <literal>c</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ This is not only inefficient, but also violates any <literal>NOT NULL</literal> constraint on the
+ <literal>parent_id</literal> column. We can fix the nullability constraint violation by specifying
+ <literal>not-null="true"</literal> in the collection mapping:
+ </para>
+
+ <programlisting><![CDATA[<set name="children">
+ <key column="parent_id" not-null="true"/>
+ <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+ <para>
+ However, this is not the recommended solution.
+ </para>
+ <para>
+ The underlying cause of this behaviour is that the link (the foreign key <literal>parent_id</literal>)
+ from <literal>p</literal> to <literal>c</literal> is not considered part of the state of the
+ <literal>Child</literal> object and is therefore not created in the <literal>INSERT</literal>. So the
+ solution is to make the link part of the <literal>Child</literal> mapping.
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="parent" column="parent_id" not-null="true"/>]]></programlisting>
+
+ <para>
+ (We also need to add the <literal>parent</literal> property to the <literal>Child</literal> class.)
+ </para>
+
+ <para>
+ Now that the <literal>Child</literal> entity is managing the state of the link, we tell the collection
+ not to update the link. We use the <literal>inverse</literal> attribute.
+ </para>
+
+ <programlisting><![CDATA[<set name="children" inverse="true">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+ <para>
+ The following code would be used to add a new <literal>Child</literal>
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+c.setParent(p);
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+ <para>
+ And now, only one SQL <literal>INSERT</literal> would be issued!
+ </para>
+
+ <para>
+ To tighten things up a bit, we could create an <literal>addChild()</literal> method of
+ <literal>Parent</literal>.
+ </para>
+
+ <programlisting><![CDATA[public void addChild(Child c) {
+ c.setParent(this);
+ children.add(c);
+}]]></programlisting>
+
+ <para>
+ Now, the code to add a <literal>Child</literal> looks like
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="example-parentchild-cascades">
+ <title>Cascading lifecycle</title>
+
+ <para>
+ The explicit call to <literal>save()</literal> is still annoying. We will address this by
+ using cascades.
+ </para>
+
+ <programlisting><![CDATA[<set name="children" inverse="true" cascade="all">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+ <para>
+ This simplifies the code above to
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.flush();]]></programlisting>
+
+ <para>
+ Similarly, we don't need to iterate over the children when saving or deleting a <literal>Parent</literal>.
+ The following removes <literal>p</literal> and all its children from the database.
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+session.delete(p);
+session.flush();]]></programlisting>
+
+ <para>
+ However, this code
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+c.setParent(null);
+session.flush();]]></programlisting>
+
+ <para>
+ will not remove <literal>c</literal> from the database; it will ony remove the link to <literal>p</literal>
+ (and cause a <literal>NOT NULL</literal> constraint violation, in this case). You need to explicitly
+ <literal>delete()</literal> the <literal>Child</literal>.
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+session.delete(c);
+session.flush();]]></programlisting>
+
+ <para>
+ Now, in our case, a <literal>Child</literal> can't really exist without its parent. So if we remove
+ a <literal>Child</literal> from the collection, we really do want it to be deleted. For this, we must
+ use <literal>cascade="all-delete-orphan"</literal>.
+ </para>
+
+ <programlisting><![CDATA[<set name="children" inverse="true" cascade="all-delete-orphan">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+ <para>
+ Note: even though the collection mapping specifies <literal>inverse="true"</literal>, cascades are
+ still processed by iterating the collection elements. So if you require that an object be saved,
+ deleted or updated by cascade, you must add it to the collection. It is not enough to simply call
+ <literal>setParent()</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="example-parentchild-update">
+ <title>Cascades and <literal>unsaved-value</literal></title>
+
+ <para>
+ Suppose we loaded up a <literal>Parent</literal> in one <literal>Session</literal>, made some changes
+ in a UI action and wish to persist these changes in a new session by calling <literal>update()</literal>.
+ The <literal>Parent</literal> will contain a collection of childen and, since cascading update is enabled,
+ Hibernate needs to know which children are newly instantiated and which represent existing rows in the
+ database. Lets assume that both <literal>Parent</literal> and <literal>Child</literal> have genenerated
+ identifier properties of type <literal>Long</literal>. Hibernate will use the identifier and
+ version/timestamp property value to determine which of the children are new. (See
+ <xref linkend="objectstate-saveorupdate"/>.) <emphasis>In Hibernate3, it is no longer necessary to specify
+ an <literal>unsaved-value</literal> explicitly.</emphasis>
+ </para>
+
+ <para>
+ The following code will update <literal>parent</literal> and <literal>child</literal> and insert
+ <literal>newChild</literal>.
+ </para>
+
+ <programlisting><![CDATA[//parent and child were both loaded in a previous session
+parent.addChild(child);
+Child newChild = new Child();
+parent.addChild(newChild);
+session.update(parent);
+session.flush();]]></programlisting>
+
+ <para>
+ Well, that's all very well for the case of a generated identifier, but what about assigned identifiers
+ and composite identifiers? This is more difficult, since Hibernate can't use the identifier property to
+ distinguish between a newly instantiated object (with an identifier assigned by the user) and an
+ object loaded in a previous session. In this case, Hibernate will either use the timestamp or version
+ property, or will actually query the second-level cache or, worst case, the database, to see if the
+ row exists.
+ </para>
+
+ <!-- undocumenting
+ <para>
+ There is one further possibility. The <literal>Interceptor</literal> method named
+ <literal>isUnsaved()</literal> lets the application implement its own strategy for distinguishing
+ newly instantiated objects. For example, you could define a base class for your persistent classes.
+ </para>
+
+ <programlisting><![CDATA[public class Persistent {
+ private boolean _saved = false;
+ public void onSave() {
+ _saved=true;
+ }
+ public void onLoad() {
+ _saved=true;
+ }
+ ......
+ public boolean isSaved() {
+ return _saved;
+ }
+}]]></programlisting>
+
+ <para>
+ (The <literal>saved</literal> property is non-persistent.)
+ Now implement <literal>isUnsaved()</literal>, along with <literal>onLoad()</literal>
+ and <literal>onSave()</literal> as follows.
+ </para>
+
+ <programlisting><![CDATA[public Boolean isUnsaved(Object entity) {
+ if (entity instanceof Persistent) {
+ return new Boolean( !( (Persistent) entity ).isSaved() );
+ }
+ else {
+ return null;
+ }
+}
+
+public boolean onLoad(Object entity,
+ Serializable id,
+ Object[] state,
+ String[] propertyNames,
+ Type[] types) {
+
+ if (entity instanceof Persistent) ( (Persistent) entity ).onLoad();
+ return false;
+}
+
+public boolean onSave(Object entity,
+ Serializable id,
+ Object[] state,
+ String[] propertyNames,
+ Type[] types) {
+
+ if (entity instanceof Persistent) ( (Persistent) entity ).onSave();
+ return false;
+}]]></programlisting>
+
+ <para>
+ Don't worry; in Hibernate3 you don't need to write any of this kind of code if you don't want to.
+ </para>
+ -->
+ </sect1>
+
+ <sect1 id="example-parentchild-conclusion">
+ <title>Conclusion</title>
+
+ <para>
+ There is quite a bit to digest here and it might look confusing first time around. However, in practice,
+ it all works out very nicely. Most Hibernate applications use the parent / child pattern in many places.
+ </para>
+
+ <para>
+ We mentioned an alternative in the first paragraph. None of the above issues exist in the case of
+ <literal><composite-element></literal> mappings, which have exactly the semantics of a parent / child
+ relationship. Unfortunately, there are two big limitations to composite element classes: composite elements
+ may not own collections, and they should not be the child of any entity other than the unique parent.
+ </para>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/example_weblog.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/example_weblog.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/example_weblog.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,432 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="example-weblog">
+ <title>Example: Weblog Application</title>
+
+ <sect1 id="example-weblog-classes">
+ <title>Persistent Classes</title>
+
+ <para>
+ The persistent classes represent a weblog, and an item posted
+ in a weblog. They are to be modelled as a standard parent/child
+ relationship, but we will use an ordered bag, instead of a set.
+ </para>
+
+ <programlisting><![CDATA[package eg;
+
+import java.util.List;
+
+public class Blog {
+ private Long _id;
+ private String _name;
+ private List _items;
+
+ public Long getId() {
+ return _id;
+ }
+ public List getItems() {
+ return _items;
+ }
+ public String getName() {
+ return _name;
+ }
+ public void setId(Long long1) {
+ _id = long1;
+ }
+ public void setItems(List list) {
+ _items = list;
+ }
+ public void setName(String string) {
+ _name = string;
+ }
+}]]></programlisting>
+
+ <programlisting><![CDATA[package eg;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+
+public class BlogItem {
+ private Long _id;
+ private Calendar _datetime;
+ private String _text;
+ private String _title;
+ private Blog _blog;
+
+ public Blog getBlog() {
+ return _blog;
+ }
+ public Calendar getDatetime() {
+ return _datetime;
+ }
+ public Long getId() {
+ return _id;
+ }
+ public String getText() {
+ return _text;
+ }
+ public String getTitle() {
+ return _title;
+ }
+ public void setBlog(Blog blog) {
+ _blog = blog;
+ }
+ public void setDatetime(Calendar calendar) {
+ _datetime = calendar;
+ }
+ public void setId(Long long1) {
+ _id = long1;
+ }
+ public void setText(String string) {
+ _text = string;
+ }
+ public void setTitle(String string) {
+ _title = string;
+ }
+}]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="example-weblog-mappings">
+ <title>Hibernate Mappings</title>
+
+ <para>
+ The XML mappings should now be quite straightforward.
+ </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">
+
+<hibernate-mapping package="eg">
+
+ <class
+ name="Blog"
+ table="BLOGS">
+
+ <id
+ name="id"
+ column="BLOG_ID">
+
+ <generator class="native"/>
+
+ </id>
+
+ <property
+ name="name"
+ column="NAME"
+ not-null="true"
+ unique="true"/>
+
+ <bag
+ name="items"
+ inverse="true"
+ order-by="DATE_TIME"
+ cascade="all">
+
+ <key column="BLOG_ID"/>
+ <one-to-many class="BlogItem"/>
+
+ </bag>
+
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <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">
+
+<hibernate-mapping package="eg">
+
+ <class
+ name="BlogItem"
+ table="BLOG_ITEMS"
+ dynamic-update="true">
+
+ <id
+ name="id"
+ column="BLOG_ITEM_ID">
+
+ <generator class="native"/>
+
+ </id>
+
+ <property
+ name="title"
+ column="TITLE"
+ not-null="true"/>
+
+ <property
+ name="text"
+ column="TEXT"
+ not-null="true"/>
+
+ <property
+ name="datetime"
+ column="DATE_TIME"
+ not-null="true"/>
+
+ <many-to-one
+ name="blog"
+ column="BLOG_ID"
+ not-null="true"/>
+
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="example-weblog-code">
+ <title>Hibernate Code</title>
+
+ <para>
+ The following class demonstrates some of the kinds of things
+ we can do with these classes, using Hibernate.
+ </para>
+
+ <programlisting><![CDATA[package eg;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+
+public class BlogMain {
+
+ private SessionFactory _sessions;
+
+ public void configure() throws HibernateException {
+ _sessions = new Configuration()
+ .addClass(Blog.class)
+ .addClass(BlogItem.class)
+ .buildSessionFactory();
+ }
+
+ public void exportTables() throws HibernateException {
+ Configuration cfg = new Configuration()
+ .addClass(Blog.class)
+ .addClass(BlogItem.class);
+ new SchemaExport(cfg).create(true, true);
+ }
+
+ public Blog createBlog(String name) throws HibernateException {
+
+ Blog blog = new Blog();
+ blog.setName(name);
+ blog.setItems( new ArrayList() );
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ try {
+ tx = session.beginTransaction();
+ session.persist(blog);
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return blog;
+ }
+
+ public BlogItem createBlogItem(Blog blog, String title, String text)
+ throws HibernateException {
+
+ BlogItem item = new BlogItem();
+ item.setTitle(title);
+ item.setText(text);
+ item.setBlog(blog);
+ item.setDatetime( Calendar.getInstance() );
+ blog.getItems().add(item);
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ try {
+ tx = session.beginTransaction();
+ session.update(blog);
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return item;
+ }
+
+ public BlogItem createBlogItem(Long blogid, String title, String text)
+ throws HibernateException {
+
+ BlogItem item = new BlogItem();
+ item.setTitle(title);
+ item.setText(text);
+ item.setDatetime( Calendar.getInstance() );
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ try {
+ tx = session.beginTransaction();
+ Blog blog = (Blog) session.load(Blog.class, blogid);
+ item.setBlog(blog);
+ blog.getItems().add(item);
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return item;
+ }
+
+ public void updateBlogItem(BlogItem item, String text)
+ throws HibernateException {
+
+ item.setText(text);
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ try {
+ tx = session.beginTransaction();
+ session.update(item);
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ }
+
+ public void updateBlogItem(Long itemid, String text)
+ throws HibernateException {
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ try {
+ tx = session.beginTransaction();
+ BlogItem item = (BlogItem) session.load(BlogItem.class, itemid);
+ item.setText(text);
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ }
+
+ public List listAllBlogNamesAndItemCounts(int max)
+ throws HibernateException {
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ List result = null;
+ try {
+ tx = session.beginTransaction();
+ Query q = session.createQuery(
+ "select blog.id, blog.name, count(blogItem) " +
+ "from Blog as blog " +
+ "left outer join blog.items as blogItem " +
+ "group by blog.name, blog.id " +
+ "order by max(blogItem.datetime)"
+ );
+ q.setMaxResults(max);
+ result = q.list();
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return result;
+ }
+
+ public Blog getBlogAndAllItems(Long blogid)
+ throws HibernateException {
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ Blog blog = null;
+ try {
+ tx = session.beginTransaction();
+ Query q = session.createQuery(
+ "from Blog as blog " +
+ "left outer join fetch blog.items " +
+ "where blog.id = :blogid"
+ );
+ q.setParameter("blogid", blogid);
+ blog = (Blog) q.uniqueResult();
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return blog;
+ }
+
+ public List listBlogsAndRecentItems() throws HibernateException {
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ List result = null;
+ try {
+ tx = session.beginTransaction();
+ Query q = session.createQuery(
+ "from Blog as blog " +
+ "inner join blog.items as blogItem " +
+ "where blogItem.datetime > :minDate"
+ );
+
+ Calendar cal = Calendar.getInstance();
+ cal.roll(Calendar.MONTH, false);
+ q.setCalendar("minDate", cal);
+
+ result = q.list();
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return result;
+ }
+}]]></programlisting>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/filters.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/filters.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/filters.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,148 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="filters">
+ <title>Filtering data</title>
+
+ <para>
+ Hibernate3 provides an innovative new approach to handling data with "visibility" rules.
+ A <emphasis>Hibernate filter</emphasis> is a global, named, parameterized filter that may be
+ enabled or disabled for a particular Hibernate session.
+ </para>
+
+ <sect1 id="objectstate-filters" revision="1">
+ <title>Hibernate filters</title>
+
+ <para>
+ Hibernate3 adds the ability to pre-define filter criteria and attach those filters at both
+ a class and a collection level. A filter criteria is the ability to define a restriction clause
+ very similiar to the existing "where" attribute available on the class and various collection
+ elements. Except these filter conditions can be parameterized. The application can then make
+ the decision at runtime whether given filters should be enabled and what their parameter
+ values should be. Filters can be used like database views, but parameterized inside the
+ application.
+ </para>
+
+ <para>
+ In order to use filters, they must first be defined and then attached to the appropriate
+ mapping elements. To define a filter, use the <literal><filter-def/></literal> element
+ within a <literal><hibernate-mapping/></literal> element:
+ </para>
+
+ <programlisting><![CDATA[<filter-def name="myFilter">
+ <filter-param name="myFilterParam" type="string"/>
+</filter-def>]]></programlisting>
+
+ <para>
+ Then, this filter can be attached to a class:
+ </para>
+
+ <programlisting><![CDATA[<class name="myClass" ...>
+ ...
+ <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</class>]]></programlisting>
+
+ <para>
+ or, to a collection:
+ </para>
+
+ <programlisting><![CDATA[<set ...>
+ <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</set>]]></programlisting>
+
+ <para>
+ or, even to both (or multiples of each) at the same time.
+ </para>
+
+ <para>
+ The methods on <literal>Session</literal> are: <literal>enableFilter(String filterName)</literal>,
+ <literal>getEnabledFilter(String filterName)</literal>, and <literal>disableFilter(String filterName)</literal>.
+ By default, filters are <emphasis>not</emphasis> enabled for a given session; they must be explcitly
+ enabled through use of the <literal>Session.enabledFilter()</literal> method, which returns an
+ instance of the <literal>Filter</literal> interface. Using the simple filter defined above, this
+ would look like:
+ </para>
+
+ <programlisting><![CDATA[session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");]]></programlisting>
+
+ <para>
+ Note that methods on the org.hibernate.Filter interface do allow the method-chaining common to much of Hibernate.
+ </para>
+
+ <para>
+ A full example, using temporal data with an effective record date pattern:
+ </para>
+
+ <programlisting><![CDATA[<filter-def name="effectiveDate">
+ <filter-param name="asOfDate" type="date"/>
+</filter-def>
+
+<class name="Employee" ...>
+...
+ <many-to-one name="department" column="dept_id" class="Department"/>
+ <property name="effectiveStartDate" type="date" column="eff_start_dt"/>
+ <property name="effectiveEndDate" type="date" column="eff_end_dt"/>
+...
+ <!--
+ Note that this assumes non-terminal records have an eff_end_dt set to
+ a max db date for simplicity-sake
+ -->
+ <filter name="effectiveDate"
+ condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+</class>
+
+<class name="Department" ...>
+...
+ <set name="employees" lazy="true">
+ <key column="dept_id"/>
+ <one-to-many class="Employee"/>
+ <filter name="effectiveDate"
+ condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+ </set>
+</class>]]></programlisting>
+
+ <para>
+ Then, in order to ensure that you always get back currently effective records, simply
+ enable the filter on the session prior to retrieving employee data:
+ </para>
+
+<programlisting><![CDATA[Session session = ...;
+session.enabledFilter("effectiveDate").setParameter("asOfDate", new Date());
+List results = session.createQuery("from Employee as e where e.salary > :targetSalary")
+ .setLong("targetSalary", new Long(1000000))
+ .list();
+]]></programlisting>
+
+ <para>
+ In the HQL above, even though we only explicitly mentioned a salary constraint on the results,
+ because of the enabled filter the query will return only currently active employees who have
+ a salary greater than a million dollars.
+ </para>
+
+ <para>
+ Note: if you plan on using filters with outer joining (either through HQL or load fetching) be
+ careful of the direction of the condition expression. Its safest to set this up for left
+ outer joining; in general, place the parameter first followed by the column name(s) after
+ the operator.
+ </para>
+
+ <para>
+ After being defined a filter might be attached to multiple entities and/or
+ collections each with its own condition. That can be tedious when the
+ conditions are the same each time. Thus <literal><filter-def/></literal>
+ allows defining a default condition, either as an attribute or CDATA:
+ </para>
+
+ <programlisting><![CDATA[<filter-def name="myFilter" condition="abc > xyz">...</filter-def>
+<filter-def name="myOtherFilter">abc=xyz</filter-def>]]></programlisting>
+
+ <para>
+ This default condition will then be used whenever the filter is attached to something
+ without specifying a condition. Note that this means you can give a specific condition
+ as part of the attachment of the filter which overrides the default condition in that
+ particular case.
+ </para>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/inheritance_mapping.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/inheritance_mapping.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/inheritance_mapping.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,493 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="inheritance">
+ <title>Inheritance Mapping</title>
+
+ <sect1 id="inheritance-strategies" revision="3">
+ <title>The Three Strategies</title>
+
+ <para>
+ Hibernate supports the three basic inheritance mapping strategies:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ table per class hierarchy
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ table per subclass
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ table per concrete class
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ In addition, Hibernate supports a fourth, slightly different kind of
+ polymorphism:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ implicit polymorphism
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ It is possible to use different mapping strategies for different
+ branches of the same inheritance hierarchy, and then make use of implicit
+ polymorphism to achieve polymorphism across the whole hierarchy. However,
+ Hibernate does not support mixing <literal><subclass></literal>,
+ and <literal><joined-subclass></literal> and
+ <literal><union-subclass></literal> mappings under the same root
+ <literal><class></literal> element. It is possible to mix together
+ the table per hierarchy and table per subclass strategies, under the
+ the same <literal><class></literal> element, by combining the
+ <literal><subclass></literal> and <literal><join></literal>
+ elements (see below).
+ </para>
+
+ <para>
+ It is possible to define <literal>subclass</literal>, <literal>union-subclass</literal>,
+ and <literal>joined-subclass</literal> mappings in separate mapping documents, directly beneath
+ <literal>hibernate-mapping</literal>. This allows you to extend a class hierachy just by adding
+ a new mapping file. You must specify an <literal>extends</literal> attribute in the subclass mapping,
+ naming a previously mapped superclass. Note: Previously this feature made the ordering of the mapping
+ documents important. Since Hibernate3, the ordering of mapping files does not matter when using the
+ extends keyword. The ordering inside a single mapping file still needs to be defined as superclasses
+ before subclasses.
+ </para>
+
+ <programlisting><![CDATA[
+ <hibernate-mapping>
+ <subclass name="DomesticCat" extends="Cat" discriminator-value="D">
+ <property name="name" type="string"/>
+ </subclass>
+ </hibernate-mapping>]]></programlisting>
+
+
+ <sect2 id="inheritance-tableperclass" >
+ <title>Table per class hierarchy</title>
+
+ <para>
+ Suppose we have an interface <literal>Payment</literal>, with implementors
+ <literal>CreditCardPayment</literal>, <literal>CashPayment</literal>,
+ <literal>ChequePayment</literal>. The table per hierarchy mapping would
+ look like:
+ </para>
+
+ <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+ <id name="id" type="long" column="PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <discriminator column="PAYMENT_TYPE" type="string"/>
+ <property name="amount" column="AMOUNT"/>
+ ...
+ <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+ <property name="creditCardType" column="CCTYPE"/>
+ ...
+ </subclass>
+ <subclass name="CashPayment" discriminator-value="CASH">
+ ...
+ </subclass>
+ <subclass name="ChequePayment" discriminator-value="CHEQUE">
+ ...
+ </subclass>
+</class>]]></programlisting>
+
+ <para>
+ Exactly one table is required. There is one big limitation of this mapping
+ strategy: columns declared by the subclasses, such as <literal>CCTYPE</literal>,
+ may not have <literal>NOT NULL</literal> constraints.
+ </para>
+
+ </sect2>
+
+ <sect2 id="inheritance-tablepersubclass">
+ <title>Table per subclass</title>
+
+ <para>
+ A table per subclass mapping would look like:
+ </para>
+
+ <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+ <id name="id" type="long" column="PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <property name="amount" column="AMOUNT"/>
+ ...
+ <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ <property name="creditCardType" column="CCTYPE"/>
+ ...
+ </joined-subclass>
+ <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ ...
+ </joined-subclass>
+ <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ ...
+ </joined-subclass>
+</class>]]></programlisting>
+
+ <para>
+ Four tables are required. The three subclass tables have primary
+ key associations to the superclass table (so the relational model
+ is actually a one-to-one association).
+ </para>
+
+ </sect2>
+
+ <sect2 id="inheritance-tablepersubclass-discriminator" revision="2">
+ <title>Table per subclass, using a discriminator</title>
+
+ <para>
+ Note that Hibernate's implementation of table per subclass requires
+ no discriminator column. Other object/relational mappers use a
+ different implementation of table per subclass which requires a type
+ discriminator column in the superclass table. The approach taken by
+ Hibernate is much more difficult to implement but arguably more
+ correct from a relational point of view. If you would like to use
+ a discriminator column with the table per subclass strategy, you
+ may combine the use of <literal><subclass></literal> and
+ <literal><join></literal>, as follow:
+ </para>
+
+ <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+ <id name="id" type="long" column="PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <discriminator column="PAYMENT_TYPE" type="string"/>
+ <property name="amount" column="AMOUNT"/>
+ ...
+ <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+ <join table="CREDIT_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ <property name="creditCardType" column="CCTYPE"/>
+ ...
+ </join>
+ </subclass>
+ <subclass name="CashPayment" discriminator-value="CASH">
+ <join table="CASH_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ ...
+ </join>
+ </subclass>
+ <subclass name="ChequePayment" discriminator-value="CHEQUE">
+ <join table="CHEQUE_PAYMENT" fetch="select">
+ <key column="PAYMENT_ID"/>
+ ...
+ </join>
+ </subclass>
+</class>]]></programlisting>
+
+ <para>
+ The optional <literal>fetch="select"</literal> declaration tells Hibernate
+ not to fetch the <literal>ChequePayment</literal> subclass data using an
+ outer join when querying the superclass.
+ </para>
+
+ </sect2>
+
+ <sect2 id="inheritance-mixing-tableperclass-tablepersubclass">
+ <title>Mixing table per class hierarchy with table per subclass</title>
+
+ <para>
+ You may even mix the table per hierarchy and table per subclass strategies
+ using this approach:
+ </para>
+
+ <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+ <id name="id" type="long" column="PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <discriminator column="PAYMENT_TYPE" type="string"/>
+ <property name="amount" column="AMOUNT"/>
+ ...
+ <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+ <join table="CREDIT_PAYMENT">
+ <property name="creditCardType" column="CCTYPE"/>
+ ...
+ </join>
+ </subclass>
+ <subclass name="CashPayment" discriminator-value="CASH">
+ ...
+ </subclass>
+ <subclass name="ChequePayment" discriminator-value="CHEQUE">
+ ...
+ </subclass>
+</class>]]></programlisting>
+
+ <para>
+ For any of these mapping strategies, a polymorphic association to the root
+ <literal>Payment</literal> class is mapped using
+ <literal><many-to-one></literal>.
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="inheritance-tableperconcrete" revision="2">
+ <title>Table per concrete class</title>
+
+ <para>
+ There are two ways we could go about mapping the table per concrete class
+ strategy. The first is to use <literal><union-subclass></literal>.
+ </para>
+
+ <programlisting><![CDATA[<class name="Payment">
+ <id name="id" type="long" column="PAYMENT_ID">
+ <generator class="sequence"/>
+ </id>
+ <property name="amount" column="AMOUNT"/>
+ ...
+ <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+ <property name="creditCardType" column="CCTYPE"/>
+ ...
+ </union-subclass>
+ <union-subclass name="CashPayment" table="CASH_PAYMENT">
+ ...
+ </union-subclass>
+ <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+ ...
+ </union-subclass>
+</class>]]></programlisting>
+
+ <para>
+ Three tables are involved for the subclasses. Each table defines columns for
+ all properties of the class, including inherited properties.
+ </para>
+
+ <para>
+ The limitation of this approach is that if a property is mapped on the
+ superclass, the column name must be the same on all subclass tables.
+ (We might relax this in a future release of Hibernate.) The identity
+ generator strategy is not allowed in union subclass inheritance, indeed
+ the primary key seed has to be shared accross all unioned subclasses
+ of a hierarchy.
+ </para>
+
+ <para>
+ If your superclass is abstract, map it with <literal>abstract="true"</literal>.
+ Of course, if it is not abstract, an additional table (defaults to
+ <literal>PAYMENT</literal> in the example above) is needed to hold instances
+ of the superclass.
+ </para>
+
+ </sect2>
+
+ <sect2 id="inheritance-tableperconcreate-polymorphism">
+ <title>Table per concrete class, using implicit polymorphism</title>
+
+ <para>
+ An alternative approach is to make use of implicit polymorphism:
+ </para>
+
+ <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+ <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <property name="amount" column="CREDIT_AMOUNT"/>
+ ...
+</class>
+
+<class name="CashPayment" table="CASH_PAYMENT">
+ <id name="id" type="long" column="CASH_PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <property name="amount" column="CASH_AMOUNT"/>
+ ...
+</class>
+
+<class name="ChequePayment" table="CHEQUE_PAYMENT">
+ <id name="id" type="long" column="CHEQUE_PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <property name="amount" column="CHEQUE_AMOUNT"/>
+ ...
+</class>]]></programlisting>
+
+ <para>
+ Notice that nowhere do we mention the <literal>Payment</literal> interface
+ explicitly. Also notice that properties of <literal>Payment</literal> are
+ mapped in each of the subclasses. If you want to avoid duplication, consider
+ using XML entities
+ (e.g. <literal>[ <!ENTITY allproperties SYSTEM "allproperties.xml"> ]</literal>
+ in the <literal>DOCTYPE</literal> declartion and
+ <literal>&allproperties;</literal> in the mapping).
+ </para>
+
+ <para>
+ The disadvantage of this approach is that Hibernate does not generate SQL
+ <literal>UNION</literal>s when performing polymorphic queries.
+ </para>
+
+ <para>
+ For this mapping strategy, a polymorphic association to <literal>Payment</literal>
+ is usually mapped using <literal><any></literal>.
+ </para>
+
+ <programlisting><![CDATA[<any name="payment" meta-type="string" id-type="long">
+ <meta-value value="CREDIT" class="CreditCardPayment"/>
+ <meta-value value="CASH" class="CashPayment"/>
+ <meta-value value="CHEQUE" class="ChequePayment"/>
+ <column name="PAYMENT_CLASS"/>
+ <column name="PAYMENT_ID"/>
+</any>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="inheritace-mixingpolymorphism">
+ <title>Mixing implicit polymorphism with other inheritance mappings</title>
+
+ <para>
+ There is one further thing to notice about this mapping. Since the subclasses
+ are each mapped in their own <literal><class></literal> element (and since
+ <literal>Payment</literal> is just an interface), each of the subclasses could
+ easily be part of another inheritance hierarchy! (And you can still use polymorphic
+ queries against the <literal>Payment</literal> interface.)
+ </para>
+
+ <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+ <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <discriminator column="CREDIT_CARD" type="string"/>
+ <property name="amount" column="CREDIT_AMOUNT"/>
+ ...
+ <subclass name="MasterCardPayment" discriminator-value="MDC"/>
+ <subclass name="VisaPayment" discriminator-value="VISA"/>
+</class>
+
+<class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
+ <id name="id" type="long" column="TXN_ID">
+ <generator class="native"/>
+ </id>
+ ...
+ <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ <property name="amount" column="CASH_AMOUNT"/>
+ ...
+ </joined-subclass>
+ <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ <property name="amount" column="CHEQUE_AMOUNT"/>
+ ...
+ </joined-subclass>
+</class>]]></programlisting>
+
+ <para>
+ Once again, we don't mention <literal>Payment</literal> explicitly. If we
+ execute a query against the <literal>Payment</literal> interface - for
+ example, <literal>from Payment</literal> - Hibernate
+ automatically returns instances of <literal>CreditCardPayment</literal>
+ (and its subclasses, since they also implement <literal>Payment</literal>),
+ <literal>CashPayment</literal> and <literal>ChequePayment</literal> but
+ not instances of <literal>NonelectronicTransaction</literal>.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="inheritance-limitations">
+ <title>Limitations</title>
+
+ <para>
+ There are certain limitations to the "implicit polymorphism" approach to
+ the table per concrete-class mapping strategy. There are somewhat less
+ restrictive limitations to <literal><union-subclass></literal>
+ mappings.
+ </para>
+
+ <para>
+ The following table shows the limitations of table per concrete-class
+ mappings, and of implicit polymorphism, in Hibernate.
+ </para>
+
+ <table frame="topbot">
+ <title>Features of inheritance mappings</title>
+ <tgroup cols='8' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <colspec colname='c3' colwidth="1*"/>
+ <colspec colname='c4' colwidth="1*"/>
+ <colspec colname='c5' colwidth="1*"/>
+ <colspec colname='c6' colwidth="1*"/>
+ <colspec colname='c7' colwidth="1*"/>
+ <colspec colname='c8' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Inheritance strategy</entry>
+ <entry>Polymorphic many-to-one</entry>
+ <entry>Polymorphic one-to-one</entry>
+ <entry>Polymorphic one-to-many</entry>
+ <entry>Polymorphic many-to-many</entry>
+ <entry>Polymorphic <literal>load()/get()</literal></entry>
+ <entry>Polymorphic queries</entry>
+ <entry>Polymorphic joins</entry>
+ <entry>Outer join fetching</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>table per class-hierarchy</entry>
+ <entry><literal><many-to-one></literal></entry>
+ <entry><literal><one-to-one></literal></entry>
+ <entry><literal><one-to-many></literal></entry>
+ <entry><literal><many-to-many></literal></entry>
+ <entry><literal>s.get(Payment.class, id)</literal></entry>
+ <entry><literal>from Payment p</literal></entry>
+ <entry><literal>from Order o join o.payment p</literal></entry>
+ <entry><emphasis>supported</emphasis></entry>
+ </row>
+ <row>
+ <entry>table per subclass</entry>
+ <entry><literal><many-to-one></literal></entry>
+ <entry><literal><one-to-one></literal></entry>
+ <entry><literal><one-to-many></literal></entry>
+ <entry><literal><many-to-many></literal></entry>
+ <entry><literal>s.get(Payment.class, id)</literal></entry>
+ <entry><literal>from Payment p</literal></entry>
+ <entry><literal>from Order o join o.payment p</literal></entry>
+ <entry><emphasis>supported</emphasis></entry>
+ </row>
+ <row>
+ <entry>table per concrete-class (union-subclass)</entry>
+ <entry><literal><many-to-one></literal></entry>
+ <entry><literal><one-to-one></literal></entry>
+ <entry><literal><one-to-many></literal> (for <literal>inverse="true"</literal> only)</entry>
+ <entry><literal><many-to-many></literal></entry>
+ <entry><literal>s.get(Payment.class, id)</literal></entry>
+ <entry><literal>from Payment p</literal></entry>
+ <entry><literal>from Order o join o.payment p</literal></entry>
+ <entry><emphasis>supported</emphasis></entry>
+ </row>
+ <row>
+ <entry>table per concrete class (implicit polymorphism)</entry>
+ <entry><literal><any></literal></entry>
+ <entry><emphasis>not supported</emphasis></entry>
+ <entry><emphasis>not supported</emphasis></entry>
+ <entry><literal><many-to-any></literal></entry>
+ <entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
+ <entry><literal>from Payment p</literal></entry>
+ <entry><emphasis>not supported</emphasis></entry>
+ <entry><emphasis>not supported</emphasis></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/performance.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/performance.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/performance.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,1390 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="performance">
+ <title>Improving performance</title>
+
+ <sect1 id="performance-fetching" revision="2">
+ <title>Fetching strategies</title>
+
+ <para>
+ A <emphasis>fetching strategy</emphasis> is the strategy Hibernate will use for
+ retrieving associated objects if the application needs to navigate the association.
+ Fetch strategies may be declared in the O/R mapping metadata, or over-ridden by a
+ particular HQL or <literal>Criteria</literal> query.
+ </para>
+
+ <para>
+ Hibernate3 defines the following fetching strategies:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Join fetching</emphasis> - Hibernate retrieves the
+ associated instance or collection in the same <literal>SELECT</literal>,
+ using an <literal>OUTER JOIN</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Select fetching</emphasis> - a second <literal>SELECT</literal>
+ is used to retrieve the associated entity or collection. Unless
+ you explicitly disable lazy fetching by specifying <literal>lazy="false"</literal>,
+ this second select will only be executed when you actually access the
+ association.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Subselect fetching</emphasis> - a second <literal>SELECT</literal>
+ is used to retrieve the associated collections for all entities retrieved in a
+ previous query or fetch. Unless you explicitly disable lazy fetching by specifying
+ <literal>lazy="false"</literal>, this second select will only be executed when you
+ actually access the association.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Batch fetching</emphasis> - an optimization strategy
+ for select fetching - Hibernate retrieves a batch of entity instances
+ or collections in a single <literal>SELECT</literal>, by specifying
+ a list of primary keys or foreign keys.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Hibernate also distinguishes between:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Immediate fetching</emphasis> - an association, collection or
+ attribute is fetched immediately, when the owner is loaded.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Lazy collection fetching</emphasis> - a collection is fetched
+ when the application invokes an operation upon that collection. (This
+ is the default for collections.)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>"Extra-lazy" collection fetching</emphasis> - individual
+ elements of the collection are accessed from the database as needed.
+ Hibernate tries not to fetch the whole collection into memory unless
+ absolutely needed (suitable for very large collections)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Proxy fetching</emphasis> - a single-valued association is
+ fetched when a method other than the identifier getter is invoked
+ upon the associated object.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>"No-proxy" fetching</emphasis> - a single-valued association is
+ fetched when the instance variable is accessed. Compared to proxy fetching,
+ this approach is less lazy (the association is fetched even when only the
+ identifier is accessed) but more transparent, since no proxy is visible to
+ the application. This approach requires buildtime bytecode instrumentation
+ and is rarely necessary.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Lazy attribute fetching</emphasis> - an attribute or single
+ valued association is fetched when the instance variable is accessed.
+ This approach requires buildtime bytecode instrumentation and is rarely
+ necessary.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ We have two orthogonal notions here: <emphasis>when</emphasis> is the association
+ fetched, and <emphasis>how</emphasis> is it fetched (what SQL is used). Don't
+ confuse them! We use <literal>fetch</literal> to tune performance. We may use
+ <literal>lazy</literal> to define a contract for what data is always available
+ in any detached instance of a particular class.
+ </para>
+
+ <sect2 id="performance-fetching-lazy">
+ <title>Working with lazy associations</title>
+
+ <para>
+ By default, Hibernate3 uses lazy select fetching for collections and lazy proxy
+ fetching for single-valued associations. These defaults make sense for almost
+ all associations in almost all applications.
+ </para>
+
+ <para>
+ <emphasis>Note:</emphasis> if you set
+ <literal>hibernate.default_batch_fetch_size</literal>, Hibernate will use the
+ batch fetch optimization for lazy fetching (this optimization may also be enabled
+ at a more granular level).
+ </para>
+
+ <para>
+ However, lazy fetching poses one problem that you must be aware of. Access to a
+ lazy association outside of the context of an open Hibernate session will result
+ in an exception. For example:
+ </para>
+
+ <programlisting><![CDATA[s = sessions.openSession();
+Transaction tx = s.beginTransaction();
+
+User u = (User) s.createQuery("from User u where u.name=:userName")
+ .setString("userName", userName).uniqueResult();
+Map permissions = u.getPermissions();
+
+tx.commit();
+s.close();
+
+Integer accessLevel = (Integer) permissions.get("accounts"); // Error!]]></programlisting>
+
+ <para>
+ Since the permissions collection was not initialized when the
+ <literal>Session</literal> was closed, the collection will not be able to
+ load its state. <emphasis>Hibernate does not support lazy initialization
+ for detached objects</emphasis>. The fix is to move the code that reads
+ from the collection to just before the transaction is committed.
+ </para>
+
+ <para>
+ Alternatively, we could use a non-lazy collection or association,
+ by specifying <literal>lazy="false"</literal> for the association mapping.
+ However, it is intended that lazy initialization be used for almost all
+ collections and associations. If you define too many non-lazy associations
+ in your object model, Hibernate will end up needing to fetch the entire
+ database into memory in every transaction!
+ </para>
+
+ <para>
+ On the other hand, we often want to choose join fetching (which is non-lazy by
+ nature) instead of select fetching in a particular transaction. We'll now see
+ how to customize the fetching strategy. In Hibernate3, the mechanisms for
+ choosing a fetch strategy are identical for single-valued associations and
+ collections.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-fetching-custom" revision="4">
+ <title>Tuning fetch strategies</title>
+
+ <para>
+ Select fetching (the default) is extremely vulnerable to N+1 selects problems,
+ so we might want to enable join fetching in the mapping document:
+ </para>
+
+ <programlisting><![CDATA[<set name="permissions"
+ fetch="join">
+ <key column="userId"/>
+ <one-to-many class="Permission"/>
+</set]]></programlisting>
+
+ <programlisting><![CDATA[<many-to-one name="mother" class="Cat" fetch="join"/>]]></programlisting>
+
+ <para>
+ The <literal>fetch</literal> strategy defined in the mapping document affects:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ retrieval via <literal>get()</literal> or <literal>load()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ retrieval that happens implicitly when an association is navigated
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>Criteria</literal> queries
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ HQL queries if <literal>subselect</literal> fetching is used
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ No matter what fetching strategy you use, the defined non-lazy graph is guaranteed
+ to be loaded into memory. Note that this might result in several immediate selects
+ being used to execute a particular HQL query.
+ </para>
+
+ <para>
+ Usually, we don't use the mapping document to customize fetching. Instead, we
+ keep the default behavior, and override it for a particular transaction, using
+ <literal>left join fetch</literal> in HQL. This tells Hibernate to fetch
+ the association eagerly in the first select, using an outer join. In the
+ <literal>Criteria</literal> query API, you would use
+ <literal>setFetchMode(FetchMode.JOIN)</literal>.
+ </para>
+
+ <para>
+ If you ever feel like you wish you could change the fetching strategy used by
+ <literal>get()</literal> or <literal>load()</literal>, simply use a
+ <literal>Criteria</literal> query, for example:
+ </para>
+
+ <programlisting><![CDATA[User user = (User) session.createCriteria(User.class)
+ .setFetchMode("permissions", FetchMode.JOIN)
+ .add( Restrictions.idEq(userId) )
+ .uniqueResult();]]></programlisting>
+
+ <para>
+ (This is Hibernate's equivalent of what some ORM solutions call a "fetch plan".)
+ </para>
+
+ <para>
+ A completely different way to avoid problems with N+1 selects is to use the
+ second-level cache.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-fetching-proxies" revision="2">
+ <title>Single-ended association proxies</title>
+
+ <para>
+ Lazy fetching for collections is implemented using Hibernate's own implementation
+ of persistent collections. However, a different mechanism is needed for lazy
+ behavior in single-ended associations. The target entity of the association must
+ be proxied. Hibernate implements lazy initializing proxies for persistent objects
+ using runtime bytecode enhancement (via the excellent CGLIB library).
+ </para>
+
+ <para>
+ By default, Hibernate3 generates proxies (at startup) for all persistent classes
+ and uses them to enable lazy fetching of <literal>many-to-one</literal> and
+ <literal>one-to-one</literal> associations.
+ </para>
+
+ <para>
+ The mapping file may declare an interface to use as the proxy interface for that
+ class, with the <literal>proxy</literal> attribute. By default, Hibernate uses a subclass
+ of the class. <emphasis>Note that the proxied class must implement a default constructor
+ with at least package visibility. We recommend this constructor for all persistent classes!</emphasis>
+ </para>
+
+ <para>
+ There are some gotchas to be aware of when extending this approach to polymorphic
+ classes, eg.
+ </para>
+
+ <programlisting><![CDATA[<class name="Cat" proxy="Cat">
+ ......
+ <subclass name="DomesticCat">
+ .....
+ </subclass>
+</class>]]></programlisting>
+
+ <para>
+ Firstly, instances of <literal>Cat</literal> will never be castable to
+ <literal>DomesticCat</literal>, even if the underlying instance is an
+ instance of <literal>DomesticCat</literal>:
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id); // instantiate a proxy (does not hit the db)
+if ( cat.isDomesticCat() ) { // hit the db to initialize the proxy
+ DomesticCat dc = (DomesticCat) cat; // Error!
+ ....
+}]]></programlisting>
+
+ <para>
+ Secondly, it is possible to break proxy <literal>==</literal>.
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id); // instantiate a Cat proxy
+DomesticCat dc =
+ (DomesticCat) session.load(DomesticCat.class, id); // acquire new DomesticCat proxy!
+System.out.println(cat==dc); // false]]></programlisting>
+
+ <para>
+ However, the situation is not quite as bad as it looks. Even though we now have two references
+ to different proxy objects, the underlying instance will still be the same object:
+ </para>
+
+ <programlisting><![CDATA[cat.setWeight(11.0); // hit the db to initialize the proxy
+System.out.println( dc.getWeight() ); // 11.0]]></programlisting>
+
+ <para>
+ Third, you may not use a CGLIB proxy for a <literal>final</literal> class or a class
+ with any <literal>final</literal> methods.
+ </para>
+
+ <para>
+ Finally, if your persistent object acquires any resources upon instantiation (eg. in
+ initializers or default constructor), then those resources will also be acquired by
+ the proxy. The proxy class is an actual subclass of the persistent class.
+ </para>
+
+ <para>
+ These problems are all due to fundamental limitations in Java's single inheritance model.
+ If you wish to avoid these problems your persistent classes must each implement an interface
+ that declares its business methods. You should specify these interfaces in the mapping file. eg.
+ </para>
+
+ <programlisting><![CDATA[<class name="CatImpl" proxy="Cat">
+ ......
+ <subclass name="DomesticCatImpl" proxy="DomesticCat">
+ .....
+ </subclass>
+</class>]]></programlisting>
+
+ <para>
+ where <literal>CatImpl</literal> implements the interface <literal>Cat</literal> and
+ <literal>DomesticCatImpl</literal> implements the interface <literal>DomesticCat</literal>. Then
+ proxies for instances of <literal>Cat</literal> and <literal>DomesticCat</literal> may be returned
+ by <literal>load()</literal> or <literal>iterate()</literal>. (Note that <literal>list()</literal>
+ does not usually return proxies.)
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) session.load(CatImpl.class, catid);
+Iterator iter = session.iterate("from CatImpl as cat where cat.name='fritz'");
+Cat fritz = (Cat) iter.next();]]></programlisting>
+
+ <para>
+ Relationships are also lazily initialized. This means you must declare any properties to be of
+ type <literal>Cat</literal>, not <literal>CatImpl</literal>.
+ </para>
+
+ <para>
+ Certain operations do <emphasis>not</emphasis> require proxy initialization
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>equals()</literal>, if the persistent class does not override
+ <literal>equals()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>hashCode()</literal>, if the persistent class does not override
+ <literal>hashCode()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The identifier getter method
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Hibernate will detect persistent classes that override <literal>equals()</literal> or
+ <literal>hashCode()</literal>.
+ </para>
+
+ <para>
+ By choosing <literal>lazy="no-proxy"</literal> instead of the default
+ <literal>lazy="proxy"</literal>, we can avoid the problems associated with typecasting.
+ However, we will require buildtime bytecode instrumentation, and all operations
+ will result in immediate proxy initialization.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-fetching-initialization" revision="1">
+ <title>Initializing collections and proxies</title>
+
+ <para>
+ A <literal>LazyInitializationException</literal> will be thrown by Hibernate if an uninitialized
+ collection or proxy is accessed outside of the scope of the <literal>Session</literal>, ie. when
+ the entity owning the collection or having the reference to the proxy is in the detached state.
+ </para>
+
+ <para>
+ Sometimes we need to ensure that a proxy or collection is initialized before closing the
+ <literal>Session</literal>. Of course, we can alway force initialization by calling
+ <literal>cat.getSex()</literal> or <literal>cat.getKittens().size()</literal>, for example.
+ But that is confusing to readers of the code and is not convenient for generic code.
+ </para>
+
+ <para>
+ The static methods <literal>Hibernate.initialize()</literal> and <literal>Hibernate.isInitialized()</literal>
+ provide the application with a convenient way of working with lazily initialized collections or
+ proxies. <literal>Hibernate.initialize(cat)</literal> will force the initialization of a proxy,
+ <literal>cat</literal>, as long as its <literal>Session</literal> is still open.
+ <literal>Hibernate.initialize( cat.getKittens() )</literal> has a similar effect for the collection
+ of kittens.
+ </para>
+
+ <para>
+ Another option is to keep the <literal>Session</literal> open until all needed
+ collections and proxies have been loaded. In some application architectures,
+ particularly where the code that accesses data using Hibernate, and the code that
+ uses it are in different application layers or different physical processes, it
+ can be a problem to ensure that the <literal>Session</literal> is open when a
+ collection is initialized. There are two basic ways to deal with this issue:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ In a web-based application, a servlet filter can be used to close the
+ <literal>Session</literal> only at the very end of a user request, once
+ the rendering of the view is complete (the <emphasis>Open Session in
+ View</emphasis> pattern). Of course, this places heavy demands on the
+ correctness of the exception handling of your application infrastructure.
+ It is vitally important that the <literal>Session</literal> is closed and the
+ transaction ended before returning to the user, even when an exception occurs
+ during rendering of the view. See the Hibernate Wiki for examples of this
+ "Open Session in View" pattern.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ In an application with a separate business tier, the business logic must
+ "prepare" all collections that will be needed by the web tier before
+ returning. This means that the business tier should load all the data and
+ return all the data already initialized to the presentation/web tier that
+ is required for a particular use case. Usually, the application calls
+ <literal>Hibernate.initialize()</literal> for each collection that will
+ be needed in the web tier (this call must occur before the session is closed)
+ or retrieves the collection eagerly using a Hibernate query with a
+ <literal>FETCH</literal> clause or a <literal>FetchMode.JOIN</literal> in
+ <literal>Criteria</literal>. This is usually easier if you adopt the
+ <emphasis>Command</emphasis> pattern instead of a <emphasis>Session Facade</emphasis>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ You may also attach a previously loaded object to a new <literal>Session</literal>
+ with <literal>merge()</literal> or <literal>lock()</literal> before
+ accessing uninitialized collections (or other proxies). No, Hibernate does not,
+ and certainly <emphasis>should</emphasis> not do this automatically, since it
+ would introduce ad hoc transaction semantics!
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Sometimes you don't want to initialize a large collection, but still need some
+ information about it (like its size) or a subset of the data.
+ </para>
+
+ <para>
+ You can use a collection filter to get the size of a collection without initializing it:
+ </para>
+
+ <programlisting><![CDATA[( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()]]></programlisting>
+
+ <para>
+ The <literal>createFilter()</literal> method is also used to efficiently retrieve subsets
+ of a collection without needing to initialize the whole collection:
+ </para>
+
+ <programlisting><![CDATA[s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="performance-fetching-batch">
+ <title>Using batch fetching</title>
+
+ <para>
+ Hibernate can make efficient use of batch fetching, that is, Hibernate can load several uninitialized
+ proxies if one proxy is accessed (or collections. Batch fetching is an optimization of the lazy select
+ fetching strategy. There are two ways you can tune batch fetching: on the class and the collection level.
+ </para>
+
+ <para>
+ Batch fetching for classes/entities is easier to understand. Imagine you have the following situation
+ at runtime: You have 25 <literal>Cat</literal> instances loaded in a <literal>Session</literal>, each
+ <literal>Cat</literal> has a reference to its <literal>owner</literal>, a <literal>Person</literal>.
+ The <literal>Person</literal> class is mapped with a proxy, <literal>lazy="true"</literal>. If you now
+ iterate through all cats and call <literal>getOwner()</literal> on each, Hibernate will by default
+ execute 25 <literal>SELECT</literal> statements, to retrieve the proxied owners. You can tune this
+ behavior by specifying a <literal>batch-size</literal> in the mapping of <literal>Person</literal>:
+ </para>
+
+ <programlisting><![CDATA[<class name="Person" batch-size="10">...</class>]]></programlisting>
+
+ <para>
+ Hibernate will now execute only three queries, the pattern is 10, 10, 5.
+ </para>
+
+ <para>
+ You may also enable batch fetching of collections. For example, if each <literal>Person</literal> has
+ a lazy collection of <literal>Cat</literal>s, and 10 persons are currently loaded in the
+ <literal>Sesssion</literal>, iterating through all persons will generate 10 <literal>SELECT</literal>s,
+ one for every call to <literal>getCats()</literal>. If you enable batch fetching for the
+ <literal>cats</literal> collection in the mapping of <literal>Person</literal>, Hibernate can pre-fetch
+ collections:
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <set name="cats" batch-size="3">
+ ...
+ </set>
+</class>]]></programlisting>
+
+ <para>
+ With a <literal>batch-size</literal> of 8, Hibernate will load 3, 3, 3, 1 collections in four
+ <literal>SELECT</literal>s. Again, the value of the attribute depends on the expected number of
+ uninitialized collections in a particular <literal>Session</literal>.
+ </para>
+
+ <para>
+ Batch fetching of collections is particularly useful if you have a nested tree of items, ie.
+ the typical bill-of-materials pattern. (Although a <emphasis>nested set</emphasis> or a
+ <emphasis>materialized path</emphasis> might be a better option for read-mostly trees.)
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-fetching-subselect">
+ <title>Using subselect fetching</title>
+
+ <para>
+ If one lazy collection or single-valued proxy has to be fetched, Hibernate loads all of
+ them, re-running the original query in a subselect. This works in the same way as
+ batch-fetching, without the piecemeal loading.
+ </para>
+
+ <!-- TODO: Write more about this -->
+
+ </sect2>
+
+ <sect2 id="performance-fetching-lazyproperties">
+ <title>Using lazy property fetching</title>
+
+ <para>
+ Hibernate3 supports the lazy fetching of individual properties. This optimization technique
+ is also known as <emphasis>fetch groups</emphasis>. Please note that this is mostly a
+ marketing feature, as in practice, optimizing row reads is much more important than
+ optimization of column reads. However, only loading some properties of a class might
+ be useful in extreme cases, when legacy tables have hundreds of columns and the data model
+ can not be improved.
+ </para>
+
+ <para>
+ To enable lazy property loading, set the <literal>lazy</literal> attribute on your
+ particular property mappings:
+ </para>
+
+ <programlisting><![CDATA[<class name="Document">
+ <id name="id">
+ <generator class="native"/>
+ </id>
+ <property name="name" not-null="true" length="50"/>
+ <property name="summary" not-null="true" length="200" lazy="true"/>
+ <property name="text" not-null="true" length="2000" lazy="true"/>
+</class>]]></programlisting>
+
+ <para>
+ Lazy property loading requires buildtime bytecode instrumentation! If your persistent
+ classes are not enhanced, Hibernate will silently ignore lazy property settings and
+ fall back to immediate fetching.
+ </para>
+
+ <para>
+ For bytecode instrumentation, use the following Ant task:
+ </para>
+
+ <programlisting><![CDATA[<target name="instrument" depends="compile">
+ <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
+ <classpath path="${jar.path}"/>
+ <classpath path="${classes.dir}"/>
+ <classpath refid="lib.class.path"/>
+ </taskdef>
+
+ <instrument verbose="true">
+ <fileset dir="${testclasses.dir}/org/hibernate/auction/model">
+ <include name="*.class"/>
+ </fileset>
+ </instrument>
+</target>]]></programlisting>
+
+ <para>
+ A different (better?) way to avoid unnecessary column reads, at least for
+ read-only transactions is to use the projection features of HQL or Criteria
+ queries. This avoids the need for buildtime bytecode processing and is
+ certainly a prefered solution.
+ </para>
+
+ <para>
+ You may force the usual eager fetching of properties using <literal>fetch all
+ properties</literal> in HQL.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="performance-cache" revision="1">
+ <title>The Second Level Cache</title>
+
+ <para>
+ A Hibernate <literal>Session</literal> is a transaction-level cache of persistent data. It is
+ possible to configure a cluster or JVM-level (<literal>SessionFactory</literal>-level) cache on
+ a class-by-class and collection-by-collection basis. You may even plug in a clustered cache. Be
+ careful. Caches are never aware of changes made to the persistent store by another application
+ (though they may be configured to regularly expire cached data).
+ </para>
+
+ <para revision="1">
+ You have the option to tell Hibernate which caching implementation to use by
+ specifying the name of a class that implements <literal>org.hibernate.cache.CacheProvider</literal>
+ using the property <literal>hibernate.cache.provider_class</literal>. Hibernate
+ comes bundled with a number of built-in integrations with open-source cache providers
+ (listed below); additionally, you could implement your own and plug it in as
+ outlined above. Note that versions prior to 3.2 defaulted to use EhCache as the
+ default cache provider; that is no longer the case as of 3.2.
+ </para>
+
+ <table frame="topbot" id="cacheproviders" revision="1">
+ <title>Cache Providers</title>
+ <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="3*"/>
+ <colspec colname='c3' colwidth="1*"/>
+ <colspec colname='c4' colwidth="1*"/>
+ <colspec colname='c5' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Cache</entry>
+ <entry>Provider class</entry>
+ <entry>Type</entry>
+ <entry>Cluster Safe</entry>
+ <entry>Query Cache Supported</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>Hashtable (not intended for production use)</entry>
+ <entry><literal>org.hibernate.cache.HashtableCacheProvider</literal></entry>
+ <entry>memory</entry>
+ <entry></entry>
+ <entry>yes</entry>
+ </row>
+ <row>
+ <entry>EHCache</entry>
+ <entry><literal>org.hibernate.cache.EhCacheProvider</literal></entry>
+ <entry>memory, disk</entry>
+ <entry></entry>
+ <entry>yes</entry>
+ </row>
+ <row>
+ <entry>OSCache</entry>
+ <entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
+ <entry>memory, disk</entry>
+ <entry></entry>
+ <entry>yes</entry>
+ </row>
+ <row>
+ <entry>SwarmCache</entry>
+ <entry><literal>org.hibernate.cache.SwarmCacheProvider</literal></entry>
+ <entry>clustered (ip multicast)</entry>
+ <entry>yes (clustered invalidation)</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>JBoss TreeCache</entry>
+ <entry><literal>org.hibernate.cache.TreeCacheProvider</literal></entry>
+ <entry>clustered (ip multicast), transactional</entry>
+ <entry>yes (replication)</entry>
+ <entry>yes (clock sync req.)</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <sect2 id="performance-cache-mapping" revision="2">
+ <title>Cache mappings</title>
+
+ <para>
+ The <literal><cache></literal> element of a class or collection mapping has the
+ following form:
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="cache1" coords="2 70"/>
+ <area id="cache2" coords="3 70"/>
+ <area id="cache3" coords="4 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<cache
+ usage="transactional|read-write|nonstrict-read-write|read-only"
+ region="RegionName"
+ include="all|non-lazy"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="cache1">
+ <para>
+ <literal>usage</literal> (required) specifies the caching strategy:
+ <literal>transactional</literal>,
+ <literal>read-write</literal>,
+ <literal>nonstrict-read-write</literal> or
+ <literal>read-only</literal>
+ </para>
+ </callout>
+ <callout arearefs="cache2">
+ <para>
+ <literal>region</literal> (optional, defaults to the class or
+ collection role name) specifies the name of the second level cache
+ region
+ </para>
+ </callout>
+ <callout arearefs="cache3">
+ <para>
+ <literal>include</literal> (optional, defaults to <literal>all</literal>)
+ <literal>non-lazy</literal> specifies that properties of the entity mapped
+ with <literal>lazy="true"</literal> may not be cached when attribute-level
+ lazy fetching is enabled
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Alternatively (preferrably?), you may specify <literal><class-cache></literal> and
+ <literal><collection-cache></literal> elements in <literal>hibernate.cfg.xml</literal>.
+ </para>
+
+ <para>
+ The <literal>usage</literal> attribute specifies a <emphasis>cache concurrency strategy</emphasis>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-cache-readonly">
+ <title>Strategy: read only</title>
+
+ <para>
+ If your application needs to read but never modify instances of a persistent class, a
+ <literal>read-only</literal> cache may be used. This is the simplest and best performing
+ strategy. It's even perfectly safe for use in a cluster.
+ </para>
+
+ <programlisting><![CDATA[<class name="eg.Immutable" mutable="false">
+ <cache usage="read-only"/>
+ ....
+</class>]]></programlisting>
+
+ </sect2>
+
+
+ <sect2 id="performance-cache-readwrite">
+ <title>Strategy: read/write</title>
+
+ <para>
+ If the application needs to update data, a <literal>read-write</literal> cache might be appropriate.
+ This cache strategy should never be used if serializable transaction isolation level is required.
+ If the cache is used in a JTA environment, you must specify the property
+ <literal>hibernate.transaction.manager_lookup_class</literal>, naming a strategy for obtaining the
+ JTA <literal>TransactionManager</literal>. In other environments, you should ensure that the transaction
+ is completed when <literal>Session.close()</literal> or <literal>Session.disconnect()</literal> is called.
+ If you wish to use this strategy in a cluster, you should ensure that the underlying cache implementation
+ supports locking. The built-in cache providers do <emphasis>not</emphasis>.
+ </para>
+
+ <programlisting><![CDATA[<class name="eg.Cat" .... >
+ <cache usage="read-write"/>
+ ....
+ <set name="kittens" ... >
+ <cache usage="read-write"/>
+ ....
+ </set>
+</class>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="performance-cache-nonstrict">
+ <title>Strategy: nonstrict read/write</title>
+
+ <para>
+ If the application only occasionally needs to update data (ie. if it is extremely unlikely that two
+ transactions would try to update the same item simultaneously) and strict transaction isolation is
+ not required, a <literal>nonstrict-read-write</literal> cache might be appropriate. If the cache is
+ used in a JTA environment, you must specify <literal>hibernate.transaction.manager_lookup_class</literal>.
+ In other environments, you should ensure that the transaction is completed when
+ <literal>Session.close()</literal> or <literal>Session.disconnect()</literal> is called.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-cache-transactional">
+ <title>Strategy: transactional</title>
+
+ <para>
+ The <literal>transactional</literal> cache strategy provides support for fully transactional cache
+ providers such as JBoss TreeCache. Such a cache may only be used in a JTA environment and you must
+ specify <literal>hibernate.transaction.manager_lookup_class</literal>.
+ </para>
+
+ </sect2>
+
+ <para>
+ None of the cache providers support all of the cache concurrency strategies. The following table shows
+ which providers are compatible with which concurrency strategies.
+ </para>
+
+ <table frame="topbot">
+ <title>Cache Concurrency Strategy Support</title>
+ <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <colspec colname='c3' colwidth="1*"/>
+ <colspec colname='c4' colwidth="1*"/>
+ <colspec colname='c5' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Cache</entry>
+ <entry>read-only</entry>
+ <entry>nonstrict-read-write</entry>
+ <entry>read-write</entry>
+ <entry>transactional</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>Hashtable (not intended for production use)</entry>
+ <entry>yes</entry>
+ <entry>yes</entry>
+ <entry>yes</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>EHCache</entry>
+ <entry>yes</entry>
+ <entry>yes</entry>
+ <entry>yes</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>OSCache</entry>
+ <entry>yes</entry>
+ <entry>yes</entry>
+ <entry>yes</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>SwarmCache</entry>
+ <entry>yes</entry>
+ <entry>yes</entry>
+ <entry></entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>JBoss TreeCache</entry>
+ <entry>yes</entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>yes</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect1>
+
+ <sect1 id="performance-sessioncache" revision="2">
+ <title>Managing the caches</title>
+
+ <para>
+ Whenever you pass an object to <literal>save()</literal>, <literal>update()</literal>
+ or <literal>saveOrUpdate()</literal> and whenever you retrieve an object using
+ <literal>load()</literal>, <literal>get()</literal>, <literal>list()</literal>,
+ <literal>iterate()</literal> or <literal>scroll()</literal>, that object is added
+ to the internal cache of the <literal>Session</literal>.
+ </para>
+ <para>
+ When <literal>flush()</literal> is subsequently called, the state of that object will
+ be synchronized with the database. If you do not want this synchronization to occur or
+ if you are processing a huge number of objects and need to manage memory efficiently,
+ the <literal>evict()</literal> method may be used to remove the object and its collections
+ from the first-level cache.
+ </para>
+
+ <programlisting><![CDATA[ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
+while ( cats.next() ) {
+ Cat cat = (Cat) cats.get(0);
+ doSomethingWithACat(cat);
+ sess.evict(cat);
+}]]></programlisting>
+
+ <para>
+ The <literal>Session</literal> also provides a <literal>contains()</literal> method to determine
+ if an instance belongs to the session cache.
+ </para>
+
+ <para>
+ To completely evict all objects from the session cache, call <literal>Session.clear()</literal>
+ </para>
+
+ <para>
+ For the second-level cache, there are methods defined on <literal>SessionFactory</literal> for
+ evicting the cached state of an instance, entire class, collection instance or entire collection
+ role.
+ </para>
+
+ <programlisting><![CDATA[sessionFactory.evict(Cat.class, catId); //evict a particular Cat
+sessionFactory.evict(Cat.class); //evict all Cats
+sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
+sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections]]></programlisting>
+
+ <para>
+ The <literal>CacheMode</literal> controls how a particular session interacts with the second-level
+ cache.
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>CacheMode.NORMAL</literal> - read items from and write items to the second-level cache
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CacheMode.GET</literal> - read items from the second-level cache, but don't write to
+ the second-level cache except when updating data
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CacheMode.PUT</literal> - write items to the second-level cache, but don't read from
+ the second-level cache
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CacheMode.REFRESH</literal> - write items to the second-level cache, but don't read from
+ the second-level cache, bypass the effect of <literal>hibernate.cache.use_minimal_puts</literal>, forcing
+ a refresh of the second-level cache for all items read from the database
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ To browse the contents of a second-level or query cache region, use the <literal>Statistics</literal>
+ API:
+ </para>
+
+ <programlisting><![CDATA[Map cacheEntries = sessionFactory.getStatistics()
+ .getSecondLevelCacheStatistics(regionName)
+ .getEntries();]]></programlisting>
+
+ <para>
+ You'll need to enable statistics, and, optionally, force Hibernate to keep the cache entries in a
+ more human-understandable format:
+ </para>
+
+ <programlisting><![CDATA[hibernate.generate_statistics true
+hibernate.cache.use_structured_entries true]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="performance-querycache" revision="1">
+ <title>The Query Cache</title>
+
+ <para>
+ Query result sets may also be cached. This is only useful for queries that are run
+ frequently with the same parameters. To use the query cache you must first enable it:
+ </para>
+
+ <programlisting><![CDATA[hibernate.cache.use_query_cache true]]></programlisting>
+
+ <para>
+ This setting causes the creation of two new cache regions - one holding cached query
+ result sets (<literal>org.hibernate.cache.StandardQueryCache</literal>), the other
+ holding timestamps of the most recent updates to queryable tables
+ (<literal>org.hibernate.cache.UpdateTimestampsCache</literal>). Note that the query
+ cache does not cache the state of the actual entities in the result set; it caches
+ only identifier values and results of value type. So the query cache should always be
+ used in conjunction with the second-level cache.
+ </para>
+
+ <para>
+ Most queries do not benefit from caching, so by default queries are not cached. To
+ enable caching, call <literal>Query.setCacheable(true)</literal>. This call allows
+ the query to look for existing cache results or add its results to the cache when
+ it is executed.
+ </para>
+
+ <para>
+ If you require fine-grained control over query cache expiration policies, you may
+ specify a named cache region for a particular query by calling
+ <literal>Query.setCacheRegion()</literal>.
+ </para>
+
+ <programlisting><![CDATA[List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
+ .setEntity("blogger", blogger)
+ .setMaxResults(15)
+ .setCacheable(true)
+ .setCacheRegion("frontpages")
+ .list();]]></programlisting>
+
+ <para>
+ If the query should force a refresh of its query cache region, you should call
+ <literal>Query.setCacheMode(CacheMode.REFRESH)</literal>. This is particularly useful
+ in cases where underlying data may have been updated via a separate process (i.e.,
+ not modified through Hibernate) and allows the application to selectively refresh
+ particular query result sets. This is a more efficient alternative to eviction of
+ a query cache region via <literal>SessionFactory.evictQueries()</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="performance-collections">
+ <title>Understanding Collection performance</title>
+
+ <para>
+ We've already spent quite some time talking about collections.
+ In this section we will highlight a couple more issues about
+ how collections behave at runtime.
+ </para>
+
+ <sect2 id="performance-collections-taxonomy">
+ <title>Taxonomy</title>
+
+ <para>Hibernate defines three basic kinds of collections:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>collections of values</para>
+ </listitem>
+ <listitem>
+ <para>one to many associations</para>
+ </listitem>
+ <listitem>
+ <para>many to many associations</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ This classification distinguishes the various table and foreign key
+ relationships but does not tell us quite everything we need to know
+ about the relational model. To fully understand the relational structure
+ and performance characteristics, we must also consider the structure of
+ the primary key that is used by Hibernate to update or delete collection
+ rows. This suggests the following classification:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>indexed collections</para>
+ </listitem>
+ <listitem>
+ <para>sets</para>
+ </listitem>
+ <listitem>
+ <para>bags</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ All indexed collections (maps, lists, arrays) have a primary key consisting
+ of the <literal><key></literal> and <literal><index></literal>
+ columns. In this case collection updates are usually extremely efficient -
+ the primary key may be efficiently indexed and a particular row may be efficiently
+ located when Hibernate tries to update or delete it.
+ </para>
+
+ <para>
+ Sets have a primary key consisting of <literal><key></literal> and element
+ columns. This may be less efficient for some types of collection element, particularly
+ composite elements or large text or binary fields; the database may not be able to index
+ a complex primary key as efficently. On the other hand, for one to many or many to many
+ associations, particularly in the case of synthetic identifiers, it is likely to be just
+ as efficient. (Side-note: if you want <literal>SchemaExport</literal> to actually create
+ the primary key of a <literal><set></literal> for you, you must declare all columns
+ as <literal>not-null="true"</literal>.)
+ </para>
+
+ <para>
+ <literal><idbag></literal> mappings define a surrogate key, so they are
+ always very efficient to update. In fact, they are the best case.
+ </para>
+
+ <para>
+ Bags are the worst case. Since a bag permits duplicate element values and has no
+ index column, no primary key may be defined. Hibernate has no way of distinguishing
+ between duplicate rows. Hibernate resolves this problem by completely removing
+ (in a single <literal>DELETE</literal>) and recreating the collection whenever it
+ changes. This might be very inefficient.
+ </para>
+
+ <para>
+ Note that for a one-to-many association, the "primary key" may not be the physical
+ primary key of the database table - but even in this case, the above classification
+ is still useful. (It still reflects how Hibernate "locates" individual rows of the
+ collection.)
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-collections-mostefficientupdate">
+ <title>Lists, maps, idbags and sets are the most efficient collections to update</title>
+
+ <para>
+ From the discussion above, it should be clear that indexed collections
+ and (usually) sets allow the most efficient operation in terms of adding,
+ removing and updating elements.
+ </para>
+
+ <para>
+ There is, arguably, one more advantage that indexed collections have over sets for
+ many to many associations or collections of values. Because of the structure of a
+ <literal>Set</literal>, Hibernate doesn't ever <literal>UPDATE</literal> a row when
+ an element is "changed". Changes to a <literal>Set</literal> always work via
+ <literal>INSERT</literal> and <literal>DELETE</literal> (of individual rows). Once
+ again, this consideration does not apply to one to many associations.
+ </para>
+
+ <para>
+ After observing that arrays cannot be lazy, we would conclude that lists, maps and
+ idbags are the most performant (non-inverse) collection types, with sets not far
+ behind. Sets are expected to be the most common kind of collection in Hibernate
+ applications. This is because the "set" semantics are most natural in the relational
+ model.
+ </para>
+
+ <para>
+ However, in well-designed Hibernate domain models, we usually see that most collections
+ are in fact one-to-many associations with <literal>inverse="true"</literal>. For these
+ associations, the update is handled by the many-to-one end of the association, and so
+ considerations of collection update performance simply do not apply.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-collections-mostefficentinverse">
+ <title>Bags and lists are the most efficient inverse collections</title>
+
+ <para>
+ Just before you ditch bags forever, there is a particular case in which bags (and also lists)
+ are much more performant than sets. For a collection with <literal>inverse="true"</literal>
+ (the standard bidirectional one-to-many relationship idiom, for example) we can add elements
+ to a bag or list without needing to initialize (fetch) the bag elements! This is because
+ <literal>Collection.add()</literal> or <literal>Collection.addAll()</literal> must always
+ return true for a bag or <literal>List</literal> (unlike a <literal>Set</literal>). This can
+ make the following common code much faster.
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) sess.load(Parent.class, id);
+Child c = new Child();
+c.setParent(p);
+p.getChildren().add(c); //no need to fetch the collection!
+sess.flush();]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="performance-collections-oneshotdelete">
+ <title>One shot delete</title>
+
+ <para>
+ Occasionally, deleting collection elements one by one can be extremely inefficient. Hibernate
+ isn't completely stupid, so it knows not to do that in the case of an newly-empty collection
+ (if you called <literal>list.clear()</literal>, for example). In this case, Hibernate will
+ issue a single <literal>DELETE</literal> and we are done!
+ </para>
+
+ <para>
+ Suppose we add a single element to a collection of size twenty and then remove two elements.
+ Hibernate will issue one <literal>INSERT</literal> statement and two <literal>DELETE</literal>
+ statements (unless the collection is a bag). This is certainly desirable.
+ </para>
+
+ <para>
+ However, suppose that we remove eighteen elements, leaving two and then add thee new elements.
+ There are two possible ways to proceed
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>delete eighteen rows one by one and then insert three rows</para>
+ </listitem>
+ <listitem>
+ <para>remove the whole collection (in one SQL <literal>DELETE</literal>) and insert
+ all five current elements (one by one)</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Hibernate isn't smart enough to know that the second option is probably quicker in this case.
+ (And it would probably be undesirable for Hibernate to be that smart; such behaviour might
+ confuse database triggers, etc.)
+ </para>
+
+ <para>
+ Fortunately, you can force this behaviour (ie. the second strategy) at any time by discarding
+ (ie. dereferencing) the original collection and returning a newly instantiated collection with
+ all the current elements. This can be very useful and powerful from time to time.
+ </para>
+
+ <para>
+ Of course, one-shot-delete does not apply to collections mapped <literal>inverse="true"</literal>.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="performance-monitoring" revision="1">
+ <title>Monitoring performance</title>
+
+ <para>
+ Optimization is not much use without monitoring and access to performance numbers.
+ Hibernate provides a full range of figures about its internal operations.
+ Statistics in Hibernate are available per <literal>SessionFactory</literal>.
+ </para>
+
+ <sect2 id="performance-monitoring-sf" revision="2">
+ <title>Monitoring a SessionFactory</title>
+
+ <para>
+ You can access <literal>SessionFactory</literal> metrics in two ways.
+ Your first option is to call <literal>sessionFactory.getStatistics()</literal> and
+ read or display the <literal>Statistics</literal> yourself.
+ </para>
+
+ <para>
+ Hibernate can also use JMX to publish metrics if you enable the
+ <literal>StatisticsService</literal> MBean. You may enable a single MBean for all your
+ <literal>SessionFactory</literal> or one per factory. See the following code for
+ minimalistic configuration examples:
+ </para>
+
+ <programlisting><![CDATA[// MBean service registration for a specific SessionFactory
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "myFinancialApp");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+stats.setSessionFactory(sessionFactory); // Bind the stats to a SessionFactory
+server.registerMBean(stats, on); // Register the Mbean on the server]]></programlisting>
+
+
+<programlisting><![CDATA[// MBean service registration for all SessionFactory's
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "all");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+server.registerMBean(stats, on); // Register the MBean on the server]]></programlisting>
+
+ <para>
+ TODO: This doesn't make sense: In the first case, we retrieve and use the MBean directly. In the second one, we must give
+ the JNDI name in which the session factory is held before using it. Use
+ <literal>hibernateStatsBean.setSessionFactoryJNDIName("my/JNDI/Name")</literal>
+ </para>
+ <para>
+ You can (de)activate the monitoring for a <literal>SessionFactory</literal>
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ at configuration time, set <literal>hibernate.generate_statistics</literal> to <literal>false</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+ <itemizedlist>
+ <listitem>
+ <para>
+ at runtime: <literal>sf.getStatistics().setStatisticsEnabled(true)</literal>
+ or <literal>hibernateStatsBean.setStatisticsEnabled(true)</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Statistics can be reset programatically using the <literal>clear()</literal> method.
+ A summary can be sent to a logger (info level) using the <literal>logSummary()</literal>
+ method.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-monitoring-metrics" revision="1">
+ <title>Metrics</title>
+
+ <para>
+ Hibernate provides a number of metrics, from very basic to the specialized information
+ only relevant in certain scenarios. All available counters are described in the
+ <literal>Statistics</literal> interface API, in three categories:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Metrics related to the general <literal>Session</literal> usage, such as
+ number of open sessions, retrieved JDBC connections, etc.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Metrics related to he entities, collections, queries, and caches as a
+ whole (aka global metrics),
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Detailed metrics related to a particular entity, collection, query or
+ cache region.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ For exampl,e you can check the cache hit, miss, and put ratio of entities, collections
+ and queries, and the average time a query needs. Beware that the number of milliseconds
+ is subject to approximation in Java. Hibernate is tied to the JVM precision, on some
+ platforms this might even only be accurate to 10 seconds.
+ </para>
+
+ <para>
+ Simple getters are used to access the global metrics (i.e. not tied to a particular entity,
+ collection, cache region, etc.). You can access the metrics of a particular entity, collection
+ or cache region through its name, and through its HQL or SQL representation for queries. Please
+ refer to the <literal>Statistics</literal>, <literal>EntityStatistics</literal>,
+ <literal>CollectionStatistics</literal>, <literal>SecondLevelCacheStatistics</literal>,
+ and <literal>QueryStatistics</literal> API Javadoc for more information. The following
+ code shows a simple example:
+ </para>
+
+ <programlisting><![CDATA[Statistics stats = HibernateUtil.sessionFactory.getStatistics();
+
+double queryCacheHitCount = stats.getQueryCacheHitCount();
+double queryCacheMissCount = stats.getQueryCacheMissCount();
+double queryCacheHitRatio =
+ queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);
+
+log.info("Query Hit ratio:" + queryCacheHitRatio);
+
+EntityStatistics entityStats =
+ stats.getEntityStatistics( Cat.class.getName() );
+long changes =
+ entityStats.getInsertCount()
+ + entityStats.getUpdateCount()
+ + entityStats.getDeleteCount();
+log.info(Cat.class.getName() + " changed " + changes + "times" );]]></programlisting>
+
+ <para>
+ To work on all entities, collections, queries and region caches, you can retrieve
+ the list of names of entities, collections, queries and region caches with the
+ following methods: <literal>getQueries()</literal>, <literal>getEntityNames()</literal>,
+ <literal>getCollectionRoleNames()</literal>, and
+ <literal>getSecondLevelCacheRegionNames()</literal>.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/persistent_classes.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/persistent_classes.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/persistent_classes.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,533 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="persistent-classes" revision="2">
+ <title>Persistent Classes</title>
+
+ <para>
+ Persistent classes are classes in an application that implement the entities
+ of the business problem (e.g. Customer and Order in an E-commerce application).
+ Not all instances of a persistent class are considered to be in the persistent
+ state - an instance may instead be transient or detached.
+ </para>
+
+ <para>
+ Hibernate works best if these classes follow some simple rules, also known
+ as the Plain Old Java Object (POJO) programming model. However, none of these
+ rules are hard requirements. Indeed, Hibernate3 assumes very little about
+ the nature of your persistent objects. You may express a domain model in other
+ ways: using trees of <literal>Map</literal> instances, for example.
+ </para>
+
+ <sect1 id="persistent-classes-pojo">
+ <title>A simple POJO example</title>
+
+ <para>
+ Most Java applications require a persistent class representing felines.
+ </para>
+
+ <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+public class Cat {
+ private Long id; // identifier
+
+ private Date birthdate;
+ private Color color;
+ private char sex;
+ private float weight;
+ private int litterId;
+
+ private Cat mother;
+ private Set kittens = new HashSet();
+
+ private void setId(Long id) {
+ this.id=id;
+ }
+ public Long getId() {
+ return id;
+ }
+
+ void setBirthdate(Date date) {
+ birthdate = date;
+ }
+ public Date getBirthdate() {
+ return birthdate;
+ }
+
+ void setWeight(float weight) {
+ this.weight = weight;
+ }
+ public float getWeight() {
+ return weight;
+ }
+
+ public Color getColor() {
+ return color;
+ }
+ void setColor(Color color) {
+ this.color = color;
+ }
+
+ void setSex(char sex) {
+ this.sex=sex;
+ }
+ public char getSex() {
+ return sex;
+ }
+
+ void setLitterId(int id) {
+ this.litterId = id;
+ }
+ public int getLitterId() {
+ return litterId;
+ }
+
+ void setMother(Cat mother) {
+ this.mother = mother;
+ }
+ public Cat getMother() {
+ return mother;
+ }
+ void setKittens(Set kittens) {
+ this.kittens = kittens;
+ }
+ public Set getKittens() {
+ return kittens;
+ }
+
+ // addKitten not needed by Hibernate
+ public void addKitten(Cat kitten) {
+ kitten.setMother(this);
+ kitten.setLitterId( kittens.size() );
+ kittens.add(kitten);
+ }
+}]]></programlisting>
+
+ <para>
+ There are four main rules to follow here:
+ </para>
+
+
+ <sect2 id="persistent-classes-pojo-constructor" revision="1">
+ <title>Implement a no-argument constructor</title>
+
+ <para>
+ <literal>Cat</literal> has a no-argument constructor. All persistent classes must
+ have a default constructor (which may be non-public) so that Hibernate can instantiate
+ them using <literal>Constructor.newInstance()</literal>. We strongly recommend having a
+ default constructor with at least <emphasis>package</emphasis> visibility for runtime proxy
+ generation in Hibernate.
+ </para>
+ </sect2>
+
+ <sect2 id="persistent-classes-pojo-identifier" revision="2">
+ <title>Provide an identifier property (optional)</title>
+
+ <para>
+ <literal>Cat</literal> has a property called <literal>id</literal>. This property
+ maps to the primary key column of a database table. The property might have been called
+ anything, and its type might have been any primitive type, any primitive "wrapper"
+ type, <literal>java.lang.String</literal> or <literal>java.util.Date</literal>. (If
+ your legacy database table has composite keys, you can even use a user-defined class
+ with properties of these types - see the section on composite identifiers later.)
+ </para>
+
+ <para>
+ The identifier property is strictly optional. You can leave them off and let Hibernate
+ keep track of object identifiers internally. We do not recommend this, however.
+ </para>
+
+ <para>
+ In fact, some functionality is available only to classes which declare an
+ identifier property:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Transitive reattachment for detached objects (cascade update or cascade
+ merge) - see <xref linkend="objectstate-transitive"/>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>Session.saveOrUpdate()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>Session.merge()</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ We recommend you declare consistently-named identifier properties on persistent
+ classes. We further recommend that you use a nullable (ie. non-primitive) type.
+ </para>
+ </sect2>
+
+ <sect2 id="persistent-classes-pojo-final">
+ <title>Prefer non-final classes (optional)</title>
+ <para>
+ A central feature of Hibernate, <emphasis>proxies</emphasis>, depends upon the
+ persistent class being either non-final, or the implementation of an interface
+ that declares all public methods.
+ </para>
+ <para>
+ You can persist <literal>final</literal> classes that do not implement an interface
+ with Hibernate, but you won't be able to use proxies for lazy association fetching -
+ which will limit your options for performance tuning.
+ </para>
+ <para>
+ You should also avoid declaring <literal>public final</literal> methods on the
+ non-final classes. If you want to use a class with a <literal>public final</literal>
+ method, you must explicitly disable proying by setting <literal>lazy="false"</literal>.
+ </para>
+ </sect2>
+
+ <sect2 id="persistent-classes-pojo-accessors" revision="2">
+ <title>Declare accessors and mutators for persistent fields (optional)</title>
+
+ <para>
+ <literal>Cat</literal> declares accessor methods for all its persistent fields.
+ Many other ORM tools directly persist instance variables. We believe it is
+ better to provide an indirection between the relational schema and internal
+ data structures of the class. By default, Hibernate persists JavaBeans style
+ properties, and recognizes method names of the form <literal>getFoo</literal>,
+ <literal>isFoo</literal> and <literal>setFoo</literal>. You may switch to direct
+ field access for particular properties, if needed.
+ </para>
+
+ <para>
+ Properties need <emphasis>not</emphasis> be declared public - Hibernate can
+ persist a property with a default, <literal>protected</literal> or
+ <literal>private</literal> get / set pair.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="persistent-classes-inheritance">
+ <title>Implementing inheritance</title>
+
+ <para>
+ A subclass must also observe the first and second rules. It inherits its
+ identifier property from the superclass, <literal>Cat</literal>.
+ </para>
+
+ <programlisting><![CDATA[package eg;
+
+public class DomesticCat extends Cat {
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+ protected void setName(String name) {
+ this.name=name;
+ }
+}]]></programlisting>
+ </sect1>
+
+ <sect1 id="persistent-classes-equalshashcode" revision="1">
+ <title>Implementing <literal>equals()</literal> and <literal>hashCode()</literal></title>
+
+ <para>
+ You have to override the <literal>equals()</literal> and <literal>hashCode()</literal>
+ methods if you
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ intend to put instances of persistent classes in a <literal>Set</literal>
+ (the recommended way to represent many-valued associations)
+ <emphasis>and</emphasis>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ intend to use reattachment of detached instances
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Hibernate guarantees equivalence of persistent identity (database row) and Java identity
+ only inside a particular session scope. So as soon as we mix instances retrieved in
+ different sessions, we must implement <literal>equals()</literal> and
+ <literal>hashCode()</literal> if we wish to have meaningful semantics for
+ <literal>Set</literal>s.
+ </para>
+
+ <para>
+ The most obvious way is to implement <literal>equals()</literal>/<literal>hashCode()</literal>
+ by comparing the identifier value of both objects. If the value is the same, both must
+ be the same database row, they are therefore equal (if both are added to a <literal>Set</literal>,
+ we will only have one element in the <literal>Set</literal>). Unfortunately, we can't use that
+ approach with generated identifiers! Hibernate will only assign identifier values to objects
+ that are persistent, a newly created instance will not have any identifier value! Furthermore,
+ if an instance is unsaved and currently in a <literal>Set</literal>, saving it will assign
+ an identifier value to the object. If <literal>equals()</literal> and <literal>hashCode()</literal>
+ are based on the identifier value, the hash code would change, breaking the contract of the
+ <literal>Set</literal>. See the Hibernate website for a full discussion of this problem. Note
+ that this is not a Hibernate issue, but normal Java semantics of object identity and equality.
+ </para>
+
+ <para>
+ We recommend implementing <literal>equals()</literal> and <literal>hashCode()</literal>
+ using <emphasis>Business key equality</emphasis>. Business key equality means that the
+ <literal>equals()</literal> method compares only the properties that form the business
+ key, a key that would identify our instance in the real world (a
+ <emphasis>natural</emphasis> candidate key):
+ </para>
+
+ <programlisting><![CDATA[public class Cat {
+
+ ...
+ public boolean equals(Object other) {
+ if (this == other) return true;
+ if ( !(other instanceof Cat) ) return false;
+
+ final Cat cat = (Cat) other;
+
+ if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
+ if ( !cat.getMother().equals( getMother() ) ) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = getMother().hashCode();
+ result = 29 * result + getLitterId();
+ return result;
+ }
+
+}]]></programlisting>
+
+ <para>
+ Note that a business key does not have to be as solid as a database
+ primary key candidate (see <xref linkend="transactions-basics-identity"/>).
+ Immutable or unique properties are usually good
+ candidates for a business key.
+ </para>
+
+ </sect1>
+
+ <sect1 id="persistent-classes-dynamicmodels">
+ <title>Dynamic models</title>
+
+ <para>
+ <emphasis>Note that the following features are currently considered
+ experimental and may change in the near future.</emphasis>
+ </para>
+
+ <para>
+ Persistent entities don't necessarily have to be represented as POJO classes
+ or as JavaBean objects at runtime. Hibernate also supports dynamic models
+ (using <literal>Map</literal>s of <literal>Map</literal>s at runtime) and the
+ representation of entities as DOM4J trees. With this approach, you don't
+ write persistent classes, only mapping files.
+ </para>
+
+ <para>
+ By default, Hibernate works in normal POJO mode. You may set a default entity
+ representation mode for a particular <literal>SessionFactory</literal> using the
+ <literal>default_entity_mode</literal> configuration option (see
+ <xref linkend="configuration-optional-properties"/>.
+ </para>
+
+ <para>
+ The following examples demonstrates the representation using <literal>Map</literal>s.
+ First, in the mapping file, an <literal>entity-name</literal> has to be declared
+ instead of (or in addition to) a class name:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class entity-name="Customer">
+
+ <id name="id"
+ type="long"
+ column="ID">
+ <generator class="sequence"/>
+ </id>
+
+ <property name="name"
+ column="NAME"
+ type="string"/>
+
+ <property name="address"
+ column="ADDRESS"
+ type="string"/>
+
+ <many-to-one name="organization"
+ column="ORGANIZATION_ID"
+ class="Organization"/>
+
+ <bag name="orders"
+ inverse="true"
+ lazy="false"
+ cascade="all">
+ <key column="CUSTOMER_ID"/>
+ <one-to-many class="Order"/>
+ </bag>
+
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+
+ Note that even though associations are declared using target class names,
+ the target type of an associations may also be a dynamic entity instead
+ of a POJO.
+ </para>
+
+ <para>
+ After setting the default entity mode to <literal>dynamic-map</literal>
+ for the <literal>SessionFactory</literal>, we can at runtime work with
+ <literal>Map</literal>s of <literal>Map</literal>s:
+ </para>
+
+ <programlisting><![CDATA[Session s = openSession();
+Transaction tx = s.beginTransaction();
+Session s = openSession();
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+
+// Create an organization
+Map foobar = new HashMap();
+foobar.put("name", "Foobar Inc.");
+
+// Link both
+david.put("organization", foobar);
+
+// Save both
+s.save("Customer", david);
+s.save("Organization", foobar);
+
+tx.commit();
+s.close();]]></programlisting>
+
+ <para>
+ The advantages of a dynamic mapping are quick turnaround time for prototyping
+ without the need for entity class implementation. However, you lose compile-time
+ type checking and will very likely deal with many exceptions at runtime. Thanks
+ to the Hibernate mapping, the database schema can easily be normalized and sound,
+ allowing to add a proper domain model implementation on top later on.
+ </para>
+
+ <para>
+ Entity representation modes can also be set on a per <literal>Session</literal>
+ basis:
+ </para>
+
+ <programlisting><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+dynamicSession.save("Customer", david);
+...
+dynamicSession.flush();
+dynamicSession.close()
+...
+// Continue on pojoSession
+]]></programlisting>
+
+
+ <para>
+ Please note that the call to <literal>getSession()</literal> using an
+ <literal>EntityMode</literal> is on the <literal>Session</literal> API, not the
+ <literal>SessionFactory</literal>. That way, the new <literal>Session</literal>
+ shares the underlying JDBC connection, transaction, and other context
+ information. This means you don't have tocall <literal>flush()</literal>
+ and <literal>close()</literal> on the secondary <literal>Session</literal>, and
+ also leave the transaction and connection handling to the primary unit of work.
+ </para>
+
+ <para>
+ More information about the XML representation capabilities can be found
+ in <xref linkend="xml"/>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="persistent-classes-tuplizers" revision="1">
+ <title>Tuplizers</title>
+
+ <para>
+ <literal>org.hibernate.tuple.Tuplizer</literal>, and its sub-interfaces, are responsible
+ for managing a particular representation of a piece of data, given that representation's
+ <literal>org.hibernate.EntityMode</literal>. If a given piece of data is thought of as
+ a data structure, then a tuplizer is the thing which knows how to create such a data structure
+ and how to extract values from and inject values into such a data structure. For example,
+ for the POJO entity mode, the correpsonding tuplizer knows how create the POJO through its
+ constructor and how to access the POJO properties using the defined property accessors.
+ There are two high-level types of Tuplizers, represented by the
+ <literal>org.hibernate.tuple.entity.EntityTuplizer</literal> and <literal>org.hibernate.tuple.component.ComponentTuplizer</literal>
+ interfaces. <literal>EntityTuplizer</literal>s are responsible for managing the above mentioned
+ contracts in regards to entities, while <literal>ComponentTuplizer</literal>s do the same for
+ components.
+ </para>
+
+ <para>
+ Users may also plug in their own tuplizers. Perhaps you require that a <literal>java.util.Map</literal>
+ implementation other than <literal>java.util.HashMap</literal> be used while in the
+ dynamic-map entity-mode; or perhaps you need to define a different proxy generation strategy
+ than the one used by default. Both would be achieved by defining a custom tuplizer
+ implementation. Tuplizers definitions are attached to the entity or component mapping they
+ are meant to manage. Going back to the example of our customer entity:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+ <class entity-name="Customer">
+ <!--
+ Override the dynamic-map entity-mode
+ tuplizer for the customer entity
+ -->
+ <tuplizer entity-mode="dynamic-map"
+ class="CustomMapTuplizerImpl"/>
+
+ <id name="id" type="long" column="ID">
+ <generator class="sequence"/>
+ </id>
+
+ <!-- other properties -->
+ ...
+ </class>
+</hibernate-mapping>
+
+
+public class CustomMapTuplizerImpl
+ extends org.hibernate.tuple.entity.DynamicMapEntityTuplizer {
+ // override the buildInstantiator() method to plug in our custom map...
+ protected final Instantiator buildInstantiator(
+ org.hibernate.mapping.PersistentClass mappingInfo) {
+ return new CustomMapInstantiator( mappingInfo );
+ }
+
+ private static final class CustomMapInstantiator
+ extends org.hibernate.tuple.DynamicMapInstantitor {
+ // override the generateMap() method to return our custom map...
+ protected final Map generateMap() {
+ return new CustomMap();
+ }
+ }
+}]]></programlisting>
+
+
+ </sect1>
+
+ <para>
+ TODO: Document user-extension framework in the property and proxy packages
+ </para>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/query_criteria.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/query_criteria.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/query_criteria.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,438 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="querycriteria">
+ <title>Criteria Queries</title>
+
+ <para>
+ Hibernate features an intuitive, extensible criteria query API.
+ </para>
+
+ <sect1 id="querycriteria-creating">
+ <title>Creating a <literal>Criteria</literal> instance</title>
+
+ <para>
+ The interface <literal>org.hibernate.Criteria</literal> represents a query against
+ a particular persistent class. The <literal>Session</literal> is a factory for
+ <literal>Criteria</literal> instances.
+ </para>
+
+ <programlisting><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
+crit.setMaxResults(50);
+List cats = crit.list();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-narrowing">
+ <title>Narrowing the result set</title>
+
+ <para>
+ An individual query criterion is an instance of the interface
+ <literal>org.hibernate.criterion.Criterion</literal>. The class
+ <literal>org.hibernate.criterion.Restrictions</literal> defines
+ factory methods for obtaining certain built-in
+ <literal>Criterion</literal> types.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.like("name", "Fritz%") )
+ .add( Restrictions.between("weight", minWeight, maxWeight) )
+ .list();]]></programlisting>
+
+ <para>
+ Restrictions may be grouped logically.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.like("name", "Fritz%") )
+ .add( Restrictions.or(
+ Restrictions.eq( "age", new Integer(0) ),
+ Restrictions.isNull("age")
+ ) )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
+ .add( Restrictions.disjunction()
+ .add( Restrictions.isNull("age") )
+ .add( Restrictions.eq("age", new Integer(0) ) )
+ .add( Restrictions.eq("age", new Integer(1) ) )
+ .add( Restrictions.eq("age", new Integer(2) ) )
+ ) )
+ .list();]]></programlisting>
+
+ <para>
+ There are quite a range of built-in criterion types (<literal>Restrictions</literal>
+ subclasses), but one that is especially useful lets you specify SQL directly.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.sqlRestriction("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
+ .list();]]></programlisting>
+
+ <para>
+ The <literal>{alias}</literal> placeholder with be replaced by the row alias
+ of the queried entity.
+ </para>
+
+ <para>
+ An alternative approach to obtaining a criterion is to get it from a
+ <literal>Property</literal> instance. You can create a <literal>Property</literal>
+ by calling <literal>Property.forName()</literal>.
+ </para>
+
+ <programlisting><![CDATA[
+Property age = Property.forName("age");
+List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.disjunction()
+ .add( age.isNull() )
+ .add( age.eq( new Integer(0) ) )
+ .add( age.eq( new Integer(1) ) )
+ .add( age.eq( new Integer(2) ) )
+ ) )
+ .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
+ .list();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-ordering">
+ <title>Ordering the results</title>
+
+ <para>
+ You may order the results using <literal>org.hibernate.criterion.Order</literal>.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.like("name", "F%")
+ .addOrder( Order.asc("name") )
+ .addOrder( Order.desc("age") )
+ .setMaxResults(50)
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Property.forName("name").like("F%") )
+ .addOrder( Property.forName("name").asc() )
+ .addOrder( Property.forName("age").desc() )
+ .setMaxResults(50)
+ .list();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-associations" revision="2">
+ <title>Associations</title>
+
+ <para>
+ You may easily specify constraints upon related entities by navigating
+ associations using <literal>createCriteria()</literal>.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.like("name", "F%") )
+ .createCriteria("kittens")
+ .add( Restrictions.like("name", "F%") )
+ .list();]]></programlisting>
+
+ <para>
+ note that the second <literal>createCriteria()</literal> returns a new
+ instance of <literal>Criteria</literal>, which refers to the elements of
+ the <literal>kittens</literal> collection.
+ </para>
+
+ <para>
+ The following, alternate form is useful in certain circumstances.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .createAlias("kittens", "kt")
+ .createAlias("mate", "mt")
+ .add( Restrictions.eqProperty("kt.name", "mt.name") )
+ .list();]]></programlisting>
+
+ <para>
+ (<literal>createAlias()</literal> does not create a new instance of
+ <literal>Criteria</literal>.)
+ </para>
+
+ <para>
+ Note that the kittens collections held by the <literal>Cat</literal> instances
+ returned by the previous two queries are <emphasis>not</emphasis> pre-filtered
+ by the criteria! If you wish to retrieve just the kittens that match the
+ criteria, you must use a <literal>ResultTransformer</literal>.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .createCriteria("kittens", "kt")
+ .add( Restrictions.eq("name", "F%") )
+ .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
+ .list();
+Iterator iter = cats.iterator();
+while ( iter.hasNext() ) {
+ Map map = (Map) iter.next();
+ Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
+ Cat kitten = (Cat) map.get("kt");
+}]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-dynamicfetching" revision="1">
+ <title>Dynamic association fetching</title>
+
+ <para>
+ You may specify association fetching semantics at runtime using
+ <literal>setFetchMode()</literal>.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.like("name", "Fritz%") )
+ .setFetchMode("mate", FetchMode.EAGER)
+ .setFetchMode("kittens", FetchMode.EAGER)
+ .list();]]></programlisting>
+
+ <para>
+ This query will fetch both <literal>mate</literal> and <literal>kittens</literal>
+ by outer join. See <xref linkend="performance-fetching"/> for more information.
+ </para>
+
+ </sect1>
+
+ <sect1 id="querycriteria-examples">
+ <title>Example queries</title>
+
+ <para>
+ The class <literal>org.hibernate.criterion.Example</literal> allows
+ you to construct a query criterion from a given instance.
+ </para>
+
+ <programlisting><![CDATA[Cat cat = new Cat();
+cat.setSex('F');
+cat.setColor(Color.BLACK);
+List results = session.createCriteria(Cat.class)
+ .add( Example.create(cat) )
+ .list();]]></programlisting>
+
+ <para>
+ Version properties, identifiers and associations are ignored. By default,
+ null valued properties are excluded.
+ </para>
+
+ <para>
+ You can adjust how the <literal>Example</literal> is applied.
+ </para>
+
+ <programlisting><![CDATA[Example example = Example.create(cat)
+ .excludeZeroes() //exclude zero valued properties
+ .excludeProperty("color") //exclude the property named "color"
+ .ignoreCase() //perform case insensitive string comparisons
+ .enableLike(); //use like for string comparisons
+List results = session.createCriteria(Cat.class)
+ .add(example)
+ .list();]]></programlisting>
+
+ <para>
+ You can even use examples to place criteria upon associated objects.
+ </para>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .add( Example.create(cat) )
+ .createCriteria("mate")
+ .add( Example.create( cat.getMate() ) )
+ .list();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-projection">
+ <title>Projections, aggregation and grouping</title>
+ <para>
+ The class <literal>org.hibernate.criterion.Projections</literal> is a
+ factory for <literal>Projection</literal> instances. We apply a
+ projection to a query by calling <literal>setProjection()</literal>.
+ </para>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.rowCount() )
+ .add( Restrictions.eq("color", Color.BLACK) )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.projectionList()
+ .add( Projections.rowCount() )
+ .add( Projections.avg("weight") )
+ .add( Projections.max("weight") )
+ .add( Projections.groupProperty("color") )
+ )
+ .list();]]></programlisting>
+
+ <para>
+ There is no explicit "group by" necessary in a criteria query. Certain
+ projection types are defined to be <emphasis>grouping projections</emphasis>,
+ which also appear in the SQL <literal>group by</literal> clause.
+ </para>
+
+ <para>
+ An alias may optionally be assigned to a projection, so that the projected value
+ may be referred to in restrictions or orderings. Here are two different ways to
+ do this:
+ </para>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
+ .addOrder( Order.asc("colr") )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.groupProperty("color").as("colr") )
+ .addOrder( Order.asc("colr") )
+ .list();]]></programlisting>
+
+ <para>
+ The <literal>alias()</literal> and <literal>as()</literal> methods simply wrap a
+ projection instance in another, aliased, instance of <literal>Projection</literal>.
+ As a shortcut, you can assign an alias when you add the projection to a
+ projection list:
+ </para>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.projectionList()
+ .add( Projections.rowCount(), "catCountByColor" )
+ .add( Projections.avg("weight"), "avgWeight" )
+ .add( Projections.max("weight"), "maxWeight" )
+ .add( Projections.groupProperty("color"), "color" )
+ )
+ .addOrder( Order.desc("catCountByColor") )
+ .addOrder( Order.desc("avgWeight") )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Domestic.class, "cat")
+ .createAlias("kittens", "kit")
+ .setProjection( Projections.projectionList()
+ .add( Projections.property("cat.name"), "catName" )
+ .add( Projections.property("kit.name"), "kitName" )
+ )
+ .addOrder( Order.asc("catName") )
+ .addOrder( Order.asc("kitName") )
+ .list();]]></programlisting>
+
+ <para>
+ You can also use <literal>Property.forName()</literal> to express projections:
+ </para>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Property.forName("name") )
+ .add( Property.forName("color").eq(Color.BLACK) )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.projectionList()
+ .add( Projections.rowCount().as("catCountByColor") )
+ .add( Property.forName("weight").avg().as("avgWeight") )
+ .add( Property.forName("weight").max().as("maxWeight") )
+ .add( Property.forName("color").group().as("color" )
+ )
+ .addOrder( Order.desc("catCountByColor") )
+ .addOrder( Order.desc("avgWeight") )
+ .list();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-detachedqueries">
+ <title>Detached queries and subqueries</title>
+ <para>
+ The <literal>DetachedCriteria</literal> class lets you create a query outside the scope
+ of a session, and then later execute it using some arbitrary <literal>Session</literal>.
+ </para>
+
+ <programlisting><![CDATA[DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
+ .add( Property.forName("sex").eq('F') );
+
+Session session = ....;
+Transaction txn = session.beginTransaction();
+List results = query.getExecutableCriteria(session).setMaxResults(100).list();
+txn.commit();
+session.close();]]></programlisting>
+
+ <para>
+ A <literal>DetachedCriteria</literal> may also be used to express a subquery. Criterion
+ instances involving subqueries may be obtained via <literal>Subqueries</literal> or
+ <literal>Property</literal>.
+ </para>
+
+ <programlisting><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
+ .setProjection( Property.forName("weight").avg() );
+session.createCriteria(Cat.class)
+ .add( Property.forName("weight).gt(avgWeight) )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
+ .setProjection( Property.forName("weight") );
+session.createCriteria(Cat.class)
+ .add( Subqueries.geAll("weight", weights) )
+ .list();]]></programlisting>
+
+ <para>
+ Even correlated subqueries are possible:
+ </para>
+
+ <programlisting><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
+ .setProjection( Property.forName("weight").avg() )
+ .add( Property.forName("cat2.sex").eqProperty("cat.sex") );
+session.createCriteria(Cat.class, "cat")
+ .add( Property.forName("weight).gt(avgWeightForSex) )
+ .list();]]></programlisting>
+
+ </sect1>
+
+ <!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer allow returning arbitrary
+ user objects - similar to setResultClass in JDO2. General use of ResultTransformer
+ could also be explained. -->
+
+ <sect1 id="query-criteria-naturalid">
+ <title>Queries by natural identifier</title>
+
+ <para>
+ For most queries, including criteria queries, the query cache is not very efficient,
+ because query cache invalidation occurs too frequently. However, there is one special
+ kind of query where we can optimize the cache invalidation algorithm: lookups by a
+ constant natural key. In some applications, this kind of query occurs frequently.
+ The criteria API provides special provision for this use case.
+ </para>
+
+ <para>
+ First, you should map the natural key of your entity using
+ <literal><natural-id></literal>, and enable use of the second-level cache.
+ </para>
+
+ <programlisting><![CDATA[<class name="User">
+ <cache usage="read-write"/>
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <natural-id>
+ <property name="name"/>
+ <property name="org"/>
+ </natural-id>
+ <property name="password"/>
+</class>]]></programlisting>
+
+ <para>
+ Note that this functionality is not intended for use with entities with
+ <emphasis>mutable</emphasis> natural keys.
+ </para>
+
+ <para>
+ Next, enable the Hibernate query cache.
+ </para>
+
+ <para>
+ Now, <literal>Restrictions.naturalId()</literal> allows us to make use of
+ the more efficient cache algorithm.
+ </para>
+
+ <programlisting><![CDATA[session.createCriteria(User.class)
+ .add( Restrictions.naturalId()
+ .set("name", "gavin")
+ .set("org", "hb")
+ ).setCacheable(true)
+ .uniqueResult();]]></programlisting>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/query_hql.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/query_hql.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/query_hql.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,1236 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="queryhql" revision="1">
+ <title>HQL: The Hibernate Query Language</title>
+
+ <para>
+ Hibernate is equipped with an extremely powerful query language that (quite intentionally)
+ looks very much like SQL. But don't be fooled by the syntax; HQL is fully object-oriented,
+ understanding notions like inheritence, polymorphism and association.
+ </para>
+
+ <sect1 id="queryhql-casesensitivity">
+ <title>Case Sensitivity</title>
+
+ <para>
+ Queries are case-insensitive, except for names of Java classes and properties.
+ So <literal>SeLeCT</literal> is the same as
+ <literal>sELEct</literal> is the same as
+ <literal>SELECT</literal> but
+ <literal>org.hibernate.eg.FOO</literal> is not
+ <literal>org.hibernate.eg.Foo</literal> and
+ <literal>foo.barSet</literal> is not
+ <literal>foo.BARSET</literal>.
+ </para>
+
+ <para>
+ This manual uses lowercase HQL keywords. Some users find queries with uppercase keywords
+ more readable, but we find this convention ugly when embedded in Java code.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-from">
+ <title>The from clause</title>
+
+ <para>
+ The simplest possible Hibernate query is of the form:
+ </para>
+
+ <programlisting><![CDATA[from eg.Cat]]></programlisting>
+
+ <para>
+ which simply returns all instances of the class <literal>eg.Cat</literal>.
+ We don't usually need to qualify the class name, since <literal>auto-import</literal>
+ is the default. So we almost always just write:
+ </para>
+
+ <programlisting><![CDATA[from Cat]]></programlisting>
+
+ <para>
+ Most of the time, you will need to assign an <emphasis>alias</emphasis>, since
+ you will want to refer to the <literal>Cat</literal> in other parts of the
+ query.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+ <para>
+ This query assigns the alias <literal>cat</literal> to <literal>Cat</literal>
+ instances, so we could use that alias later in the query. The <literal>as</literal>
+ keyword is optional; we could also write:
+ </para>
+
+ <programlisting><![CDATA[from Cat cat]]></programlisting>
+
+ <para>
+ Multiple classes may appear, resulting in a cartesian product or "cross" join.
+ </para>
+
+ <programlisting><![CDATA[from Formula, Parameter]]></programlisting>
+ <programlisting><![CDATA[from Formula as form, Parameter as param]]></programlisting>
+
+ <para>
+ It is considered good practice to name query aliases using an initial lowercase,
+ consistent with Java naming standards for local variables
+ (eg. <literal>domesticCat</literal>).
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-joins" revision="2">
+ <title>Associations and joins</title>
+
+ <para>
+ We may also assign aliases to associated entities, or even to elements of a
+ collection of values, using a <literal>join</literal>.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ inner join cat.mate as mate
+ left outer join cat.kittens as kitten]]></programlisting>
+
+ <programlisting><![CDATA[from Cat as cat left join cat.mate.kittens as kittens]]></programlisting>
+
+ <programlisting><![CDATA[from Formula form full join form.parameter param]]></programlisting>
+
+ <para>
+ The supported join types are borrowed from ANSI SQL
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>inner join</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>left outer join</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>right outer join</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>full join</literal> (not usually useful)
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The <literal>inner join</literal>, <literal>left outer join</literal> and
+ <literal>right outer join</literal> constructs may be abbreviated.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ join cat.mate as mate
+ left join cat.kittens as kitten]]></programlisting>
+
+ <para>
+ You may supply extra join conditions using the HQL <literal>with</literal>
+ keyword.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ left join cat.kittens as kitten
+ with kitten.bodyWeight > 10.0]]></programlisting>
+
+ <para>
+ In addition, a "fetch" join allows associations or collections of values to be
+ initialized along with their parent objects, using a single select. This is particularly
+ useful in the case of a collection. It effectively overrides the outer join and
+ lazy declarations of the mapping file for associations and collections. See
+ <xref linkend="performance-fetching"/> for more information.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ inner join fetch cat.mate
+ left join fetch cat.kittens]]></programlisting>
+
+ <para>
+ A fetch join does not usually need to assign an alias, because the associated objects
+ should not be used in the <literal>where</literal> clause (or any other clause). Also,
+ the associated objects are not returned directly in the query results. Instead, they may
+ be accessed via the parent object. The only reason we might need an alias is if we are
+ recursively join fetching a further collection:
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ inner join fetch cat.mate
+ left join fetch cat.kittens child
+ left join fetch child.kittens]]></programlisting>
+
+ <para>
+ Note that the <literal>fetch</literal> construct may not be used in queries called using
+ <literal>iterate()</literal> (though <literal>scroll()</literal> can be used). Nor should
+ <literal>fetch</literal> be used together with <literal>setMaxResults()</literal> or
+ <literal>setFirstResult()</literal> as these operations are based on the result rows, which
+ usually contain duplicates for eager collection fetching, hence, the number of rows is not what
+ you'd expect.
+ Nor may <literal>fetch</literal> be used together with an ad hoc <literal>with</literal> condition.
+ It is possible to create a cartesian product by join fetching more than one collection in a
+ query, so take care in this case. Join fetching multiple collection roles also sometimes gives
+ unexpected results for bag mappings, so be careful about how you formulate your queries in this
+ case. Finally, note that <literal>full join fetch</literal> and <literal>right join fetch</literal>
+ are not meaningful.
+ </para>
+
+ <para>
+ If you are using property-level lazy fetching (with bytecode instrumentation), it is
+ possible to force Hibernate to fetch the lazy properties immediately (in the first
+ query) using <literal>fetch all properties</literal>.
+ </para>
+
+ <programlisting><![CDATA[from Document fetch all properties order by name]]></programlisting>
+ <programlisting><![CDATA[from Document doc fetch all properties where lower(doc.name) like '%cats%']]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-joins-forms">
+ <title>Forms of join syntax</title>
+
+ <para>
+ HQL supports two forms of association joining: <literal>implicit</literal> and <literal>explicit</literal>.
+ </para>
+
+ <para>
+ The queries shown in the previous section all use the <literal>explicit</literal> form where
+ the join keyword is explicitly used in the from clause. This is the recommended form.
+ </para>
+
+ <para>
+ The <literal>implicit</literal> form does not use the join keyword. Instead, the
+ associations are "dereferenced" using dot-notation. <literal>implicit</literal> joins
+ can appear in any of the HQL clauses. <literal>implicit</literal> join result
+ in inner joins in the resulting SQL statement.
+ </para>
+
+ <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>The select clause</title>
+
+ <para>
+ The <literal>select</literal> clause picks which objects and properties to return in
+ the query result set. Consider:
+ </para>
+
+ <programlisting><![CDATA[select mate
+from Cat as cat
+ inner join cat.mate as mate]]></programlisting>
+
+ <para>
+ The query will select <literal>mate</literal>s of other <literal>Cat</literal>s.
+ Actually, you may express this query more compactly as:
+ </para>
+
+ <programlisting><![CDATA[select cat.mate from Cat cat]]></programlisting>
+
+ <para>
+ Queries may return properties of any value type including properties of component type:
+ </para>
+
+ <programlisting><![CDATA[select cat.name from DomesticCat cat
+where cat.name like 'fri%']]></programlisting>
+
+ <programlisting><![CDATA[select cust.name.firstName from Customer as cust]]></programlisting>
+
+ <para>
+ Queries may return multiple objects and/or properties as an array of type
+ <literal>Object[]</literal>,
+ </para>
+
+ <programlisting><![CDATA[select mother, offspr, mate.name
+from DomesticCat as mother
+ inner join mother.mate as mate
+ left outer join mother.kittens as offspr]]></programlisting>
+
+ <para>
+ or as a <literal>List</literal>,
+ </para>
+
+ <programlisting><![CDATA[select new list(mother, offspr, mate.name)
+from DomesticCat as mother
+ inner join mother.mate as mate
+ left outer join mother.kittens as offspr]]></programlisting>
+
+ <para>
+ or as an actual typesafe Java object,
+ </para>
+
+ <programlisting><![CDATA[select new Family(mother, mate, offspr)
+from DomesticCat as mother
+ join mother.mate as mate
+ left join mother.kittens as offspr]]></programlisting>
+
+ <para>
+ assuming that the class <literal>Family</literal> has an appropriate constructor.
+ </para>
+
+ <para>
+ You may assign aliases to selected expressions using <literal>as</literal>:
+ </para>
+
+ <programlisting><![CDATA[select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n
+from Cat cat]]></programlisting>
+
+ <para>
+ This is most useful when used together with <literal>select new map</literal>:
+ </para>
+
+ <programlisting><![CDATA[select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
+from Cat cat]]></programlisting>
+
+ <para>
+ This query returns a <literal>Map</literal> from aliases to selected values.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-aggregation">
+ <title>Aggregate functions</title>
+
+ <para>
+ HQL queries may even return the results of aggregate functions on properties:
+ </para>
+
+ <programlisting><![CDATA[select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
+from Cat cat]]></programlisting>
+
+<!-- NO LONGER SUPPORTED
+ <para>
+ Collections may also appear inside aggregate functions in the <literal>select</literal>
+ clause.
+ </para>
+
+ <programlisting><![CDATA[select cat, count( elements(cat.kittens) )
+from Cat cat group by cat]]></programlisting>
+-->
+
+ <para>
+ The supported aggregate functions are
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>avg(...), sum(...), min(...), max(...)</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>count(*)</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>count(...), count(distinct ...), count(all...)</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ You may use arithmetic operators, concatenation, and recognized SQL functions
+ in the select clause:
+ </para>
+
+ <programlisting><![CDATA[select cat.weight + sum(kitten.weight)
+from Cat cat
+ join cat.kittens kitten
+group by cat.id, cat.weight]]></programlisting>
+
+ <programlisting><![CDATA[select firstName||' '||initial||' '||upper(lastName) from Person]]></programlisting>
+
+ <para>
+ The <literal>distinct</literal> and <literal>all</literal> keywords may be used and
+ have the same semantics as in SQL.
+ </para>
+
+ <programlisting><![CDATA[select distinct cat.name from Cat cat
+
+select count(distinct cat.name), count(cat) from Cat cat]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-polymorphism">
+ <title>Polymorphic queries</title>
+
+ <para>
+ A query like:
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+ <para>
+ returns instances not only of <literal>Cat</literal>, but also of subclasses like
+ <literal>DomesticCat</literal>. Hibernate queries may name <emphasis>any</emphasis> Java
+ class or interface in the <literal>from</literal> clause. The query will return instances
+ of all persistent classes that extend that class or implement the interface. The following
+ query would return all persistent objects:
+ </para>
+
+ <programlisting><![CDATA[from java.lang.Object o]]></programlisting>
+
+ <para>
+ The interface <literal>Named</literal> might be implemented by various persistent
+ classes:
+ </para>
+
+ <programlisting><![CDATA[from Named n, Named m where n.name = m.name]]></programlisting>
+
+ <para>
+ Note that these last two queries will require more than one SQL <literal>SELECT</literal>. This
+ means that the <literal>order by</literal> clause does not correctly order the whole result set.
+ (It also means you can't call these queries using <literal>Query.scroll()</literal>.)
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-where" revision="1">
+ <title>The where clause</title>
+
+ <para>
+ The <literal>where</literal> clause allows you to narrow the list of instances returned.
+ If no alias exists, you may refer to properties by name:
+ </para>
+
+ <programlisting><![CDATA[from Cat where name='Fritz']]></programlisting>
+
+ <para>
+ If there is an alias, use a qualified property name:
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat where cat.name='Fritz']]></programlisting>
+
+ <para>
+ returns instances of <literal>Cat</literal> named 'Fritz'.
+ </para>
+
+ <programlisting><![CDATA[select foo
+from Foo foo, Bar bar
+where foo.startDate = bar.date]]></programlisting>
+
+ <para>
+ will return all instances of <literal>Foo</literal> for which
+ there exists an instance of <literal>bar</literal> with a
+ <literal>date</literal> property equal to the
+ <literal>startDate</literal> property of the
+ <literal>Foo</literal>. Compound path expressions make the
+ <literal>where</literal> clause extremely powerful. Consider:
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.mate.name is not null]]></programlisting>
+
+ <para>
+ This query translates to an SQL query with a table (inner) join. If you were to write
+ something like
+ </para>
+
+ <programlisting><![CDATA[from Foo foo
+where foo.bar.baz.customer.address.city is not null]]></programlisting>
+
+ <para>
+ you would end up with a query that would require four table joins in SQL.
+ </para>
+
+ <para>
+ The <literal>=</literal> operator may be used to compare not only properties, but also
+ instances:
+ </para>
+
+ <programlisting><![CDATA[from Cat cat, Cat rival where cat.mate = rival.mate]]></programlisting>
+
+ <programlisting><![CDATA[select cat, mate
+from Cat cat, Cat mate
+where cat.mate = mate]]></programlisting>
+
+ <para>
+ The special property (lowercase) <literal>id</literal> may be used to reference the
+ unique identifier of an object. See <xref linkend="queryhql-identifier-property"/>
+ for more information.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat where cat.id = 123
+
+from Cat as cat where cat.mate.id = 69]]></programlisting>
+
+ <para>
+ The second query is efficient. No table join is required!
+ </para>
+
+ <para>
+ Properties of composite identifiers may also be used. Suppose <literal>Person</literal>
+ has a composite identifier consisting of <literal>country</literal> and
+ <literal>medicareNumber</literal>. Again, see <xref linkend="queryhql-identifier-property"/>
+ for more information regarding referencing identifier properties.
+ </para>
+
+ <programlisting><![CDATA[from bank.Person person
+where person.id.country = 'AU'
+ and person.id.medicareNumber = 123456]]></programlisting>
+
+ <programlisting><![CDATA[from bank.Account account
+where account.owner.id.country = 'AU'
+ and account.owner.id.medicareNumber = 123456]]></programlisting>
+
+ <para>
+ Once again, the second query requires no table join.
+ </para>
+
+ <para>
+ Likewise, the special property <literal>class</literal> accesses the discriminator value
+ of an instance in the case of polymorphic persistence. A Java class name embedded in the
+ where clause will be translated to its discriminator value.
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.class = DomesticCat]]></programlisting>
+
+ <para>
+ You may also use components or composite user types, or properties of said
+ component types. See <xref linkend="queryhql-coomponents"/> for more details.
+ </para>
+
+ <para>
+ An "any" type has the special properties <literal>id</literal> and <literal>class</literal>,
+ allowing us to express a join in the following way (where <literal>AuditLog.item</literal>
+ is a property mapped with <literal><any></literal>).
+ </para>
+
+ <programlisting><![CDATA[from AuditLog log, Payment payment
+where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting>
+
+ <para>
+ Notice that <literal>log.item.class</literal> and <literal>payment.class</literal>
+ would refer to the values of completely different database columns in the above query.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-expressions">
+ <title>Expressions</title>
+
+ <para>
+ Expressions allowed in the <literal>where</literal> clause include
+ most of the kind of things you could write in SQL:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ mathematical operators <literal>+, -, *, /</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ binary comparison operators <literal>=, >=, <=, <>, !=, like</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ logical operations <literal>and, or, not</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Parentheses <literal>( )</literal>, indicating grouping
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>in</literal>,
+ <literal>not in</literal>,
+ <literal>between</literal>,
+ <literal>is null</literal>,
+ <literal>is not null</literal>,
+ <literal>is empty</literal>,
+ <literal>is not empty</literal>,
+ <literal>member of</literal> and
+ <literal>not member of</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ "Simple" case, <literal>case ... when ... then ... else ... end</literal>, and
+ "searched" case, <literal>case when ... then ... else ... end</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ string concatenation <literal>...||...</literal> or <literal>concat(...,...)</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>current_date()</literal>, <literal>current_time()</literal>,
+ <literal>current_timestamp()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>second(...)</literal>, <literal>minute(...)</literal>,
+ <literal>hour(...)</literal>, <literal>day(...)</literal>,
+ <literal>month(...)</literal>, <literal>year(...)</literal>,
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Any function or operator defined by EJB-QL 3.0: <literal>substring(), trim(),
+ lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(), mod()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>coalesce()</literal> and <literal>nullif()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>str()</literal> for converting numeric or temporal values to a
+ readable string
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>cast(... as ...)</literal>, where the second argument is the name of
+ a Hibernate type, and <literal>extract(... from ...)</literal> if ANSI
+ <literal>cast()</literal> and <literal>extract()</literal> is supported by
+ the underlying database
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ the HQL <literal>index()</literal> function, that applies to aliases of
+ a joined indexed collection
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ HQL functions that take collection-valued path expressions: <literal>size(),
+ minelement(), maxelement(), minindex(), maxindex()</literal>, along with the
+ special <literal>elements()</literal> and <literal>indices</literal> functions
+ which may be quantified using <literal>some, all, exists, any, in</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Any database-supported SQL scalar function like <literal>sign()</literal>,
+ <literal>trunc()</literal>, <literal>rtrim()</literal>, <literal>sin()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ JDBC-style positional parameters <literal>?</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ named parameters <literal>:name</literal>, <literal>:start_date</literal>, <literal>:x1</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ SQL literals <literal>'foo'</literal>, <literal>69</literal>, <literal>6.66E+2</literal>,
+ <literal>'1970-01-01 10:00:01.0'</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Java <literal>public static final</literal> constants <literal>eg.Color.TABBY</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ <literal>in</literal> and <literal>between</literal> may be used as follows:
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name between 'A' and 'B']]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+ <para>
+ and the negated forms may be written
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name not between 'A' and 'B']]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+ <para>
+ Likewise, <literal>is null</literal> and <literal>is not null</literal> may be used to test
+ for null values.
+ </para>
+
+ <para>
+ Booleans may be easily used in expressions by declaring HQL query substitutions in Hibernate
+ configuration:
+ </para>
+
+ <programlisting><![CDATA[<property name="hibernate.query.substitutions">true 1, false 0</property>]]></programlisting>
+
+ <para>
+ This will replace the keywords <literal>true</literal> and <literal>false</literal> with the
+ literals <literal>1</literal> and <literal>0</literal> in the translated SQL from this HQL:
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.alive = true]]></programlisting>
+
+ <para>
+ You may test the size of a collection with the special property <literal>size</literal>, or
+ the special <literal>size()</literal> function.
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.kittens.size > 0]]></programlisting>
+
+ <programlisting><![CDATA[from Cat cat where size(cat.kittens) > 0]]></programlisting>
+
+ <para>
+ For indexed collections, you may refer to the minimum and maximum indices using
+ <literal>minindex</literal> and <literal>maxindex</literal> functions. Similarly,
+ you may refer to the minimum and maximum elements of a collection of basic type
+ using the <literal>minelement</literal> and <literal>maxelement</literal>
+ functions.
+ </para>
+
+ <programlisting><![CDATA[from Calendar cal where maxelement(cal.holidays) > current_date]]></programlisting>
+
+ <programlisting><![CDATA[from Order order where maxindex(order.items) > 100]]></programlisting>
+
+ <programlisting><![CDATA[from Order order where minelement(order.items) > 10000]]></programlisting>
+
+ <para>
+ The SQL functions <literal>any, some, all, exists, in</literal> are supported when passed the element
+ or index set of a collection (<literal>elements</literal> and <literal>indices</literal> functions)
+ or the result of a subquery (see below).
+ </para>
+
+ <programlisting><![CDATA[select mother from Cat as mother, Cat as kit
+where kit in elements(foo.kittens)]]></programlisting>
+
+ <programlisting><![CDATA[select p from NameList list, Person p
+where p.name = some elements(list.names)]]></programlisting>
+
+ <programlisting><![CDATA[from Cat cat where exists elements(cat.kittens)]]></programlisting>
+
+ <programlisting><![CDATA[from Player p where 3 > all elements(p.scores)]]></programlisting>
+
+ <programlisting><![CDATA[from Show show where 'fizard' in indices(show.acts)]]></programlisting>
+
+ <para>
+ Note that these constructs - <literal>size</literal>, <literal>elements</literal>,
+ <literal>indices</literal>, <literal>minindex</literal>, <literal>maxindex</literal>,
+ <literal>minelement</literal>, <literal>maxelement</literal> - may only be used in
+ the where clause in Hibernate3.
+ </para>
+
+ <para>
+ Elements of indexed collections (arrays, lists, maps) may be referred to by
+ index (in a where clause only):
+ </para>
+
+ <programlisting><![CDATA[from Order order where order.items[0].id = 1234]]></programlisting>
+
+ <programlisting><![CDATA[select person from Person person, Calendar calendar
+where calendar.holidays['national day'] = person.birthDay
+ and person.nationality.calendar = calendar]]></programlisting>
+
+ <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11]]></programlisting>
+
+ <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ maxindex(order.items) ] = item and order.id = 11]]></programlisting>
+
+ <para>
+ The expression inside <literal>[]</literal> may even be an arithmetic expression.
+ </para>
+
+ <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ size(order.items) - 1 ] = item]]></programlisting>
+
+ <para>
+ HQL also provides the built-in <literal>index()</literal> function, for elements
+ of a one-to-many association or collection of values.
+ </para>
+
+ <programlisting><![CDATA[select item, index(item) from Order order
+ join order.items item
+where index(item) < 5]]></programlisting>
+
+ <para>
+ Scalar SQL functions supported by the underlying database may be used
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat where upper(cat.name) like 'FRI%']]></programlisting>
+
+ <para>
+ If you are not yet convinced by all this, think how much longer and less readable the
+ following query would be in SQL:
+ </para>
+
+ <programlisting><![CDATA[select cust
+from Product prod,
+ Store store
+ inner join store.customers cust
+where prod.name = 'widget'
+ and store.location.name in ( 'Melbourne', 'Sydney' )
+ and prod = all elements(cust.currentOrder.lineItems)]]></programlisting>
+
+ <para>
+ <emphasis>Hint:</emphasis> something like
+ </para>
+
+ <programlisting><![CDATA[SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
+FROM customers cust,
+ stores store,
+ locations loc,
+ store_customers sc,
+ product prod
+WHERE prod.name = 'widget'
+ AND store.loc_id = loc.id
+ AND loc.name IN ( 'Melbourne', 'Sydney' )
+ AND sc.store_id = store.id
+ AND sc.cust_id = cust.id
+ AND prod.id = ALL(
+ SELECT item.prod_id
+ FROM line_items item, orders o
+ WHERE item.order_id = o.id
+ AND cust.current_order = o.id
+ )]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-ordering">
+ <title>The order by clause</title>
+
+ <para>
+ The list returned by a query may be ordered by any property of a returned class or components:
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat
+order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
+
+ <para>
+ The optional <literal>asc</literal> or <literal>desc</literal> indicate ascending or descending order
+ respectively.
+ </para>
+ </sect1>
+
+ <sect1 id="queryhql-grouping" revision="1">
+ <title>The group by clause</title>
+
+ <para>
+ A query that returns aggregate values may be grouped by any property of a returned class or components:
+ </para>
+
+ <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
+from Cat cat
+group by cat.color]]></programlisting>
+
+ <programlisting><![CDATA[select foo.id, avg(name), max(name)
+from Foo foo join foo.names name
+group by foo.id]]></programlisting>
+
+ <para>
+ A <literal>having</literal> clause is also allowed.
+ </para>
+
+ <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
+from Cat cat
+group by cat.color
+having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting>
+
+ <para>
+ SQL functions and aggregate functions are allowed in the <literal>having</literal>
+ and <literal>order by</literal> clauses, if supported by the underlying database
+ (eg. not in MySQL).
+ </para>
+
+ <programlisting><![CDATA[select cat
+from Cat cat
+ join cat.kittens kitten
+group by cat.id, cat.name, cat.other, cat.properties
+having avg(kitten.weight) > 100
+order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
+
+ <para>
+ Note that neither the <literal>group by</literal> clause nor the
+ <literal>order by</literal> clause may contain arithmetic expressions.
+ Also note that Hibernate currently does not expand a grouped entity,
+ so you can't write <literal>group by cat</literal> if all properties
+ of <literal>cat</literal> are non-aggregated. You have to list all
+ non-aggregated properties explicitly.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-subqueries" revision="3">
+ <title>Subqueries</title>
+
+ <para>
+ For databases that support subselects, Hibernate supports subqueries within queries. A subquery must
+ be surrounded by parentheses (often by an SQL aggregate function call). Even correlated subqueries
+ (subqueries that refer to an alias in the outer query) are allowed.
+ </para>
+
+ <programlisting><![CDATA[from Cat as fatcat
+where fatcat.weight > (
+ select avg(cat.weight) from DomesticCat cat
+)]]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat as cat
+where cat.name = some (
+ select name.nickName from Name as name
+)]]></programlisting>
+
+ <programlisting><![CDATA[from Cat as cat
+where not exists (
+ from Cat as mate where mate.mate = cat
+)]]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat as cat
+where cat.name not in (
+ select name.nickName from Name as name
+)]]></programlisting>
+
+ <programlisting><![CDATA[select cat.id, (select max(kit.weight) from cat.kitten kit)
+from Cat as cat]]></programlisting>
+
+ <para>
+ Note that HQL subqueries may occur only in the select or where clauses.
+ </para>
+
+ <para>
+ Note that subqueries can also utilize <literal>row value constructor</literal> syntax. See
+ <xref linkend="queryhql-tuple"/> for more details.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-examples">
+ <title>HQL examples</title>
+
+ <para>
+ Hibernate queries can be quite powerful and complex. In fact, the power of the query language
+ is one of Hibernate's main selling points. Here are some example queries very similar to queries
+ that I used on a recent project. Note that most queries you will write are much simpler than these!
+ </para>
+
+ <para>
+ The following query returns the order id, number of items and total value of the order for all
+ unpaid orders for a particular customer and given minimum total value, ordering the results by
+ total value. In determining the prices, it uses the current catalog. The resulting SQL query,
+ against the <literal>ORDER</literal>, <literal>ORDER_LINE</literal>, <literal>PRODUCT</literal>,
+ <literal>CATALOG</literal> and <literal>PRICE</literal> tables has four inner joins and an
+ (uncorrelated) subselect.
+ </para>
+
+ <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+ join order.lineItems as item
+ join item.product as product,
+ Catalog as catalog
+ join catalog.prices as price
+where order.paid = false
+ and order.customer = :customer
+ and price.product = product
+ and catalog.effectiveDate < sysdate
+ and catalog.effectiveDate >= all (
+ select cat.effectiveDate
+ from Catalog as cat
+ where cat.effectiveDate < sysdate
+ )
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+
+ <para>
+ What a monster! Actually, in real life, I'm not very keen on subqueries, so my query was
+ really more like this:
+ </para>
+
+ <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+ join order.lineItems as item
+ join item.product as product,
+ Catalog as catalog
+ join catalog.prices as price
+where order.paid = false
+ and order.customer = :customer
+ and price.product = product
+ and catalog = :currentCatalog
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+
+ <para>
+ The next query counts the number of payments in each status, excluding all payments in the
+ <literal>AWAITING_APPROVAL</literal> status where the most recent status change was made by the
+ current user. It translates to an SQL query with two inner joins and a correlated subselect
+ against the <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal> and
+ <literal>PAYMENT_STATUS_CHANGE</literal> tables.
+ </para>
+
+ <programlisting><![CDATA[select count(payment), status.name
+from Payment as payment
+ join payment.currentStatus as status
+ join payment.statusChanges as statusChange
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+ or (
+ statusChange.timeStamp = (
+ select max(change.timeStamp)
+ from PaymentStatusChange change
+ where change.payment = payment
+ )
+ and statusChange.user <> :currentUser
+ )
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+ <para>
+ If I would have mapped the <literal>statusChanges</literal> collection as a list, instead of a set,
+ the query would have been much simpler to write.
+ </para>
+
+ <programlisting><![CDATA[select count(payment), status.name
+from Payment as payment
+ join payment.currentStatus as status
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+ or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+ <para>
+ The next query uses the MS SQL Server <literal>isNull()</literal> function to return all
+ the accounts and unpaid payments for the organization to which the current user belongs.
+ It translates to an SQL query with three inner joins, an outer join and a subselect against
+ the <literal>ACCOUNT</literal>, <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal>,
+ <literal>ACCOUNT_TYPE</literal>, <literal>ORGANIZATION</literal> and
+ <literal>ORG_USER</literal> tables.
+ </para>
+
+ <programlisting><![CDATA[select account, payment
+from Account as account
+ left outer join account.payments as payment
+where :currentUser in elements(account.holder.users)
+ and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+ <para>
+ For some databases, we would need to do away with the (correlated) subselect.
+ </para>
+
+ <programlisting><![CDATA[select account, payment
+from Account as account
+ join account.holder.users as user
+ left outer join account.payments as payment
+where :currentUser = user
+ and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-bulk" revision="2">
+ <title>Bulk update and delete</title>
+
+ <para>
+ HQL now supports <literal>update</literal>, <literal>delete</literal> and
+ <literal>insert ... select ...</literal> statements.
+ See <xref linkend="batch-direct"/> for details.
+ </para>
+ </sect1>
+
+ <sect1 id="queryhql-tipstricks">
+ <title>Tips & Tricks</title>
+
+ <para>
+ You can count the number of query results without actually returning them:
+ </para>
+
+ <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue()]]></programlisting>
+
+ <para>
+ To order a result by the size of a collection, use the following query:
+ </para>
+
+ <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+ left join usr.messages as msg
+group by usr.id, usr.name
+order by count(msg)]]></programlisting>
+
+ <para>
+ If your database supports subselects, you can place a condition upon selection
+ size in the where clause of your query:
+ </para>
+
+ <programlisting><![CDATA[from User usr where size(usr.messages) >= 1]]></programlisting>
+
+ <para>
+ If your database doesn't support subselects, use the following query:
+ </para>
+
+ <programlisting><![CDATA[select usr.id, usr.name
+from User usr.name
+ join usr.messages msg
+group by usr.id, usr.name
+having count(msg) >= 1]]></programlisting>
+
+ <para>
+ As this solution can't return a <literal>User</literal> with zero messages
+ because of the inner join, the following form is also useful:
+ </para>
+
+ <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+ left join usr.messages as msg
+group by usr.id, usr.name
+having count(msg) = 0]]></programlisting>
+
+ <para>
+ Properties of a JavaBean can be bound to named query parameters:
+ </para>
+
+ <programlisting><![CDATA[Query q = s.createQuery("from foo Foo as foo where foo.name=:name and foo.size=:size");
+q.setProperties(fooBean); // fooBean has getName() and getSize()
+List foos = q.list();]]></programlisting>
+
+ <para>
+ Collections are pageable by using the <literal>Query</literal> interface with a filter:
+ </para>
+
+ <programlisting><![CDATA[Query q = s.createFilter( collection, "" ); // the trivial filter
+q.setMaxResults(PAGE_SIZE);
+q.setFirstResult(PAGE_SIZE * pageNumber);
+List page = q.list();]]></programlisting>
+
+ <para>
+ Collection elements may be ordered or grouped using a query filter:
+ </para>
+
+ <programlisting><![CDATA[Collection orderedCollection = s.filter( collection, "order by this.amount" );
+Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );]]></programlisting>
+
+ <para>
+ You can find the size of a collection without initializing it:
+ </para>
+
+ <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-components">
+ <title>Components</title>
+
+ <para>
+ Components might be used in just about every way that simple value types can be used in HQL
+ queries. They can appear in the <literal>select</literal> clause:
+ </para>
+
+ <programlisting><![CDATA[select p.name from from Person p]]></programlisting>
+ <programlisting><![CDATA[select p.name.first from from Person p]]></programlisting>
+
+ <para>
+ where the Person's name property is a component. Components can also be used
+ in the <literal>where</literal> clause:
+ </para>
+
+ <programlisting><![CDATA[from from Person p where p.name = :name]]></programlisting>
+ <programlisting><![CDATA[from from Person p where p.name.first = :firstName]]></programlisting>
+
+ <para>
+ Components can also be used in the <literal>order by</literal> clause:
+ </para>
+
+ <programlisting><![CDATA[from from Person p order by p.name]]></programlisting>
+ <programlisting><![CDATA[from from Person p order by p.name.first]]></programlisting>
+
+ <para>
+ Another common use of components is in <xref linkend="queryhql-tuple">row value constructors</xref>.
+ </para>
+ </sect1>
+
+ <sect1 id="queryhql-tuple">
+ <title>Row value constructor syntax</title>
+
+ <para>
+ HQL supports the use of ANSI SQL <literal>row value constructor</literal> syntax (sometimes
+ called <literal>tuple</literal> syntax), even though the underlying database may not support
+ that notion. Here we are generally referring to multi-valued comparisons, typically associated
+ with components. Consider an entity Person which defines a name component:
+ </para>
+
+ <programlisting><![CDATA[from Person p where p.name.first='John' and p.name.last='Jingleheimer-Schmidt']]></programlisting>
+
+ <para>
+ That's valid syntax, although a little verbose. It be nice to make this a bit more concise and use
+ <literal>row value constructor</literal> syntax:
+ </para>
+
+ <programlisting><![CDATA[from Person p where p.name=('John', 'Jingleheimer-Schmidt')]]></programlisting>
+
+ <para>
+ It can also be useful to specify this in the <literal>select</literal> clause:
+ </para>
+
+ <programlisting><![CDATA[select p.name from from Person p]]></programlisting>
+
+ <para>
+ Another time using <literal>row value constructor</literal> syntax can be beneficial
+ is when using subqueries needing to compare against multiple values:
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+where not ( cat.name, cat.color ) in (
+ select cat.name, cat.color from DomesticCat cat
+)]]></programlisting>
+
+ <para>
+ One thing to consider when deciding if you want to use this syntax is that the query will
+ be dependent upon the ordering of the component sub-properties in the metadata.
+ </para>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/query_sql.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/query_sql.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/query_sql.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,759 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="querysql" revision="2">
+ <title>Native SQL</title>
+
+ <para>You may also express queries in the native SQL dialect of your
+ database. This is useful if you want to utilize database specific features
+ such as query hints or the <literal>CONNECT</literal> keyword in Oracle. It
+ also provides a clean migration path from a direct SQL/JDBC based
+ application to Hibernate.</para>
+
+ <para>Hibernate3 allows you to specify handwritten SQL (including stored
+ procedures) for all create, update, delete, and load operations.</para>
+
+ <sect1 id="querysql-creating" revision="4">
+ <title>Using a <literal>SQLQuery</literal></title>
+
+ <para>Execution of native SQL queries is controlled via the
+ <literal>SQLQuery</literal> interface, which is obtained by calling
+ <literal>Session.createSQLQuery()</literal>. The following describes how
+ to use this API for querying.</para>
+
+ <sect2>
+ <title>Scalar queries</title>
+
+ <para>The most basic SQL query is to get a list of scalars
+ (values).</para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").list();
+sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
+]]></programlisting>
+
+ <para>These will both return a List of Object arrays (Object[]) with
+ scalar values for each column in the CATS table. Hibernate will use
+ ResultSetMetadata to deduce the actual order and types of the returned
+ scalar values.</para>
+
+ <para>To avoid the overhead of using
+ <literal>ResultSetMetadata</literal> or simply to be more explicit in
+ what is returned one can use <literal>addScalar()</literal>.</para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME", Hibernate.STRING)
+ .addScalar("BIRTHDATE", Hibernate.DATE)
+]]></programlisting>
+
+ <para>This query specified:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>the SQL query string</para>
+ </listitem>
+
+ <listitem>
+ <para>the columns and types to return</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>This will still return Object arrays, but now it will not use
+ <literal>ResultSetMetdata</literal> but will instead explicitly get the
+ ID, NAME and BIRTHDATE column as respectively a Long, String and a Short
+ 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>
+
+ <para>It is possible to leave out the type information for all or some
+ of the scalars.</para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME")
+ .addScalar("BIRTHDATE")
+]]></programlisting>
+
+ <para>This is essentially the same query as before, but now
+ <literal>ResultSetMetaData</literal> is used to decide the type of NAME
+ and BIRTHDATE where as the type of ID is explicitly specified.</para>
+
+ <para>How the java.sql.Types returned from ResultSetMetaData is mapped
+ 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>
+
+ <sect2>
+ <title>Entity queries</title>
+
+ <para>The above queries were all about returning scalar values,
+ 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>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class);
+sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);
+]]></programlisting>
+
+ <para>This query specified:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>the SQL query string</para>
+ </listitem>
+
+ <listitem>
+ <para>the entity returned by the query</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Assuming that Cat is mapped as a class with the columns ID, NAME
+ and BIRTHDATE the above queries will both return a List where each
+ element is a Cat entity.</para>
+
+ <para>If the entity is mapped with a <literal>many-to-one</literal> to
+ another entity it is required to also return this when performing the
+ native query, otherwise a database specific "column not found" error
+ 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>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);
+]]></programlisting>
+
+ <para>This will allow cat.getDog() to function properly.</para>
+ </sect2>
+
+ <sect2>
+ <title>Handling associations and collections</title>
+
+ <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>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dog");
+]]></programlisting>
+
+ <para>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>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dogs");
+]]></programlisting>
+
+ <p>At this stage we are reaching the limits of what is possible with
+ native queries without starting to 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.</p>
+ </sect2>
+
+ <sect2>
+ <title>Returning multiple entities</title>
+
+ <para>Until now the result set column names are assumed to be the same
+ 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>
+
+ <para>Column alias injection is needed in the following query (which
+ most likely will fail):</para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT c.*, m.* FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+]]></programlisting>
+
+ <para>The intention for this query is to return two Cat instances per
+ row, a cat and its mother. This will fail since there is a conflict of
+ 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>
+
+ <para>The following form is not vulnerable to column name
+ duplication:</para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT {cat.*}, {mother.*} FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+]]></programlisting>
+
+ <para>This query specified:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>the SQL query string, with placeholders for Hibernate to
+ inject column aliases</para>
+ </listitem>
+
+ <listitem>
+ <para>the entities returned by the query</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The {cat.*} and {mother.*} notation used above is a shorthand for
+ "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>
+
+ <programlisting><![CDATA[String sql = "SELECT ID as {c.id}, NAME as {c.name}, " +
+ "BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
+ "FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
+
+List loggedCats = sess.createSQLQuery(sql)
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class).list()
+]]></programlisting>
+
+ <sect3 id="querysql-aliasreferences" revision="2">
+ <title>Alias and property references</title>
+
+ <para>For most cases the above alias injection is needed, but for
+ 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>
+
+ <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>
+
+ <table frame="topbot" id="aliasinjection-summary">
+ <title>Alias injection names</title>
+
+ <tgroup cols="3">
+ <colspec colwidth="1*" />
+
+ <colspec colwidth="1*" />
+
+ <colspec colwidth="2.5*" />
+
+ <thead>
+ <row>
+ <entry>Description</entry>
+
+ <entry>Syntax</entry>
+
+ <entry>Example</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>A simple property</entry>
+
+ <entry><literal>{[aliasname].[propertyname]</literal></entry>
+
+ <entry><literal>A_NAME as {item.name}</literal></entry>
+ </row>
+
+ <row>
+ <entry>A composite property</entry>
+
+ <entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
+
+ <entry><literal>CURRENCY as {item.amount.currency}, VALUE as
+ {item.amount.value}</literal></entry>
+ </row>
+
+ <row>
+ <entry>Discriminator of an entity</entry>
+
+ <entry><literal>{[aliasname].class}</literal></entry>
+
+ <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">
+ <title>Named SQL queries</title>
+
+ <para>Named SQL queries may be defined in the mapping document and called
+ in exactly the same way as a named HQL query. In this case, we do
+ <emphasis>not</emphasis> need to call
+ <literal>addEntity()</literal>.</para>
+
+ <programlisting><![CDATA[<sql-query name="persons">
+ <return alias="person" class="eg.Person"/>
+ SELECT person.NAME AS {person.name},
+ person.AGE AS {person.age},
+ person.SEX AS {person.sex}
+ FROM PERSON person
+ WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+ <programlisting><![CDATA[List people = sess.getNamedQuery("persons")
+ .setString("namePattern", namePattern)
+ .setMaxResults(50)
+ .list();]]></programlisting>
+
+ <para>The <literal><return-join></literal> and
+ <literal><load-collection></literal> elements are used to join
+ associations and define queries which initialize collections,
+ respectively.</para>
+
+ <programlisting><![CDATA[<sql-query name="personsWith">
+ <return alias="person" class="eg.Person"/>
+ <return-join alias="address" property="person.mailingAddress"/>
+ SELECT person.NAME AS {person.name},
+ person.AGE AS {person.age},
+ person.SEX AS {person.sex},
+ adddress.STREET AS {address.street},
+ adddress.CITY AS {address.city},
+ adddress.STATE AS {address.state},
+ adddress.ZIP AS {address.zip}
+ FROM PERSON person
+ JOIN ADDRESS adddress
+ ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+ WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+ <para>A named SQL query may return a scalar value. You must declare the
+ column alias and Hibernate type using the
+ <literal><return-scalar></literal> element:</para>
+
+ <programlisting><![CDATA[<sql-query name="mySqlQuery">
+ <return-scalar column="name" type="string"/>
+ <return-scalar column="age" type="long"/>
+ SELECT p.NAME AS name,
+ p.AGE AS age,
+ FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
+</sql-query>]]></programlisting>
+
+ <para>You can externalize the resultset mapping informations in a
+ <literal><resultset></literal> element to either reuse them accross
+ several named queries or through the
+ <literal>setResultSetMapping()</literal> API.</para>
+
+ <programlisting><![CDATA[<resultset name="personAddress">
+ <return alias="person" class="eg.Person"/>
+ <return-join alias="address" property="person.mailingAddress"/>
+</resultset>
+
+<sql-query name="personsWith" resultset-ref="personAddress">
+ SELECT person.NAME AS {person.name},
+ person.AGE AS {person.age},
+ person.SEX AS {person.sex},
+ adddress.STREET AS {address.street},
+ adddress.CITY AS {address.city},
+ adddress.STATE AS {address.state},
+ adddress.ZIP AS {address.zip}
+ FROM PERSON person
+ JOIN ADDRESS adddress
+ ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+ WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+ <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">
+ <title>Using return-property to explicitly specify column/alias
+ names</title>
+
+ <para>With <literal><return-property></literal> you can explicitly
+ tell Hibernate what column aliases to use, instead of using the
+ <literal>{}</literal>-syntax to let Hibernate inject its own
+ aliases.</para>
+
+ <programlisting><![CDATA[<sql-query name="mySqlQuery">
+ <return alias="person" class="eg.Person">
+ <return-property name="name" column="myName"/>
+ <return-property name="age" column="myAge"/>
+ <return-property name="sex" column="mySex"/>
+ </return>
+ SELECT person.NAME AS myName,
+ person.AGE AS myAge,
+ person.SEX AS mySex,
+ FROM PERSON person WHERE person.NAME LIKE :name
+</sql-query>
+]]></programlisting>
+
+ <para><literal><return-property></literal> also works with
+ multiple columns. This solves a limitation with the
+ <literal>{}</literal>-syntax which can not allow fine grained control of
+ multi-column properties.</para>
+
+ <programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
+ <return alias="emp" class="Employment">
+ <return-property name="salary">
+ <return-column name="VALUE"/>
+ <return-column name="CURRENCY"/>
+ </return-property>
+ <return-property name="endDate" column="myEndDate"/>
+ </return>
+ SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
+ STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+ REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
+ FROM EMPLOYMENT
+ WHERE EMPLOYER = :id AND ENDDATE IS NULL
+ ORDER BY STARTDATE ASC
+</sql-query>]]></programlisting>
+
+ <para>Notice that in this example we used
+ <literal><return-property></literal> in combination with the
+ <literal>{}</literal>-syntax for injection. Allowing users to choose how
+ they want to refer column and properties.</para>
+
+ <para>If your mapping has a discriminator you must use
+ <literal><return-discriminator></literal> to specify the
+ discriminator column.</para>
+ </sect2>
+
+ <sect2 id="sp_query" revision="1">
+ <title>Using stored procedures for querying</title>
+
+ <para>Hibernate 3 introduces support for queries via stored procedures
+ and functions. Most of the following documentation is equivalent for
+ both. The stored procedure/function must return a resultset as the first
+ out-parameter to be able to work with Hibernate. An example of such a
+ stored function in Oracle 9 and higher is as follows:</para>
+
+ <programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
+ RETURN SYS_REFCURSOR
+AS
+ st_cursor SYS_REFCURSOR;
+BEGIN
+ OPEN st_cursor FOR
+ SELECT EMPLOYEE, EMPLOYER,
+ STARTDATE, ENDDATE,
+ REGIONCODE, EID, VALUE, CURRENCY
+ FROM EMPLOYMENT;
+ RETURN st_cursor;
+ END;]]></programlisting>
+
+ <para>To use this query in Hibernate you need to map it via a named
+ query.</para>
+
+ <programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
+ <return alias="emp" class="Employment">
+ <return-property name="employee" column="EMPLOYEE"/>
+ <return-property name="employer" column="EMPLOYER"/>
+ <return-property name="startDate" column="STARTDATE"/>
+ <return-property name="endDate" column="ENDDATE"/>
+ <return-property name="regionCode" column="REGIONCODE"/>
+ <return-property name="id" column="EID"/>
+ <return-property name="salary">
+ <return-column name="VALUE"/>
+ <return-column name="CURRENCY"/>
+ </return-property>
+ </return>
+ { ? = call selectAllEmployments() }
+</sql-query>]]></programlisting>
+
+ <para>Notice stored procedures currently only return scalars and
+ entities. <literal><return-join></literal> and
+ <literal><load-collection></literal> are not supported.</para>
+
+ <sect3 id="querysql-limits-storedprocedures" revision="1">
+ <title>Rules/limitations for using stored procedures</title>
+
+ <para>To use stored procedures with Hibernate the procedures/functions
+ have to follow some rules. If they do not follow those rules they are
+ not usable with Hibernate. If you still want to use these procedures
+ you have to execute them via <literal>session.connection()</literal>.
+ The rules are different for each database, since database vendors have
+ different stored procedure semantics/syntax.</para>
+
+ <para>Stored procedure queries can't be paged with
+ <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>For Oracle the following rules apply:</para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>A function must return a result set. The first parameter of
+ a procedure must be an <literal>OUT</literal> that returns a
+ result set. This is done by using a
+ <literal>SYS_REFCURSOR</literal> type in Oracle 9 or 10. In Oracle
+ you need to define a <literal>REF CURSOR</literal> type, see
+ Oracle literature.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>For Sybase or MS SQL server the following rules apply:</para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>The procedure must return a result set. Note that since
+ these servers can/will return multiple result sets and update
+ counts, Hibernate will iterate the results and take the first
+ result that is a result set as its return value. Everything else
+ will be discarded.</para>
+ </listitem>
+
+ <listitem>
+ <para>If you can enable <literal>SET NOCOUNT ON</literal> in your
+ procedure it will probably be more efficient, but this is not a
+ requirement.</para>
+ </listitem>
+ </itemizedlist>
+ </sect3>
+ </sect2>
+ </sect1>
+
+ <sect1 id="querysql-cud">
+ <title>Custom SQL for create, update and delete</title>
+
+ <para>Hibernate3 can use custom SQL statements for create, update, and
+ delete operations. The class and collection persisters in Hibernate
+ already contain a set of configuration time generated strings (insertsql,
+ deletesql, updatesql etc.). The mapping tags
+ <literal><sql-insert></literal>,
+ <literal><sql-delete></literal>, and
+ <literal><sql-update></literal> override these strings:</para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <property name="name" not-null="true"/>
+ <sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
+ <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
+ <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
+</class>]]></programlisting>
+
+ <para>The SQL is directly executed in your database, so you are free to
+ use any dialect you like. This will of course reduce the portability of
+ your mapping if you use database specific SQL.</para>
+
+ <para>Stored procedures are supported if the <literal>callable</literal>
+ attribute is set:</para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <property name="name" not-null="true"/>
+ <sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
+ <sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
+ <sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
+</class>]]></programlisting>
+
+ <para>The order of the positional parameters are currently vital, as they
+ must be in the same sequence as Hibernate expects them.</para>
+
+ <para>You can see the expected order by enabling debug logging for the
+ <literal>org.hibernate.persister.entity</literal> level. With this level
+ enabled Hibernate will print out the static SQL that is used to create,
+ update, delete etc. entities. (To see the expected sequence, remember to
+ not include your custom SQL in the mapping files as that will override the
+ Hibernate generated static sql.)</para>
+
+ <para>The stored procedures are in most cases (read: better do it than
+ not) required to return the number of rows inserted/updated/deleted, as
+ Hibernate has some runtime checks for the success of the statement.
+ Hibernate always registers the first statement parameter as a numeric
+ output parameter for the CUD operations:</para>
+
+ <programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
+ RETURN NUMBER IS
+BEGIN
+
+ update PERSON
+ set
+ NAME = uname,
+ where
+ ID = uid;
+
+ return SQL%ROWCOUNT;
+
+END updatePerson;]]></programlisting>
+ </sect1>
+
+ <sect1 id="querysql-load">
+ <title>Custom SQL for loading</title>
+
+ <para>You may also declare your own SQL (or HQL) queries for entity
+ loading:</para>
+
+ <programlisting><![CDATA[<sql-query name="person">
+ <return alias="pers" class="Person" lock-mode="upgrade"/>
+ SELECT NAME AS {pers.name}, ID AS {pers.id}
+ FROM PERSON
+ WHERE ID=?
+ FOR UPDATE
+</sql-query>]]></programlisting>
+
+ <para>This is just a named query declaration, as discussed earlier. You
+ may reference this named query in a class mapping:</para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <property name="name" not-null="true"/>
+ <loader query-ref="person"/>
+</class>]]></programlisting>
+
+ <para>This even works with stored procedures.</para>
+
+ <para>You may even define a query for collection loading:</para>
+
+ <programlisting><![CDATA[<set name="employments" inverse="true">
+ <key/>
+ <one-to-many class="Employment"/>
+ <loader query-ref="employments"/>
+</set>]]></programlisting>
+
+ <programlisting><![CDATA[<sql-query name="employments">
+ <load-collection alias="emp" role="Person.employments"/>
+ SELECT {emp.*}
+ FROM EMPLOYMENT emp
+ WHERE EMPLOYER = :id
+ ORDER BY STARTDATE ASC, EMPLOYEE ASC
+</sql-query>]]></programlisting>
+
+ <para>You could even define an entity loader that loads a collection by
+ join fetching:</para>
+
+ <programlisting><![CDATA[<sql-query name="person">
+ <return alias="pers" class="Person"/>
+ <return-join alias="emp" property="pers.employments"/>
+ SELECT NAME AS {pers.*}, {emp.*}
+ FROM PERSON pers
+ LEFT OUTER JOIN EMPLOYMENT emp
+ ON pers.ID = emp.PERSON_ID
+ WHERE ID=?
+</sql-query>]]></programlisting>
+ </sect1>
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/session_api.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/session_api.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/session_api.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,1242 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="objectstate">
+ <title>Working with objects</title>
+
+ <para>
+ Hibernate is a full object/relational mapping solution that not only shields
+ the developer from the details of the underlying database management
+ system, but also offers <emphasis>state management</emphasis> of objects. This is,
+ contrary to the management of SQL <literal>statements</literal> in common JDBC/SQL
+ persistence layers, a very natural object-oriented view of persistence in Java
+ applications.
+ </para>
+
+ <para>
+ In other words, Hibernate application developers should always think about the
+ <emphasis>state</emphasis> of their objects, and not necessarily about the
+ execution of SQL statements. This part is taken care of by Hibernate and is only
+ relevant for the application developer when tuning the performance of the system.
+ </para>
+
+ <sect1 id="objectstate-overview">
+ <title>Hibernate object states</title>
+
+ <para>
+ Hibernate defines and supports the following object states:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Transient</emphasis> - an object is transient if it has just
+ been instantiated using the <literal>new</literal> operator, and it
+ is not associated with a Hibernate <literal>Session</literal>. It has no
+ persistent representation in the database and no identifier value has been
+ assigned. Transient instances will be destroyed by the garbage collector if
+ the application doesn't hold a reference anymore. Use the Hibernate
+ <literal>Session</literal> to make an object persistent (and let Hibernate
+ take care of the SQL statements that need to be executed for this transition).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Persistent</emphasis> - a persistent instance has a representation
+ in the database and an identifier value. It might just have been saved or loaded,
+ however, it is by definition in the scope of a <literal>Session</literal>.
+ Hibernate will detect any changes made to an object in persistent state and
+ synchronize the state with the database when the unit of work completes.
+ Developers don't execute manual <literal>UPDATE</literal> statements, or
+ <literal>DELETE</literal> statements when an object should be made transient.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Detached</emphasis> - a detached instance is an object that has been
+ persistent, but its <literal>Session</literal> has been closed. The reference
+ to the object is still valid, of course, and the detached instance might even
+ be modified in this state. A detached instance can be reattached to a new
+ <literal>Session</literal> at a later point in time, making it (and all the
+ modifications) persistent again. This feature enables a programming model for
+ long running units of work that require user think-time. We call them
+ <emphasis>application transactions</emphasis>, i.e. a unit of work from the
+ point of view of the user.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ We'll now discuss the states and state transitions (and the Hibernate methods that
+ trigger a transition) in more detail.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-makingpersistent" revision="1">
+ <title>Making objects persistent</title>
+
+ <para>
+ Newly instantiated instances of a a persistent class are considered
+ <emphasis>transient</emphasis> by Hibernate. We can make a transient
+ instance <emphasis>persistent</emphasis> by associating it with a
+ session:
+ </para>
+
+ <programlisting><![CDATA[DomesticCat fritz = new DomesticCat();
+fritz.setColor(Color.GINGER);
+fritz.setSex('M');
+fritz.setName("Fritz");
+Long generatedId = (Long) sess.save(fritz);]]></programlisting>
+
+ <para>
+ If <literal>Cat</literal> has a generated identifier, the identifier is
+ generated and assigned to the <literal>cat</literal> when <literal>save()</literal>
+ is called. If <literal>Cat</literal> has an <literal>assigned</literal>
+ identifier, or a composite key, the identifier should be assigned to
+ the <literal>cat</literal> instance before calling <literal>save()</literal>.
+ You may also use <literal>persist()</literal> instead of <literal>save()</literal>,
+ with the semantics defined in the EJB3 early draft.
+ </para>
+
+ <para>
+ Alternatively, you may assign the identifier using an overloaded version
+ of <literal>save()</literal>.
+ </para>
+
+<programlisting><![CDATA[DomesticCat pk = new DomesticCat();
+pk.setColor(Color.TABBY);
+pk.setSex('F');
+pk.setName("PK");
+pk.setKittens( new HashSet() );
+pk.addKitten(fritz);
+sess.save( pk, new Long(1234) );]]></programlisting>
+
+ <para>
+ If the object you make persistent has associated objects (e.g. the
+ <literal>kittens</literal> collection in the previous example),
+ these objects may be made persistent in any order you like unless you
+ have a <literal>NOT NULL</literal> constraint upon a foreign key column.
+ There is never a risk of violating foreign key constraints. However, you
+ might violate a <literal>NOT NULL</literal> constraint if you
+ <literal>save()</literal> the objects in the wrong order.
+ </para>
+
+ <para>
+ Usually you don't bother with this detail, as you'll very likely use Hibernate's
+ <emphasis>transitive persistence</emphasis> feature to save the associated
+ objects automatically. Then, even <literal>NOT NULL</literal>
+ constraint violations don't occur - Hibernate will take care of everything.
+ Transitive persistence is discussed later in this chapter.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-loading">
+ <title>Loading an object</title>
+
+ <para>
+ The <literal>load()</literal> methods of <literal>Session</literal> gives you
+ a way to retrieve a persistent instance if you already know its identifier.
+ <literal>load()</literal> takes a class object and will load the state into
+ a newly instantiated instance of that class, in persistent state.
+ </para>
+
+ <programlisting><![CDATA[Cat fritz = (Cat) sess.load(Cat.class, generatedId);]]></programlisting>
+
+<programlisting><![CDATA[// you need to wrap primitive identifiers
+long id = 1234;
+DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id) );]]></programlisting>
+
+ <para>
+ Alternatively, you can load state into a given instance:
+ </para>
+
+<programlisting><![CDATA[Cat cat = new DomesticCat();
+// load pk's state into cat
+sess.load( cat, new Long(pkId) );
+Set kittens = cat.getKittens();]]></programlisting>
+
+ <para>
+ Note that <literal>load()</literal> will throw an unrecoverable exception if
+ there is no matching database row. If the class is mapped with a proxy,
+ <literal>load()</literal> just returns an uninitialized proxy and does not
+ actually hit the database until you invoke a method of the proxy. This
+ behaviour is very useful if you wish to create an association to an object
+ without actually loading it from the database. It also allows multiple
+ instances to be loaded as a batch if <literal>batch-size</literal> is
+ defined for the class mapping.
+ </para>
+
+ <para>
+ If you are not certain that a matching row exists, you should use the
+ <literal>get()</literal> method, which hits the database immediately and
+ returns null if there is no matching row.
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id);
+if (cat==null) {
+ cat = new Cat();
+ sess.save(cat, id);
+}
+return cat;]]></programlisting>
+
+ <para>
+ You may even load an object using an SQL <literal>SELECT ... FOR UPDATE</literal>,
+ using a <literal>LockMode</literal>. See the API documentation for more information.
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);]]></programlisting>
+
+ <para>
+ Note that any associated instances or contained collections are
+ <emphasis>not</emphasis> selected <literal>FOR UPDATE</literal>, unless you decide
+ to specify <literal>lock</literal> or <literal>all</literal> as a
+ cascade style for the association.
+ </para>
+
+ <para>
+ It is possible to re-load an object and all its collections at any time, using the
+ <literal>refresh()</literal> method. This is useful when database triggers are used to
+ initialize some of the properties of the object.
+ </para>
+
+ <programlisting><![CDATA[sess.save(cat);
+sess.flush(); //force the SQL INSERT
+sess.refresh(cat); //re-read the state (after the trigger executes)]]></programlisting>
+
+ <para>
+ An important question usually appears at this point: How much does Hibernate load
+ from the database and how many SQL <literal>SELECT</literal>s will it use? This
+ depends on the <emphasis>fetching strategy</emphasis> and is explained in
+ <xref linkend="performance-fetching"/>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-querying" revision="1">
+ <title>Querying</title>
+
+ <para>
+ If you don't know the identifiers of the objects you are looking for,
+ you need a query. Hibernate supports an easy-to-use but powerful object
+ oriented query language (HQL). For programmatic query creation, Hibernate
+ supports a sophisticated Criteria and Example query feature (QBC and QBE).
+ You may also express your query in the native SQL of your database, with
+ optional support from Hibernate for result set conversion into objects.
+ </para>
+
+ <sect2 id="objectstate-querying-executing" revision="1">
+ <title>Executing queries</title>
+
+ <para>
+ HQL and native SQL queries are represented with an instance of <literal>org.hibernate.Query</literal>.
+ This interface offers methods for parameter binding, result set handling, and for the execution
+ of the actual query. You always obtain a <literal>Query</literal> using the current
+ <literal>Session</literal>:
+ </para>
+
+ <programlisting><![CDATA[List cats = session.createQuery(
+ "from Cat as cat where cat.birthdate < ?")
+ .setDate(0, date)
+ .list();
+
+List mothers = session.createQuery(
+ "select mother from Cat as cat join cat.mother as mother where cat.name = ?")
+ .setString(0, name)
+ .list();
+
+List kittens = session.createQuery(
+ "from Cat as cat where cat.mother = ?")
+ .setEntity(0, pk)
+ .list();
+
+Cat mother = (Cat) session.createQuery(
+ "select cat.mother from Cat as cat where cat = ?")
+ .setEntity(0, izi)
+ .uniqueResult();]]
+
+Query mothersWithKittens = (Cat) session.createQuery(
+ "select mother from Cat as mother left join fetch mother.kittens");
+Set uniqueMothers = new HashSet(mothersWithKittens.list());]]></programlisting>
+
+ <para>
+ A query is usually executed by invoking <literal>list()</literal>, the
+ result of the query will be loaded completely into a collection in memory.
+ Entity instances retrieved by a query are in persistent state. The
+ <literal>uniqueResult()</literal> method offers a shortcut if you
+ know your query will only return a single object. Note that queries that
+ make use of eager fetching of collections usually return duplicates of
+ the root objects (but with their collections initialized). You can filter
+ these duplicates simply through a <literal>Set</literal>.
+ </para>
+
+ <sect3 id="objectstate-querying-executing-iterate">
+ <title>Iterating results</title>
+
+ <para>
+ Occasionally, you might be able to achieve better performance by
+ executing the query using the <literal>iterate()</literal> method.
+ This will only usually be the case if you expect that the actual
+ entity instances returned by the query will already be in the session
+ or second-level cache. If they are not already cached,
+ <literal>iterate()</literal> will be slower than <literal>list()</literal>
+ and might require many database hits for a simple query, usually
+ <emphasis>1</emphasis> for the initial select which only returns identifiers,
+ and <emphasis>n</emphasis> additional selects to initialize the actual instances.
+ </para>
+
+ <programlisting><![CDATA[// fetch ids
+Iterator iter = sess.createQuery("from eg.Qux q order by q.likeliness").iterate();
+while ( iter.hasNext() ) {
+ Qux qux = (Qux) iter.next(); // fetch the object
+ // something we couldnt express in the query
+ if ( qux.calculateComplicatedAlgorithm() ) {
+ // delete the current instance
+ iter.remove();
+ // dont need to process the rest
+ break;
+ }
+}]]></programlisting>
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-tuples">
+ <title>Queries that return tuples</title>
+
+ <para>
+ Hibernate queries sometimes return tuples of objects, in which case each tuple
+ is returned as an array:
+ </para>
+
+ <programlisting><![CDATA[Iterator kittensAndMothers = sess.createQuery(
+ "select kitten, mother from Cat kitten join kitten.mother mother")
+ .list()
+ .iterator();
+
+while ( kittensAndMothers.hasNext() ) {
+ Object[] tuple = (Object[]) kittensAndMothers.next();
+ Cat kitten = tuple[0];
+ Cat mother = tuple[1];
+ ....
+}]]></programlisting>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-scalar" revision="1">
+ <title>Scalar results</title>
+
+ <para>
+ Queries may specify a property of a class in the <literal>select</literal> clause.
+ They may even call SQL aggregate functions. Properties or aggregates are considered
+ "scalar" results (and not entities in persistent state).
+ </para>
+
+ <programlisting><![CDATA[Iterator results = sess.createQuery(
+ "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
+ "group by cat.color")
+ .list()
+ .iterator();
+
+while ( results.hasNext() ) {
+ Object[] row = (Object[]) results.next();
+ Color type = (Color) row[0];
+ Date oldest = (Date) row[1];
+ Integer count = (Integer) row[2];
+ .....
+}]]></programlisting>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-parameters">
+ <title>Bind parameters</title>
+
+ <para>
+ Methods on <literal>Query</literal> are provided for binding values to
+ named parameters or JDBC-style <literal>?</literal> parameters.
+ <emphasis>Contrary to JDBC, Hibernate numbers parameters from zero.</emphasis>
+ Named parameters are identifiers of the form <literal>:name</literal> in
+ the query string. The advantages of named parameters are:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ named parameters are insensitive to the order they occur in the
+ query string
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ they may occur multiple times in the same query
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ they are self-documenting
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <programlisting><![CDATA[//named parameter (preferred)
+Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
+q.setString("name", "Fritz");
+Iterator cats = q.iterate();]]></programlisting>
+
+ <programlisting><![CDATA[//positional parameter
+Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
+q.setString(0, "Izi");
+Iterator cats = q.iterate();]]></programlisting>
+
+ <programlisting><![CDATA[//named parameter list
+List names = new ArrayList();
+names.add("Izi");
+names.add("Fritz");
+Query q = sess.createQuery("from DomesticCat cat where cat.name in (:namesList)");
+q.setParameterList("namesList", names);
+List cats = q.list();]]></programlisting>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-pagination">
+ <title>Pagination</title>
+
+ <para>
+ If you need to specify bounds upon your result set (the maximum number of rows
+ you want to retrieve and / or the first row you want to retrieve) you should
+ use methods of the <literal>Query</literal> interface:
+ </para>
+
+ <programlisting><![CDATA[Query q = sess.createQuery("from DomesticCat cat");
+q.setFirstResult(20);
+q.setMaxResults(10);
+List cats = q.list();]]></programlisting>
+
+ <para>
+ Hibernate knows how to translate this limit query into the native
+ SQL of your DBMS.
+ </para>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-scrolling">
+ <title>Scrollable iteration</title>
+
+ <para>
+ If your JDBC driver supports scrollable <literal>ResultSet</literal>s, the
+ <literal>Query</literal> interface may be used to obtain a
+ <literal>ScrollableResults</literal> object, which allows flexible
+ navigation of the query results.
+ </para>
+
+ <programlisting><![CDATA[Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " +
+ "order by cat.name");
+ScrollableResults cats = q.scroll();
+if ( cats.first() ) {
+
+ // find the first name on each page of an alphabetical list of cats by name
+ firstNamesOfPages = new ArrayList();
+ do {
+ String name = cats.getString(0);
+ firstNamesOfPages.add(name);
+ }
+ while ( cats.scroll(PAGE_SIZE) );
+
+ // Now get the first page of cats
+ pageOfCats = new ArrayList();
+ cats.beforeFirst();
+ int i=0;
+ while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) );
+
+}
+cats.close()]]></programlisting>
+
+ <para>
+ Note that an open database connection (and cursor) is required for this
+ functionality, use <literal>setMaxResult()</literal>/<literal>setFirstResult()</literal>
+ if you need offline pagination functionality.
+ </para>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-named" revision="1">
+ <title>Externalizing named queries</title>
+
+ <para>
+ You may also define named queries in the mapping document. (Remember to use a
+ <literal>CDATA</literal> section if your query contains characters that could
+ be interpreted as markup.)
+ </para>
+
+ <programlisting><![CDATA[<query name="ByNameAndMaximumWeight"><![CDATA[
+ from eg.DomesticCat as cat
+ where cat.name = ?
+ and cat.weight > ?
+] ]></query>]]></programlisting>
+
+ <para>
+ Parameter binding and executing is done programatically:
+ </para>
+
+ <programlisting><![CDATA[Query q = sess.getNamedQuery("ByNameAndMaximumWeight");
+q.setString(0, name);
+q.setInt(1, minWeight);
+List cats = q.list();]]></programlisting>
+
+ <para>
+ Note that the actual program code is independent of the query language that
+ is used, you may also define native SQL queries in metadata, or migrate
+ existing queries to Hibernate by placing them in mapping files.
+ </para>
+
+ <para>
+ 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>
+
+ </sect2>
+
+ <sect2 id="objectstate-filtering" revision="1">
+ <title>Filtering collections</title>
+ <para>
+ A collection <emphasis>filter</emphasis> is a special type of query that may be applied to
+ a persistent collection or array. The query string may refer to <literal>this</literal>,
+ meaning the current collection element.
+ </para>
+
+ <programlisting><![CDATA[Collection blackKittens = session.createFilter(
+ pk.getKittens(),
+ "where this.color = ?")
+ .setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) )
+ .list()
+);]]></programlisting>
+
+ <para>
+ The returned collection is considered a bag, and it's a copy of the given
+ collection. The original collection is not modified (this is contrary to
+ the implication of the name "filter", but consistent with expected behavior).
+ </para>
+
+ <para>
+ Observe that filters do not require a <literal>from</literal> clause (though they may have
+ one if required). Filters are not limited to returning the collection elements themselves.
+ </para>
+
+ <programlisting><![CDATA[Collection blackKittenMates = session.createFilter(
+ pk.getKittens(),
+ "select this.mate where this.color = eg.Color.BLACK.intValue")
+ .list();]]></programlisting>
+
+ <para>
+ Even an empty filter query is useful, e.g. to load a subset of elements in a
+ huge collection:
+ </para>
+
+ <programlisting><![CDATA[Collection tenKittens = session.createFilter(
+ mother.getKittens(), "")
+ .setFirstResult(0).setMaxResults(10)
+ .list();]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="objecstate-querying-criteria" revision="1">
+ <title>Criteria queries</title>
+
+ <para>
+ HQL is extremely powerful but some developers prefer to build queries dynamically,
+ using an object-oriented API, rather than building query strings. Hibernate provides
+ an intuitive <literal>Criteria</literal> query API for these cases:
+ </para>
+
+ <programlisting><![CDATA[Criteria crit = session.createCriteria(Cat.class);
+crit.add( Expression.eq( "color", eg.Color.BLACK ) );
+crit.setMaxResults(10);
+List cats = crit.list();]]></programlisting>
+
+ <para>
+ The <literal>Criteria</literal> and the associated <literal>Example</literal>
+ API are discussed in more detail in <xref linkend="querycriteria"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="objectstate-querying-nativesql" revision="2">
+ <title>Queries in native SQL</title>
+
+ <para>
+ You may express a query in SQL, using <literal>createSQLQuery()</literal> and
+ let Hibernate take care of the mapping from result sets to objects. Note
+ that you may at any time call <literal>session.connection()</literal> and
+ use the JDBC <literal>Connection</literal> directly. If you chose to use the
+ Hibernate API, you must enclose SQL aliases in braces:
+ </para>
+
+ <programlisting><![CDATA[List cats = session.createSQLQuery(
+ "SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10",
+ "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",
+ "cat",
+ Cat.class
+).list()]]></programlisting>
+
+ <para>
+ SQL queries may contain named and positional parameters, just like Hibernate queries.
+ More information about native SQL queries in Hibernate can be found in
+ <xref linkend="querysql"/>.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="objectstate-modifying" revision="1">
+ <title>Modifying persistent objects</title>
+
+ <para>
+ <emphasis>Transactional persistent instances</emphasis> (ie. objects loaded, saved, created or
+ queried by the <literal>Session</literal>) may be manipulated by the application
+ and any changes to persistent state will be persisted when the <literal>Session</literal>
+ is <emphasis>flushed</emphasis> (discussed later in this chapter). There is no need
+ to call a particular method (like <literal>update()</literal>, which has a different
+ purpose) to make your modifications persistent. So the most straightforward way to update
+ the state of an object is to <literal>load()</literal> it,
+ and then manipulate it directly, while the <literal>Session</literal> is open:
+ </para>
+
+ <programlisting><![CDATA[DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );
+cat.setName("PK");
+sess.flush(); // changes to cat are automatically detected and persisted]]></programlisting>
+
+ <para>
+ Sometimes this programming model is inefficient since it would require both an SQL
+ <literal>SELECT</literal> (to load an object) and an SQL <literal>UPDATE</literal>
+ (to persist its updated state) in the same session. Therefore Hibernate offers an
+ alternate approach, using detached instances.
+ </para>
+
+ <para>
+ <emphasis>Note that Hibernate does not offer its own API for direct execution of
+ <literal>UPDATE</literal> or <literal>DELETE</literal> statements. Hibernate is a
+ <emphasis>state management</emphasis> service, you don't have to think in
+ <emphasis>statements</emphasis> to use it. JDBC is a perfect API for executing
+ SQL statements, you can get a JDBC <literal>Connection</literal> at any time
+ by calling <literal>session.connection()</literal>. Furthermore, the notion
+ of mass operations conflicts with object/relational mapping for online
+ transaction processing-oriented applications. Future versions of Hibernate
+ may however provide special mass operation functions. See <xref linkend="batch"/>
+ for some possible batch operation tricks.</emphasis>
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-detached" revision="2">
+ <title>Modifying detached objects</title>
+
+ <para>
+ Many applications need to retrieve an object in one transaction, send it to the
+ UI layer for manipulation, then save the changes in a new transaction.
+ Applications that use this kind of approach in a high-concurrency environment
+ usually use versioned data to ensure isolation for the "long" unit of work.
+ </para>
+
+ <para>
+ Hibernate supports this model by providing for reattachment of detached instances
+ using the <literal>Session.update()</literal> or <literal>Session.merge()</literal>
+ methods:
+ </para>
+
+ <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catId);
+Cat potentialMate = new Cat();
+firstSession.save(potentialMate);
+
+// in a higher layer of the application
+cat.setMate(potentialMate);
+
+// later, in a new session
+secondSession.update(cat); // update cat
+secondSession.update(mate); // update mate]]></programlisting>
+
+ <para>
+ If the <literal>Cat</literal> with identifier <literal>catId</literal> had already
+ been loaded by <literal>secondSession</literal> when the application tried to
+ reattach it, an exception would have been thrown.
+ </para>
+
+ <para>
+ Use <literal>update()</literal> if you are sure that the session does
+ not contain an already persistent instance with the same identifier, and
+ <literal>merge()</literal> if you want to merge your modifications at any time
+ without consideration of the state of the session. In other words, <literal>update()</literal>
+ is usually the first method you would call in a fresh session, ensuring that
+ reattachment of your detached instances is the first operation that is executed.
+ </para>
+
+ <para>
+ The application should individually <literal>update()</literal> detached instances
+ reachable from the given detached instance if and <emphasis>only</emphasis> if it wants
+ their state also updated. This can be automated of course, using <emphasis>transitive
+ persistence</emphasis>, see <xref linkend="objectstate-transitive"/>.
+ </para>
+
+ <para>
+ The <literal>lock()</literal> method also allows an application to reassociate
+ an object with a new session. However, the detached instance has to be unmodified!
+ </para>
+
+ <programlisting><![CDATA[//just reassociate:
+sess.lock(fritz, LockMode.NONE);
+//do a version check, then reassociate:
+sess.lock(izi, LockMode.READ);
+//do a version check, using SELECT ... FOR UPDATE, then reassociate:
+sess.lock(pk, LockMode.UPGRADE);]]></programlisting>
+
+ <para>
+ Note that <literal>lock()</literal> can be used with various
+ <literal>LockMode</literal>s, see the API documentation and the
+ chapter on transaction handling for more information. Reattachment is not
+ the only usecase for <literal>lock()</literal>.
+ </para>
+
+ <para>
+ Other models for long units of work are discussed in <xref linkend="transactions-optimistic"/>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-saveorupdate">
+ <title>Automatic state detection</title>
+
+ <para>
+ Hibernate users have requested a general purpose method that either saves a
+ transient instance by generating a new identifier or updates/reattaches
+ the detached instances associated with its current identifier.
+ The <literal>saveOrUpdate()</literal> method implements this functionality.
+ </para>
+
+ <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catID);
+
+// in a higher tier of the application
+Cat mate = new Cat();
+cat.setMate(mate);
+
+// later, in a new session
+secondSession.saveOrUpdate(cat); // update existing state (cat has a non-null id)
+secondSession.saveOrUpdate(mate); // save the new instance (mate has a null id)]]></programlisting>
+
+ <para>
+ The usage and semantics of <literal>saveOrUpdate()</literal> seems to be confusing
+ for new users. Firstly, so long as you are not trying to use instances from one session
+ in another new session, you should not need to use <literal>update()</literal>,
+ <literal>saveOrUpdate()</literal>, or <literal>merge()</literal>. Some whole
+ applications will never use either of these methods.
+ </para>
+
+ <para>
+ Usually <literal>update()</literal> or <literal>saveOrUpdate()</literal> are used in
+ the following scenario:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ the application loads an object in the first session
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ the object is passed up to the UI tier
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ some modifications are made to the object
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ the object is passed back down to the business logic tier
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ the application persists these modifications by calling
+ <literal>update()</literal> in a second session
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ <literal>saveOrUpdate()</literal> does the following:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ if the object is already persistent in this session, do nothing
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ if another object associated with the session has the same identifier,
+ throw an exception
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ if the object has no identifier property, <literal>save()</literal> it
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ if the object's identifier has the value assigned to a newly instantiated
+ object, <literal>save()</literal> it
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ if the object is versioned (by a <literal><version></literal> or
+ <literal><timestamp></literal>), and the version property value
+ is the same value assigned to a newly instantiated object,
+ <literal>save()</literal> it
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ otherwise <literal>update()</literal> the object
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ and <literal>merge()</literal> is very different:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ if there is a persistent instance with the same identifier currently
+ associated with the session, copy the state of the given object onto
+ the persistent instance
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ if there is no persistent instance currently associated with the session,
+ try to load it from the database, or create a new persistent instance
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ the persistent instance is returned
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ the given instance does not become associated with the session, it
+ remains detached
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect1>
+
+ <sect1 id="objectstate-deleting" revision="1">
+ <title>Deleting persistent objects</title>
+
+ <para>
+ <literal>Session.delete()</literal> will remove an object's state from the database.
+ Of course, your application might still hold a reference to a deleted object.
+ It's best to think of <literal>delete()</literal> as making a persistent instance
+ transient.
+ </para>
+
+ <programlisting><![CDATA[sess.delete(cat);]]></programlisting>
+
+ <para>
+ You may delete objects in any order you like, without risk of foreign key
+ constraint violations. It is still possible to violate a <literal>NOT
+ NULL</literal> constraint on a foreign key column by deleting objects in
+ the wrong order, e.g. if you delete the parent, but forget to delete the
+ children.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-replicating" revision="1">
+ <title>Replicating object between two different datastores</title>
+
+ <para>
+ It is occasionally useful to be able to take a graph of persistent instances
+ and make them persistent in a different datastore, without regenerating identifier
+ values.
+ </para>
+
+ <programlisting><![CDATA[//retrieve a cat from one database
+Session session1 = factory1.openSession();
+Transaction tx1 = session1.beginTransaction();
+Cat cat = session1.get(Cat.class, catId);
+tx1.commit();
+session1.close();
+
+//reconcile with a second database
+Session session2 = factory2.openSession();
+Transaction tx2 = session2.beginTransaction();
+session2.replicate(cat, ReplicationMode.LATEST_VERSION);
+tx2.commit();
+session2.close();]]></programlisting>
+
+ <para>
+ The <literal>ReplicationMode</literal> determines how <literal>replicate()</literal>
+ will deal with conflicts with existing rows in the database.
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>ReplicationMode.IGNORE</literal> - ignore the object when there is
+ an existing database row with the same identifier
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ReplicationMode.OVERWRITE</literal> - overwrite any existing database
+ row with the same identifier
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ReplicationMode.EXCEPTION</literal> - throw an exception if there is
+ an existing database row with the same identifier
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ReplicationMode.LATEST_VERSION</literal> - overwrite the row if its
+ version number is earlier than the version number of the object, or ignore
+ the object otherwise
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Usecases for this feature include reconciling data entered into different database
+ instances, upgrading system configuration information during product upgrades,
+ rolling back changes made during non-ACID transactions and more.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-flushing">
+ <title>Flushing the Session</title>
+
+ <para>
+ From time to time the <literal>Session</literal> will execute the SQL statements
+ needed to synchronize the JDBC connection's state with the state of objects held in
+ memory. This process, <emphasis>flush</emphasis>, occurs by default at the following
+ points
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ before some query executions
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ from <literal>org.hibernate.Transaction.commit()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ from <literal>Session.flush()</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The SQL statements are issued in the following order
+ </para>
+
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ all entity insertions, in the same order the corresponding objects
+ were saved using <literal>Session.save()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ all entity updates
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ all collection deletions
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ all collection element deletions, updates and insertions
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ all collection insertions
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ all entity deletions, in the same order the corresponding objects
+ were deleted using <literal>Session.delete()</literal>
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ (An exception is that objects using <literal>native</literal> ID generation are
+ inserted when they are saved.)
+ </para>
+
+ <para>
+ Except when you explicity <literal>flush()</literal>, there are absolutely no
+ guarantees about <emphasis>when</emphasis> the <literal>Session</literal> executes
+ the JDBC calls, only the <emphasis>order</emphasis> in which they are executed.
+ However, Hibernate does guarantee that the <literal>Query.list(..)</literal>
+ will never return stale data; nor will they return the wrong data.
+ </para>
+
+ <para>
+ It is possible to change the default behavior so that flush occurs less frequently.
+ The <literal>FlushMode</literal> class defines three different modes: only flush
+ at commit time (and only when the Hibernate <literal>Transaction</literal> API
+ is used), flush automatically using the explained routine, or never flush unless
+ <literal>flush()</literal> is called explicitly. The last mode is useful for long running
+ units of work, where a <literal>Session</literal> is kept open and disconnected for
+ a long time (see <xref linkend="transactions-optimistic-longsession"/>).
+ </para>
+
+ <programlisting><![CDATA[sess = sf.openSession();
+Transaction tx = sess.beginTransaction();
+sess.setFlushMode(FlushMode.COMMIT); // allow queries to return stale state
+
+Cat izi = (Cat) sess.load(Cat.class, id);
+izi.setName(iznizi);
+
+// might return stale data
+sess.find("from Cat as cat left outer join cat.kittens kitten");
+
+// change to izi is not flushed!
+...
+tx.commit(); // flush occurs
+sess.close();]]></programlisting>
+
+ <para>
+ During flush, an exception might occur (e.g. if a DML operation violates a constraint).
+ Since handling exceptions involves some understanding of Hibernate's transactional
+ behavior, we discuss it in <xref linkend="transactions"/>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-transitive" revision="1">
+ <title>Transitive persistence</title>
+
+ <para>
+ It is quite cumbersome to save, delete, or reattach individual objects,
+ especially if you deal with a graph of associated objects. A common case is
+ a parent/child relationship. Consider the following example:
+ </para>
+
+ <para>
+ If the children in a parent/child relationship would be value typed (e.g. a collection
+ of addresses or strings), their lifecycle would depend on the parent and no
+ further action would be required for convenient "cascading" of state changes.
+ When the parent is saved, the value-typed child objects are saved as
+ well, when the parent is deleted, the children will be deleted, etc. This
+ even works for operations such as the removal of a child from the collection;
+ Hibernate will detect this and, since value-typed objects can't have shared
+ references, delete the child from the database.
+ </para>
+
+ <para>
+ Now consider the same scenario with parent and child objects being entities,
+ not value-types (e.g. categories and items, or parent and child cats). Entities
+ have their own lifecycle, support shared references (so removing an entity from
+ the collection does not mean it can be deleted), and there is by default no
+ cascading of state from one entity to any other associated entities. Hibernate
+ does not implement <emphasis>persistence by reachability</emphasis> by default.
+ </para>
+
+ <para>
+ For each basic operation of the Hibernate session - including <literal>persist(), merge(),
+ saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate()</literal> - there is a
+ corresponding cascade style. Respectively, the cascade styles are named <literal>create,
+ merge, save-update, delete, lock, refresh, evict, replicate</literal>. If you want an
+ operation to be cascaded along an association, you must indicate that in the mapping
+ document. For example:
+ </para>
+
+ <programlisting><![CDATA[<one-to-one name="person" cascade="persist"/>]]></programlisting>
+
+ <para>
+ Cascade styles my be combined:
+ </para>
+
+ <programlisting><![CDATA[<one-to-one name="person" cascade="persist,delete,lock"/>]]></programlisting>
+
+ <para>
+ You may even use <literal>cascade="all"</literal> to specify that <emphasis>all</emphasis>
+ operations should be cascaded along the association. The default <literal>cascade="none"</literal>
+ specifies that no operations are to be cascaded.
+ </para>
+
+ <para>
+ A special cascade style, <literal>delete-orphan</literal>, applies only to one-to-many
+ associations, and indicates that the <literal>delete()</literal> operation should
+ be applied to any child object that is removed from the association.
+ </para>
+
+
+ <para>
+ Recommendations:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ It doesn't usually make sense to enable cascade on a <literal><many-to-one></literal>
+ or <literal><many-to-many></literal> association. Cascade is often useful for
+ <literal><one-to-one></literal> and <literal><one-to-many></literal>
+ associations.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If the child object's lifespan is bounded by the lifespan of the of the parent
+ object make it a <emphasis>lifecycle object</emphasis> by specifying
+ <literal>cascade="all,delete-orphan"</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Otherwise, you might not need cascade at all. But if you think that you will often be
+ working with the parent and children together in the same transaction, and you want to save
+ yourself some typing, consider using <literal>cascade="persist,merge,save-update"</literal>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Mapping an association (either a single valued association, or a collection) with
+ <literal>cascade="all"</literal> marks the association as a
+ <emphasis>parent/child</emphasis> style relationship where save/update/delete of the
+ parent results in save/update/delete of the child or children.
+ </para>
+ <para>
+ Futhermore, a mere reference to a child from a persistent parent will result in
+ save/update of the child. This metaphor is incomplete, however. A child which becomes
+ unreferenced by its parent is <emphasis>not</emphasis> automatically deleted, except
+ in the case of a <literal><one-to-many></literal> association mapped with
+ <literal>cascade="delete-orphan"</literal>. The precise semantics of cascading
+ operations for a parent/child relationship are as follows:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ If a parent is passed to <literal>persist()</literal>, all children are passed to
+ <literal>persist()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If a parent is passed to <literal>merge()</literal>, all children are passed to
+ <literal>merge()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If a parent is passed to <literal>save()</literal>, <literal>update()</literal> or
+ <literal>saveOrUpdate()</literal>, all children are passed to <literal>saveOrUpdate()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If a transient or detached child becomes referenced by a persistent parent,
+ it is passed to <literal>saveOrUpdate()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If a parent is deleted, all children are passed to <literal>delete()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If a child is dereferenced by a persistent parent, <emphasis>nothing
+ special happens</emphasis> - the application should explicitly delete
+ the child if necessary - unless <literal>cascade="delete-orphan"</literal>,
+ in which case the "orphaned" child is deleted.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Finally, note that cascading of operations can be applied to an object graph at
+ <emphasis>call time</emphasis> or at <emphasis>flush time</emphasis>. All operations,
+ if enabled, are cascaded to associated entities reachable when the operation is
+ executed. However, <literal>save-upate</literal> and <literal>delete-orphan</literal>
+ are transitive for all associated entities reachable during flush of the
+ <literal>Session</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-metadata">
+ <title>Using metadata</title>
+
+ <para>
+ Hibernate requires a very rich meta-level model of all entity and value types. From time
+ to time, this model is very useful to the application itself. For example, the application
+ might use Hibernate's metadata to implement a "smart" deep-copy algorithm that understands
+ which objects should be copied (eg. mutable value types) and which should not (eg.
+ immutable value types and, possibly, associated entities).
+ </para>
+ <para>
+ Hibernate exposes metadata via the <literal>ClassMetadata</literal> and
+ <literal>CollectionMetadata</literal> interfaces and the <literal>Type</literal>
+ hierarchy. Instances of the metadata interfaces may be obtained from the
+ <literal>SessionFactory</literal>.
+ </para>
+
+ <programlisting><![CDATA[Cat fritz = ......;
+ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class);
+
+Object[] propertyValues = catMeta.getPropertyValues(fritz);
+String[] propertyNames = catMeta.getPropertyNames();
+Type[] propertyTypes = catMeta.getPropertyTypes();
+
+// get a Map of all properties which are not collections or associations
+Map namedValues = new HashMap();
+for ( int i=0; i<propertyNames.length; i++ ) {
+ if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType() ) {
+ namedValues.put( propertyNames[i], propertyValues[i] );
+ }
+}]]></programlisting>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/toolset_guide.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/toolset_guide.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/toolset_guide.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,606 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="toolsetguide" revision="2">
+ <title>Toolset Guide</title>
+
+ <para>
+ Roundtrip engineering with Hibernate is possible using a set of Eclipse plugins,
+ commandline tools, as well as Ant tasks.
+ </para>
+
+ <para>
+ The <emphasis>Hibernate Tools</emphasis> currently include plugins for the Eclipse
+ IDE as well as Ant tasks for reverse engineering of existing databases:
+ </para>
+
+ <itemizedlist>
+ <listitem><para>
+ <emphasis>Mapping Editor:</emphasis> An editor for Hibernate XML mapping files,
+ supporting auto-completion and syntax highlighting. It also supports semantic
+ auto-completion for class names and property/field names, making it much more versatile than a normal XML editor.
+ </para></listitem>
+ <listitem><para>
+ <emphasis>Console:</emphasis> The console is a new view in Eclipse. In addition to
+ a tree overview of your console configurations, you also get an interactive view
+ of your persistent classes and their relationships. The console allows you to
+ execute HQL queries against your database and browse the result directly in
+ Eclipse.
+ </para></listitem>
+ <listitem><para>
+ <emphasis>Development Wizards:</emphasis> Several wizards are provided with the
+ Hibernate Eclipse tools; you can use a wizard to quickly generate Hibernate configuration
+ (cfg.xml) files, or you may even completely reverse engineer an existing database schema
+ into POJO source files and Hibernate mapping files. The reverse engineering wizard
+ supports customizable templates.
+ </para></listitem>
+ <listitem><para>
+ <emphasis>Ant Tasks:</emphasis>
+ </para></listitem>
+
+ </itemizedlist>
+
+ <para>
+ Please refer to the <emphasis>Hibernate Tools</emphasis> package and it's documentation
+ for more information.
+ </para>
+
+ <para>
+ However, the Hibernate main package comes bundled with an integrated tool (it can even
+ be used from "inside" Hibernate on-the-fly): <emphasis>SchemaExport</emphasis> aka
+ <literal>hbm2ddl</literal>.
+ </para>
+
+ <sect1 id="toolsetguide-s1" revision="2">
+ <title>Automatic schema generation</title>
+
+ <para>
+ DDL may be generated from your mapping files by a Hibernate utility. The generated
+ schema includes referential integrity constraints (primary and foreign keys) for
+ entity and collection tables. Tables and sequences are also created for mapped
+ identifier generators.
+ </para>
+
+ <para>
+ You <emphasis>must</emphasis> specify a SQL <literal>Dialect</literal> via the
+ <literal>hibernate.dialect</literal> property when using this tool, as DDL
+ is highly vendor specific.
+ </para>
+
+ <para>
+ First, customize your mapping files to improve the generated schema.
+ </para>
+
+ <sect2 id="toolsetguide-s1-2" revision="3">
+ <title>Customizing the schema</title>
+
+ <para>
+ Many Hibernate mapping elements define optional attributes named <literal>length</literal>,
+ <literal>precision</literal> and <literal>scale</literal>. You may set the length, precision
+ and scale of a column with this attribute.
+
+ </para>
+
+ <programlisting><![CDATA[<property name="zip" length="5"/>]]></programlisting>
+ <programlisting><![CDATA[<property name="balance" precision="12" scale="2"/>]]></programlisting>
+
+ <para>
+ Some tags also accept a <literal>not-null</literal> attribute (for generating a
+ <literal>NOT NULL</literal> constraint on table columns) and a <literal>unique</literal>
+ attribute (for generating <literal>UNIQUE</literal> constraint on table columns).
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="bar" column="barId" not-null="true"/>]]></programlisting>
+
+ <programlisting><![CDATA[<element column="serialNumber" type="long" not-null="true" unique="true"/>]]></programlisting>
+
+ <para>
+ A <literal>unique-key</literal> attribute may be used to group columns in
+ a single unique key constraint. Currently, the specified value of the
+ <literal>unique-key</literal> attribute is <emphasis>not</emphasis> used
+ to name the constraint in the generated DDL, only to group the columns in
+ the mapping file.
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="org" column="orgId" unique-key="OrgEmployeeId"/>
+<property name="employeeId" unique-key="OrgEmployee"/>]]></programlisting>
+
+ <para>
+ An <literal>index</literal> attribute specifies the name of an index that
+ will be created using the mapped column or columns. Multiple columns may be
+ grouped into the same index, simply by specifying the same index name.
+ </para>
+
+ <programlisting><![CDATA[<property name="lastName" index="CustName"/>
+<property name="firstName" index="CustName"/>]]></programlisting>
+
+ <para>
+ A <literal>foreign-key</literal> attribute may be used to override the name
+ of any generated foreign key constraint.
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="bar" column="barId" foreign-key="FKFooBar"/>]]></programlisting>
+
+ <para>
+ Many mapping elements also accept a child <literal><column></literal> element.
+ This is particularly useful for mapping multi-column types:
+ </para>
+
+ <programlisting><![CDATA[<property name="name" type="my.customtypes.Name"/>
+ <column name="last" not-null="true" index="bar_idx" length="30"/>
+ <column name="first" not-null="true" index="bar_idx" length="20"/>
+ <column name="initial"/>
+</property>]]></programlisting>
+
+ <para>
+ The <literal>default</literal> attribute lets you specify a default value for
+ a column (you should assign the same value to the mapped property before
+ saving a new instance of the mapped class).
+ </para>
+
+ <programlisting><![CDATA[<property name="credits" type="integer" insert="false">
+ <column name="credits" default="10"/>
+</property>]]></programlisting>
+
+ <programlisting><![CDATA[<version name="version" type="integer" insert="false">
+ <column name="version" default="0"/>
+</property>]]></programlisting>
+
+ <para>
+ The <literal>sql-type</literal> attribute allows the user to override the default
+ mapping of a Hibernate type to SQL datatype.
+ </para>
+
+ <programlisting><![CDATA[<property name="balance" type="float">
+ <column name="balance" sql-type="decimal(13,3)"/>
+</property>]]></programlisting>
+
+ <para>
+ The <literal>check</literal> attribute allows you to specify a check constraint.
+ </para>
+
+ <programlisting><![CDATA[<property name="foo" type="integer">
+ <column name="foo" check="foo > 10"/>
+</property>]]></programlisting>
+
+ <programlisting><![CDATA[<class name="Foo" table="foos" check="bar < 100.0">
+ ...
+ <property name="bar" type="float"/>
+</class>]]></programlisting>
+
+
+ <table frame="topbot" id="schemattributes-summary" revision="2">
+ <title>Summary</title>
+ <tgroup cols="3">
+ <colspec colwidth="1*"/>
+ <colspec colwidth="1*"/>
+ <colspec colwidth="2.5*"/>
+ <thead>
+ <row>
+ <entry>Attribute</entry>
+ <entry>Values</entry>
+ <entry>Interpretation</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>length</literal></entry>
+ <entry>number</entry>
+ <entry>column length</entry>
+ </row>
+ <row>
+ <entry><literal>precision</literal></entry>
+ <entry>number</entry>
+ <entry>column decimal precision</entry>
+ </row>
+ <row>
+ <entry><literal>scale</literal></entry>
+ <entry>number</entry>
+ <entry>column decimal scale</entry>
+ </row>
+ <row>
+ <entry><literal>not-null</literal></entry>
+ <entry><literal>true|false</literal></entry>
+ <entry>specfies that the column should be non-nullable</entry>
+ </row>
+ <row>
+ <entry><literal>unique</literal></entry>
+ <entry><literal>true|false</literal></entry>
+ <entry>specifies that the column should have a unique constraint</entry>
+ </row>
+ <row>
+ <entry><literal>index</literal></entry>
+ <entry><literal>index_name</literal></entry>
+ <entry>specifies the name of a (multi-column) index</entry>
+ </row>
+ <row>
+ <entry><literal>unique-key</literal></entry>
+ <entry><literal>unique_key_name</literal></entry>
+ <entry>specifies the name of a multi-column unique constraint</entry>
+ </row>
+ <row>
+ <entry><literal>foreign-key</literal></entry>
+ <entry><literal>foreign_key_name</literal></entry>
+ <entry>
+ specifies the name of the foreign key constraint generated
+ for an association, for a <literal><one-to-one></literal>,
+ <literal><many-to-one></literal>, <literal><key></literal>,
+ or <literal><many-to-many></literal> mapping element. Note that
+ <literal>inverse="true"</literal> sides will not be considered
+ by <literal>SchemaExport</literal>.
+ </entry>
+ </row>
+ <row>
+ <entry><literal>sql-type</literal></entry>
+ <entry><literal>SQL column type</literal></entry>
+ <entry>
+ overrides the default column type (attribute of
+ <literal><column></literal> element only)
+ </entry>
+ </row>
+ <row>
+ <entry><literal>default</literal></entry>
+ <entry>SQL expression</entry>
+ <entry>
+ specify a default value for the column
+ </entry>
+ </row>
+ <row>
+ <entry><literal>check</literal></entry>
+ <entry>SQL expression</entry>
+ <entry>
+ create an SQL check constraint on either column or table
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ The <literal><comment></literal> element allows you to specify comments
+ for the generated schema.
+ </para>
+
+ <programlisting><![CDATA[<class name="Customer" table="CurCust">
+ <comment>Current customers only</comment>
+ ...
+</class>]]></programlisting>
+
+ <programlisting><![CDATA[<property name="balance">
+ <column name="bal">
+ <comment>Balance in USD</comment>
+ </column>
+</property>]]></programlisting>
+
+ <para>
+ This results in a <literal>comment on table</literal> or
+ <literal>comment on column</literal> statement in the generated
+ DDL (where supported).
+ </para>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-3" revision="2">
+ <title>Running the tool</title>
+
+ <para>
+ The <literal>SchemaExport</literal> tool writes a DDL script to standard out and/or
+ executes the DDL statements.
+ </para>
+
+ <para>
+ <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+ <literal>org.hibernate.tool.hbm2ddl.SchemaExport</literal> <emphasis>options mapping_files</emphasis>
+ </para>
+
+ <table frame="topbot">
+ <title><literal>SchemaExport</literal> Command Line Options</title>
+ <tgroup cols="2">
+ <colspec colwidth="1.5*"/>
+ <colspec colwidth="2*"/>
+ <thead>
+ <row>
+ <entry>Option</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>--quiet</literal></entry>
+ <entry>don't output the script to stdout</entry>
+ </row>
+ <row>
+ <entry><literal>--drop</literal></entry>
+ <entry>only drop the tables</entry>
+ </row>
+ <row>
+ <entry><literal>--create</literal></entry>
+ <entry>only create the tables</entry>
+ </row>
+ <row>
+ <entry><literal>--text</literal></entry>
+ <entry>don't export to the database</entry>
+ </row>
+ <row>
+ <entry><literal>--output=my_schema.ddl</literal></entry>
+ <entry>output the ddl script to a file</entry>
+ </row>
+ <row>
+ <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+ <entry>select a <literal>NamingStrategy</literal></entry>
+ </row>
+ <row>
+ <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+ <entry>read Hibernate configuration from an XML file</entry>
+ </row>
+ <row>
+ <entry><literal>--properties=hibernate.properties</literal></entry>
+ <entry>read database properties from a file</entry>
+ </row>
+ <row>
+ <entry><literal>--format</literal></entry>
+ <entry>format the generated SQL nicely in the script</entry>
+ </row>
+ <row>
+ <entry><literal>--delimiter=;</literal></entry>
+ <entry>set an end of line delimiter for the script</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ You may even embed <literal>SchemaExport</literal> in your application:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaExport(cfg).create(false, true);]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-4">
+ <title>Properties</title>
+
+ <para>
+ Database properties may be specified
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>as system properties with <literal>-D</literal><emphasis><property></emphasis></para>
+ </listitem>
+ <listitem>
+ <para>in <literal>hibernate.properties</literal></para>
+ </listitem>
+ <listitem>
+ <para>in a named properties file with <literal>--properties</literal></para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The needed properties are:
+ </para>
+
+ <table frame="topbot">
+ <title>SchemaExport Connection Properties</title>
+ <tgroup cols="2">
+ <colspec colwidth="1.5*"/>
+ <colspec colwidth="2*"/>
+ <thead>
+ <row>
+ <entry>Property Name</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>hibernate.connection.driver_class</literal></entry>
+ <entry>jdbc driver class</entry>
+ </row>
+ <row>
+ <entry><literal>hibernate.connection.url</literal></entry>
+ <entry>jdbc url</entry>
+ </row>
+ <row>
+ <entry><literal>hibernate.connection.username</literal></entry>
+ <entry>database user</entry>
+ </row>
+ <row>
+ <entry><literal>hibernate.connection.password</literal></entry>
+ <entry>user password</entry>
+ </row>
+ <row>
+ <entry><literal>hibernate.dialect</literal></entry>
+ <entry>dialect</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-5">
+ <title>Using Ant</title>
+
+ <para>
+ You can call <literal>SchemaExport</literal> from your Ant build script:
+ </para>
+
+ <programlisting><![CDATA[<target name="schemaexport">
+ <taskdef name="schemaexport"
+ classname="org.hibernate.tool.hbm2ddl.SchemaExportTask"
+ classpathref="class.path"/>
+
+ <schemaexport
+ properties="hibernate.properties"
+ quiet="no"
+ text="no"
+ drop="no"
+ delimiter=";"
+ output="schema-export.sql">
+ <fileset dir="src">
+ <include name="**/*.hbm.xml"/>
+ </fileset>
+ </schemaexport>
+</target>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-6" revision="2">
+ <title>Incremental schema updates</title>
+
+ <para>
+ The <literal>SchemaUpdate</literal> tool will update an existing schema with "incremental" changes.
+ Note that <literal>SchemaUpdate</literal> depends heavily upon the JDBC metadata API, so it will
+ not work with all JDBC drivers.
+ </para>
+
+ <para>
+ <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+ <literal>org.hibernate.tool.hbm2ddl.SchemaUpdate</literal> <emphasis>options mapping_files</emphasis>
+ </para>
+
+ <table frame="topbot">
+ <title><literal>SchemaUpdate</literal> Command Line Options</title>
+ <tgroup cols="2">
+ <colspec colwidth="1.5*"/>
+ <colspec colwidth="2*"/>
+ <thead>
+ <row>
+ <entry>Option</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>--quiet</literal></entry>
+ <entry>don't output the script to stdout</entry>
+ </row>
+ <row>
+ <entry><literal>--text</literal></entry>
+ <entry>don't export the script to the database</entry>
+ </row>
+ <row>
+ <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+ <entry>select a <literal>NamingStrategy</literal></entry>
+ </row>
+ <row>
+ <entry><literal>--properties=hibernate.properties</literal></entry>
+ <entry>read database properties from a file</entry>
+ </row>
+ <row>
+ <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+ <entry>specify a <literal>.cfg.xml</literal> file</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ You may embed <literal>SchemaUpdate</literal> in your application:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaUpdate(cfg).execute(false);]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-7">
+ <title>Using Ant for incremental schema updates</title>
+
+ <para>
+ You can call <literal>SchemaUpdate</literal> from the Ant script:
+ </para>
+
+ <programlisting><![CDATA[<target name="schemaupdate">
+ <taskdef name="schemaupdate"
+ classname="org.hibernate.tool.hbm2ddl.SchemaUpdateTask"
+ classpathref="class.path"/>
+
+ <schemaupdate
+ properties="hibernate.properties"
+ quiet="no">
+ <fileset dir="src">
+ <include name="**/*.hbm.xml"/>
+ </fileset>
+ </schemaupdate>
+</target>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-8" revision="1">
+ <title>Schema validation</title>
+
+ <para>
+ The <literal>SchemaValidator</literal> tool will validate that the existing database schema "matches"
+ your mapping documents. Note that <literal>SchemaValidator</literal> depends heavily upon the JDBC
+ metadata API, so it will not work with all JDBC drivers. This tool is extremely useful for testing.
+ </para>
+
+ <para>
+ <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+ <literal>org.hibernate.tool.hbm2ddl.SchemaValidator</literal> <emphasis>options mapping_files</emphasis>
+ </para>
+
+ <table frame="topbot">
+ <title><literal>SchemaValidator</literal> Command Line Options</title>
+ <tgroup cols="2">
+ <colspec colwidth="1.5*"/>
+ <colspec colwidth="2*"/>
+ <thead>
+ <row>
+ <entry>Option</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+ <entry>select a <literal>NamingStrategy</literal></entry>
+ </row>
+ <row>
+ <entry><literal>--properties=hibernate.properties</literal></entry>
+ <entry>read database properties from a file</entry>
+ </row>
+ <row>
+ <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+ <entry>specify a <literal>.cfg.xml</literal> file</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ You may embed <literal>SchemaValidator</literal> in your application:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaValidator(cfg).validate();]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-9">
+ <title>Using Ant for schema validation</title>
+
+ <para>
+ You can call <literal>SchemaValidator</literal> from the Ant script:
+ </para>
+
+ <programlisting><![CDATA[<target name="schemavalidate">
+ <taskdef name="schemavalidator"
+ classname="org.hibernate.tool.hbm2ddl.SchemaValidatorTask"
+ classpathref="class.path"/>
+
+ <schemavalidator
+ properties="hibernate.properties">
+ <fileset dir="src">
+ <include name="**/*.hbm.xml"/>
+ </fileset>
+ </schemaupdate>
+</target>]]></programlisting>
+
+ </sect2>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/transactions.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/transactions.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/transactions.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,1111 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="transactions" revision="2">
+ <title>Transactions And Concurrency</title>
+
+ <para>
+ The most important point about Hibernate and concurrency control is that it is very
+ easy to understand. Hibernate directly uses JDBC connections and JTA resources without
+ adding any additional locking behavior. We highly recommend you spend some time with the
+ JDBC, ANSI, and transaction isolation specification of your database management system.
+ </para>
+
+ <para>
+ Hibernate does not lock objects in memory. Your application can expect the behavior as
+ defined by the isolation level of your database transactions. Note that thanks to the
+ <literal>Session</literal>, which is also a transaction-scoped cache, Hibernate
+ provides repeatable reads for lookup by identifier and entity queries (not
+ reporting queries that return scalar values).
+ </para>
+
+ <para>
+ In addition to versioning for automatic optimistic concurrency control, Hibernate also
+ offers a (minor) API for pessimistic locking of rows, using the
+ <literal>SELECT FOR UPDATE</literal> syntax. Optimistic concurrency control and
+ this API are discussed later in this chapter.
+ </para>
+
+ <para>
+ We start the discussion of concurrency control in Hibernate with the granularity of
+ <literal>Configuration</literal>, <literal>SessionFactory</literal>, and
+ <literal>Session</literal>, as well as database transactions and long conversations.
+ </para>
+
+ <sect1 id="transactions-basics" revision="1">
+ <title>Session and transaction scopes</title>
+
+ <para>
+ A <literal>SessionFactory</literal> is an expensive-to-create, threadsafe object
+ intended to be shared by all application threads. It is created once, usually on
+ application startup, from a <literal>Configuration</literal> instance.
+ </para>
+
+ <para>
+ A <literal>Session</literal> is an inexpensive, non-threadsafe object that should be
+ used once, for a single request, a conversation, single unit of work, and then discarded.
+ A <literal>Session</literal> will not obtain a JDBC <literal>Connection</literal>
+ (or a <literal>Datasource</literal>) unless it is needed, hence consume no
+ resources until used.
+ </para>
+
+ <para>
+ To complete this picture you also have to think about database transactions. A
+ database transaction has to be as short as possible, to reduce lock contention in
+ the database. Long database transactions will prevent your application from scaling
+ to highly concurrent load. Hence, it is almost never good design to hold a
+ database transaction open during user think time, until the unit of work is
+ complete.
+ </para>
+
+ <para>
+ What is the scope of a unit of work? Can a single Hibernate <literal>Session</literal>
+ span several database transactions or is this a one-to-one relationship of scopes? When
+ should you open and close a <literal>Session</literal> and how do you demarcate the
+ database transaction boundaries?
+ </para>
+
+ <sect2 id="transactions-basics-uow" revision="1">
+ <title>Unit of work</title>
+
+ <para>
+ First, don't use the <emphasis>session-per-operation</emphasis> antipattern, that is,
+ don't open and close a <literal>Session</literal> for every simple database call in
+ a single thread! Of course, the same is true for database transactions. Database calls
+ in an application are made using a planned sequence, they are grouped into atomic
+ units of work. (Note that this also means that auto-commit after every single
+ SQL statement is useless in an application, this mode is intended for ad-hoc SQL
+ console work. Hibernate disables, or expects the application server to do so,
+ auto-commit mode immediately.) Database transactions are never optional, all
+ communication with a database has to occur inside a transaction, no matter if
+ you read or write data. As explained, auto-commit behavior for reading data
+ should be avoided, as many small transactions are unlikely to perform better than
+ one clearly defined unit of work. The latter is also much more maintainable
+ and extensible.
+ </para>
+
+ <para>
+ The most common pattern in a multi-user client/server application is
+ <emphasis>session-per-request</emphasis>. In this model, a request from the client
+ is send to the server (where the Hibernate persistence layer runs), a new Hibernate
+ <literal>Session</literal> is opened, and all database operations are executed in this unit
+ of work. Once the work has been completed (and the response for the client has been prepared),
+ the session is flushed and closed. You would also use a single database transaction to
+ serve the clients request, starting and committing it when you open and close the
+ <literal>Session</literal>. The relationship between the two is one-to-one and this
+ model is a perfect fit for many applications.
+ </para>
+
+ <para>
+ The challenge lies in the implementation. Hibernate provides built-in management of
+ the "current session" to simplify this pattern. All you have to do is start a
+ transaction when a server request has to be processed, and end the transaction
+ before the response is send to the client. You can do this in any way you
+ like, common solutions are <literal>ServletFilter</literal>, AOP interceptor with a
+ pointcut on the service methods, or a proxy/interception container. An EJB container
+ is a standardized way to implement cross-cutting aspects such as transaction
+ demarcation on EJB session beans, declaratively with CMT. If you decide to
+ use programmatic transaction demarcation, prefer the Hibernate <literal>Transaction</literal>
+ API shown later in this chapter, for ease of use and code portability.
+ </para>
+
+ <para>
+ Your application code can access a "current session" to process the request
+ by simply calling <literal>sessionFactory.getCurrentSession()</literal> anywhere
+ and as often as needed. You will always get a <literal>Session</literal> scoped
+ to the current database transaction. This has to be configured for either
+ resource-local or JTA environments, see <xref linkend="architecture-current-session"/>.
+ </para>
+
+ <para>
+ Sometimes it is convenient to extend the scope of a <literal>Session</literal> and
+ database transaction until the "view has been rendered". This is especially useful
+ in servlet applications that utilize a separate rendering phase after the request
+ has been processed. Extending the database transaction until view rendering is
+ complete is easy to do if you implement your own interceptor. However, it is not
+ easily doable if you rely on EJBs with container-managed transactions, as a
+ transaction will be completed when an EJB method returns, before rendering of any
+ view can start. See the Hibernate website and forum for tips and examples around
+ this <emphasis>Open Session in View</emphasis> pattern.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-basics-apptx" revision="1">
+ <title>Long conversations</title>
+
+ <para>
+ The session-per-request pattern is not the only useful concept you can use to design
+ units of work. Many business processes require a whole series of interactions with the user
+ interleaved with database accesses. In web and enterprise applications it is
+ not acceptable for a database transaction to span a user interaction. Consider the following
+ example:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ The first screen of a dialog opens, the data seen by the user has been loaded in
+ a particular <literal>Session</literal> and database transaction. The user is free to
+ modify the objects.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The user clicks "Save" after 5 minutes and expects his modifications to be made
+ persistent; he also expects that he was the only person editing this information and
+ that no conflicting modification can occur.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ We call this unit of work, from the point of view of the user, a long running
+ <emphasis>conversation</emphasis> (or <emphasis>application transaction</emphasis>).
+ There are many ways how you can implement this in your application.
+ </para>
+
+ <para>
+ A first naive implementation might keep the <literal>Session</literal> and database
+ transaction open during user think time, with locks held in the database to prevent
+ concurrent modification, and to guarantee isolation and atomicity. This is of course
+ an anti-pattern, since lock contention would not allow the application to scale with
+ the number of concurrent users.
+ </para>
+
+ <para>
+ Clearly, we have to use several database transactions to implement the converastion.
+ In this case, maintaining isolation of business processes becomes the
+ partial responsibility of the application tier. A single conversation
+ usually spans several database transactions. It will be atomic if only one of
+ these database transactions (the last one) stores the updated data, all others
+ simply read data (e.g. in a wizard-style dialog spanning several request/response
+ cycles). This is easier to implement than it might sound, especially if
+ you use Hibernate's features:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Automatic Versioning</emphasis> - Hibernate can do automatic
+ optimistic concurrency control for you, it can automatically detect
+ if a concurrent modification occured during user think time. Usually
+ we only check at the end of the conversation.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Detached Objects</emphasis> - If you decide to use the already
+ discussed <emphasis>session-per-request</emphasis> pattern, all loaded instances
+ will be in detached state during user think time. Hibernate allows you to
+ reattach the objects and persist the modifications, the pattern is called
+ <emphasis>session-per-request-with-detached-objects</emphasis>. Automatic
+ versioning is used to isolate concurrent modifications.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Extended (or Long) Session</emphasis> - The Hibernate
+ <literal>Session</literal> may be disconnected from the underlying JDBC
+ connection after the database transaction has been committed, and reconnected
+ when a new client request occurs. This pattern is known as
+ <emphasis>session-per-conversation</emphasis> and makes
+ even reattachment unnecessary. Automatic versioning is used to isolate
+ concurrent modifications and the <literal>Session</literal> is usually
+ not allowed to be flushed automatically, but explicitely.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Both <emphasis>session-per-request-with-detached-objects</emphasis> and
+ <emphasis>session-per-conversation</emphasis> have advantages and disadvantages,
+ we discuss them later in this chapter in the context of optimistic concurrency control.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-basics-identity">
+ <title>Considering object identity</title>
+
+ <para>
+ An application may concurrently access the same persistent state in two
+ different <literal>Session</literal>s. However, an instance of a persistent class
+ is never shared between two <literal>Session</literal> instances. Hence there are
+ two different notions of identity:
+ </para>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>Database Identity</term>
+ <listitem>
+ <para>
+ <literal>foo.getId().equals( bar.getId() )</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>JVM Identity</term>
+ <listitem>
+ <para>
+ <literal>foo==bar</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ Then for objects attached to a <emphasis>particular</emphasis> <literal>Session</literal>
+ (i.e. in the scope of a <literal>Session</literal>) the two notions are equivalent, and
+ JVM identity for database identity is guaranteed by Hibernate. However, while the application
+ might concurrently access the "same" (persistent identity) business object in two different
+ sessions, the two instances will actually be "different" (JVM identity). Conflicts are
+ resolved using (automatic versioning) at flush/commit time, using an optimistic approach.
+ </para>
+
+ <para>
+ This approach leaves Hibernate and the database to worry about concurrency; it also provides
+ the best scalability, since guaranteeing identity in single-threaded units of work only doesn't
+ need expensive locking or other means of synchronization. The application never needs to
+ synchronize on any business object, as long as it sticks to a single thread per
+ <literal>Session</literal>. Within a <literal>Session</literal> the application may safely use
+ <literal>==</literal> to compare objects.
+ </para>
+
+ <para>
+ However, an application that uses <literal>==</literal> outside of a <literal>Session</literal>,
+ might see unexpected results. This might occur even in some unexpected places, for example,
+ if you put two detached instances into the same <literal>Set</literal>. Both might have the same
+ database identity (i.e. they represent the same row), but JVM identity is by definition not
+ guaranteed for instances in detached state. The developer has to override the <literal>equals()</literal>
+ and <literal>hashCode()</literal> methods in persistent classes and implement
+ his own notion of object equality. There is one caveat: Never use the database
+ identifier to implement equality, use a business key, a combination of unique, usually
+ immutable, attributes. The database identifier will change if a transient object is made
+ persistent. If the transient instance (usually together with detached instances) is held in a
+ <literal>Set</literal>, changing the hashcode breaks the contract of the <literal>Set</literal>.
+ Attributes for business keys don't have to be as stable as database primary keys, you only
+ have to guarantee stability as long as the objects are in the same <literal>Set</literal>. See
+ the Hibernate website for a more thorough discussion of this issue. Also note that this is not
+ a Hibernate issue, but simply how Java object identity and equality has to be implemented.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-basics-issues">
+ <title>Common issues</title>
+
+ <para>
+ Never use the anti-patterns <emphasis>session-per-user-session</emphasis> or
+ <emphasis>session-per-application</emphasis> (of course, there are rare exceptions to
+ this rule). Note that some of the following issues might also appear with the recommended
+ patterns, make sure you understand the implications before making a design decision:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ A <literal>Session</literal> is not thread-safe. Things which are supposed to work
+ concurrently, like HTTP requests, session beans, or Swing workers, will cause race
+ conditions if a <literal>Session</literal> instance would be shared. If you keep your
+ Hibernate <literal>Session</literal> in your <literal>HttpSession</literal> (discussed
+ later), you should consider synchronizing access to your Http session. Otherwise,
+ a user that clicks reload fast enough may use the same <literal>Session</literal> in
+ two concurrently running threads.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ An exception thrown by Hibernate means you have to rollback your database transaction
+ and close the <literal>Session</literal> immediately (discussed later in more detail).
+ If your <literal>Session</literal> is bound to the application, you have to stop
+ the application. Rolling back the database transaction doesn't put your business
+ objects back into the state they were at the start of the transaction. This means the
+ database state and the business objects do get out of sync. Usually this is not a
+ problem, because exceptions are not recoverable and you have to start over after
+ rollback anyway.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The <literal>Session</literal> caches every object that is in persistent state (watched
+ and checked for dirty state by Hibernate). This means it grows endlessly until you
+ get an OutOfMemoryException, if you keep it open for a long time or simply load too
+ much data. One solution for this is to call <literal>clear()</literal> and <literal>evict()</literal>
+ to manage the <literal>Session</literal> cache, but you most likely should consider a
+ Stored Procedure if you need mass data operations. Some solutions are shown in
+ <xref linkend="batch"/>. Keeping a <literal>Session</literal> open for the duration
+ of a user session also means a high probability of stale data.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="transactions-demarcation">
+ <title>Database transaction demarcation</title>
+
+ <para>
+ Datatabase (or system) transaction boundaries are always necessary. No communication with
+ the database can occur outside of a database transaction (this seems to confuse many developers
+ who are used to the auto-commit mode). Always use clear transaction boundaries, even for
+ read-only operations. Depending on your isolation level and database capabilities this might not
+ be required but there is no downside if you always demarcate transactions explicitly. Certainly,
+ a single database transaction is going to perform better than many small transactions, even
+ for reading data.
+ </para>
+
+ <para>
+ A Hibernate application can run in non-managed (i.e. standalone, simple Web- or Swing applications)
+ and managed J2EE environments. In a non-managed environment, Hibernate is usually responsible for
+ its own database connection pool. The application developer has to manually set transaction
+ boundaries, in other words, begin, commit, or rollback database transactions himself. A managed environment
+ usually provides container-managed transactions (CMT), with the transaction assembly defined declaratively
+ in deployment descriptors of EJB session beans, for example. Programmatic transaction demarcation is
+ then no longer necessary.
+ </para>
+
+ <para>
+ However, it is often desirable to keep your persistence layer portable between non-managed
+ resource-local environments, and systems that can rely on JTA but use BMT instead of CMT.
+ In both cases you'd use programmatic transaction demaracation. Hibernate offers a wrapper
+ API called <literal>Transaction</literal> that translates into the native transaction system of
+ your deployment environment. This API is actually optional, but we strongly encourage its use
+ unless you are in a CMT session bean.
+ </para>
+
+ <para>
+ Usually, ending a <literal>Session</literal> involves four distinct phases:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ flush the session
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ commit the transaction
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ close the session
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ handle exceptions
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Flushing the session has been discussed earlier, we'll now have a closer look at transaction
+ demarcation and exception handling in both managed- and non-managed environments.
+ </para>
+
+
+ <sect2 id="transactions-demarcation-nonmanaged" revision="2">
+ <title>Non-managed environment</title>
+
+ <para>
+ If a Hibernate persistence layer runs in a non-managed environment, database connections
+ are usually handled by simple (i.e. non-DataSource) connection pools from which
+ Hibernate obtains connections as needed. The session/transaction handling idiom looks
+ like this:
+ </para>
+
+ <programlisting><![CDATA[// Non-managed environment idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+ tx = sess.beginTransaction();
+
+ // do some work
+ ...
+
+ tx.commit();
+}
+catch (RuntimeException e) {
+ if (tx != null) tx.rollback();
+ throw e; // or display error message
+}
+finally {
+ sess.close();
+}]]></programlisting>
+
+ <para>
+ You don't have to <literal>flush()</literal> the <literal>Session</literal> explicitly -
+ the call to <literal>commit()</literal> automatically triggers the synchronization (depending
+ upon the <xref linkend="objectstate-flushing">FlushMode</xref> for the session.
+ A call to <literal>close()</literal> marks the end of a session. The main implication
+ of <literal>close()</literal> is that the JDBC connection will be relinquished by the
+ session. This Java code is portable and runs in both non-managed and JTA environments.
+ </para>
+
+ <para>
+ A much more flexible solution is Hibernate's built-in "current session" context
+ management, as described earlier:
+ </para>
+
+ <programlisting><![CDATA[// Non-managed environment idiom with getCurrentSession()
+try {
+ factory.getCurrentSession().beginTransaction();
+
+ // do some work
+ ...
+
+ factory.getCurrentSession().getTransaction().commit();
+}
+catch (RuntimeException e) {
+ factory.getCurrentSession().getTransaction().rollback();
+ throw e; // or display error message
+}]]></programlisting>
+
+ <para>
+ You will very likely never see these code snippets in a regular application;
+ fatal (system) exceptions should always be caught at the "top". In other words, the
+ code that executes Hibernate calls (in the persistence layer) and the code that handles
+ <literal>RuntimeException</literal> (and usually can only clean up and exit) are in
+ different layers. The current context management by Hibernate can significantly
+ simplify this design, as all you need is access to a <literal>SessionFactory</literal>.
+ Exception handling is discussed later in this chapter.
+ </para>
+
+ <para>
+ Note that you should select <literal>org.hibernate.transaction.JDBCTransactionFactory</literal>
+ (which is the default), and for the second example <literal>"thread"</literal> as your
+ <literal>hibernate.current_session_context_class</literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-demarcation-jta" revision="3">
+ <title>Using JTA</title>
+
+ <para>
+ If your persistence layer runs in an application server (e.g. behind EJB session beans),
+ every datasource connection obtained by Hibernate will automatically be part of the global
+ JTA transaction. You can also install a standalone JTA implementation and use it without
+ EJB. Hibernate offers two strategies for JTA integration.
+ </para>
+
+ <para>
+ If you use bean-managed transactions (BMT) Hibernate will tell the application server to start
+ and end a BMT transaction if you use the <literal>Transaction</literal> API. So, the
+ transaction management code is identical to the non-managed environment.
+ </para>
+
+ <programlisting><![CDATA[// BMT idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+ tx = sess.beginTransaction();
+
+ // do some work
+ ...
+
+ tx.commit();
+}
+catch (RuntimeException e) {
+ if (tx != null) tx.rollback();
+ throw e; // or display error message
+}
+finally {
+ sess.close();
+}]]></programlisting>
+
+ <para>
+ If you want to use a transaction-bound <literal>Session</literal>, that is, the
+ <literal>getCurrentSession()</literal> functionality for easy context propagation,
+ you will have to use the JTA <literal>UserTransaction</literal> API directly:
+ </para>
+
+ <programlisting><![CDATA[// BMT idiom with getCurrentSession()
+try {
+ UserTransaction tx = (UserTransaction)new InitialContext()
+ .lookup("java:comp/UserTransaction");
+
+ tx.begin();
+
+ // Do some work on Session bound to transaction
+ factory.getCurrentSession().load(...);
+ factory.getCurrentSession().persist(...);
+
+ tx.commit();
+}
+catch (RuntimeException e) {
+ tx.rollback();
+ throw e; // or display error message
+}]]></programlisting>
+
+ <para>
+ With CMT, transaction demarcation is done in session bean deployment descriptors, not programatically,
+ hence, the code is reduced to:
+ </para>
+
+ <programlisting><![CDATA[// CMT idiom
+ Session sess = factory.getCurrentSession();
+
+ // do some work
+ ...
+]]></programlisting>
+
+ <para>
+ In a CMT/EJB even rollback happens automatically, since an unhandled <literal>RuntimeException</literal>
+ thrown by a session bean method tells the container to set the global transaction to rollback.
+ <emphasis>This means you do not need to use the Hibernate <literal>Transaction</literal> API at
+ all with BMT or CMT, and you get automatic propagation of the "current" Session bound to the
+ transaction.</emphasis>
+ </para>
+
+ <para>
+ Note that you should choose <literal>org.hibernate.transaction.JTATransactionFactory</literal>
+ if you use JTA directly (BMT), and <literal>org.hibernate.transaction.CMTTransactionFactory</literal>
+ in a CMT session bean, when you configure Hibernate's transaction factory. Remember to also set
+ <literal>hibernate.transaction.manager_lookup_class</literal>. Furthermore, make sure
+ that your <literal>hibernate.current_session_context_class</literal> is either unset (backwards
+ compatiblity), or set to <literal>"jta"</literal>.
+ </para>
+
+ <para>
+ The <literal>getCurrentSession()</literal> operation has one downside in a JTA environment.
+ There is one caveat to the use of <literal>after_statement</literal> connection release
+ mode, which is then used by default. Due to a silly limitation of the JTA spec, it is not
+ possible for Hibernate to automatically clean up any unclosed <literal>ScrollableResults</literal> or
+ <literal>Iterator</literal> instances returned by <literal>scroll()</literal> or
+ <literal>iterate()</literal>. You <emphasis>must</emphasis> release the underlying database
+ cursor by calling <literal>ScrollableResults.close()</literal> or
+ <literal>Hibernate.close(Iterator)</literal> explicity from a <literal>finally</literal>
+ block. (Of course, most applications can easily avoid using <literal>scroll()</literal> or
+ <literal>iterate()</literal> at all from the JTA or CMT code.)
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-demarcation-exceptions">
+ <title>Exception handling</title>
+
+ <para>
+ If the <literal>Session</literal> throws an exception (including any
+ <literal>SQLException</literal>), you should immediately rollback the database
+ transaction, call <literal>Session.close()</literal> and discard the
+ <literal>Session</literal> instance. Certain methods of <literal>Session</literal>
+ will <emphasis>not</emphasis> leave the session in a consistent state. No
+ exception thrown by Hibernate can be treated as recoverable. Ensure that the
+ <literal>Session</literal> will be closed by calling <literal>close()</literal>
+ in a <literal>finally</literal> block.
+ </para>
+
+ <para>
+ The <literal>HibernateException</literal>, which wraps most of the errors that
+ can occur in a Hibernate persistence layer, is an unchecked exception (it wasn't
+ in older versions of Hibernate). In our opinion, we shouldn't force the application
+ developer to catch an unrecoverable exception at a low layer. In most systems, unchecked
+ and fatal exceptions are handled in one of the first frames of the method call
+ stack (i.e. in higher layers) and an error message is presented to the application
+ user (or some other appropriate action is taken). Note that Hibernate might also throw
+ other unchecked exceptions which are not a <literal>HibernateException</literal>. These
+ are, again, not recoverable and appropriate action should be taken.
+ </para>
+
+ <para>
+ Hibernate wraps <literal>SQLException</literal>s thrown while interacting with the database
+ in a <literal>JDBCException</literal>. In fact, Hibernate will attempt to convert the eexception
+ into a more meningful subclass of <literal>JDBCException</literal>. The underlying
+ <literal>SQLException</literal> is always available via <literal>JDBCException.getCause()</literal>.
+ Hibernate converts the <literal>SQLException</literal> into an appropriate
+ <literal>JDBCException</literal> subclass using the <literal>SQLExceptionConverter</literal>
+ attached to the <literal>SessionFactory</literal>. By default, the
+ <literal>SQLExceptionConverter</literal> is defined by the configured dialect; however, it is
+ also possible to plug in a custom implementation (see the javadocs for the
+ <literal>SQLExceptionConverterFactory</literal> class for details). The standard
+ <literal>JDBCException</literal> subtypes are:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>JDBCConnectionException</literal> - indicates an error
+ with the underlying JDBC communication.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>SQLGrammarException</literal> - indicates a grammar
+ or syntax problem with the issued SQL.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ConstraintViolationException</literal> - indicates some
+ form of integrity constraint violation.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockAcquisitionException</literal> - indicates an error
+ acquiring a lock level necessary to perform the requested operation.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>GenericJDBCException</literal> - a generic exception
+ which did not fall into any of the other categories.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect2>
+
+ <sect2 id="transactions-demarcation-timeout">
+ <title>Transaction timeout</title>
+
+ <para>
+ One extremely important feature provided by a managed environment like EJB
+ that is never provided for non-managed code is transaction timeout. Transaction
+ timeouts ensure that no misbehaving transaction can indefinitely tie up
+ resources while returning no response to the user. Outside a managed (JTA)
+ environment, Hibernate cannot fully provide this functionality. However,
+ Hibernate can at least control data access operations, ensuring that database
+ level deadlocks and queries with huge result sets are limited by a defined
+ timeout. In a managed environment, Hibernate can delegate transaction timeout
+ to JTA. This functioanlity is abstracted by the Hibernate
+ <literal>Transaction</literal> object.
+ </para>
+
+ <programlisting><![CDATA[
+Session sess = factory.openSession();
+try {
+ //set transaction timeout to 3 seconds
+ sess.getTransaction().setTimeout(3);
+ sess.getTransaction().begin();
+
+ // do some work
+ ...
+
+ sess.getTransaction().commit()
+}
+catch (RuntimeException e) {
+ sess.getTransaction().rollback();
+ throw e; // or display error message
+}
+finally {
+ sess.close();
+}]]></programlisting>
+
+ <para>
+ Note that <literal>setTimeout()</literal> may not be called in a CMT bean,
+ where transaction timeouts must be defined declaratively.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="transactions-optimistic">
+ <title>Optimistic concurrency control</title>
+
+ <para>
+ The only approach that is consistent with high concurrency and high
+ scalability is optimistic concurrency control with versioning. Version
+ checking uses version numbers, or timestamps, to detect conflicting updates
+ (and to prevent lost updates). Hibernate provides for three possible approaches
+ to writing application code that uses optimistic concurrency. The use cases
+ we show are in the context of long conversations, but version checking
+ also has the benefit of preventing lost updates in single database transactions.
+ </para>
+
+ <sect2 id="transactions-optimistic-manual">
+ <title>Application version checking</title>
+
+ <para>
+ In an implementation without much help from Hibernate, each interaction with the
+ database occurs in a new <literal>Session</literal> and the developer is responsible
+ for reloading all persistent instances from the database before manipulating them.
+ This approach forces the application to carry out its own version checking to ensure
+ conversation transaction isolation. This approach is the least efficient in terms of
+ database access. It is the approach most similar to entity EJBs.
+ </para>
+
+ <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+
+int oldVersion = foo.getVersion();
+session.load( foo, foo.getKey() ); // load the current state
+if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException();
+foo.setProperty("bar");
+
+t.commit();
+session.close();]]></programlisting>
+
+ <para>
+ The <literal>version</literal> property is mapped using <literal><version></literal>,
+ and Hibernate will automatically increment it during flush if the entity is
+ dirty.
+ </para>
+
+ <para>
+ Of course, if you are operating in a low-data-concurrency environment and don't
+ require version checking, you may use this approach and just skip the version
+ check. In that case, <emphasis>last commit wins</emphasis> will be the default
+ strategy for your long conversations. Keep in mind that this might
+ confuse the users of the application, as they might experience lost updates without
+ error messages or a chance to merge conflicting changes.
+ </para>
+
+ <para>
+ Clearly, manual version checking is only feasible in very trivial circumstances
+ and not practical for most applications. Often not only single instances, but
+ complete graphs of modified ojects have to be checked. Hibernate offers automatic
+ version checking with either an extended <literal>Session</literal> or detached instances
+ as the design paradigm.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-optimistic-longsession">
+ <title>Extended session and automatic versioning</title>
+
+ <para>
+ A single <literal>Session</literal> instance and its persistent instances are
+ used for the whole conversation, known as <emphasis>session-per-conversation</emphasis>.
+ Hibernate checks instance versions at flush time, throwing an exception if concurrent
+ modification is detected. It's up to the developer to catch and handle this exception
+ (common options are the opportunity for the user to merge changes or to restart the
+ business conversation with non-stale data).
+ </para>
+
+ <para>
+ The <literal>Session</literal> is disconnected from any underlying JDBC connection
+ when waiting for user interaction. This approach is the most efficient in terms
+ of database access. The application need not concern itself with version checking or
+ with reattaching detached instances, nor does it have to reload instances in every
+ database transaction.
+ </para>
+
+ <programlisting><![CDATA[// foo is an instance loaded earlier by the old session
+Transaction t = session.beginTransaction(); // Obtain a new JDBC connection, start transaction
+
+foo.setProperty("bar");
+
+session.flush(); // Only for last transaction in conversation
+t.commit(); // Also return JDBC connection
+session.close(); // Only for last transaction in conversation]]></programlisting>
+ <para>
+ The <literal>foo</literal> object still knows which <literal>Session</literal> it was
+ loaded in. Beginning a new database transaction on an old session obtains a new connection
+ and resumes the session. Committing a database transaction disconnects a session
+ from the JDBC connection and returns the connection to the pool. After reconnection, to
+ force a version check on data you aren't updating, you may call <literal>Session.lock()</literal>
+ with <literal>LockMode.READ</literal> on any objects that might have been updated by another
+ transaction. You don't need to lock any data that you <emphasis>are</emphasis> updating.
+ Usually you would set <literal>FlushMode.NEVER</literal> on an extended <literal>Session</literal>,
+ so that only the last database transaction cycle is allowed to actually persist all
+ modifications made in this conversation. Hence, only this last database transaction
+ would include the <literal>flush()</literal> operation, and then also
+ <literal>close()</literal> the session to end the conversation.
+ </para>
+
+ <para>
+ This pattern is problematic if the <literal>Session</literal> is too big to
+ be stored during user think time, e.g. an <literal>HttpSession</literal> should
+ be kept as small as possible. As the <literal>Session</literal> is also the
+ (mandatory) first-level cache and contains all loaded objects, we can probably
+ use this strategy only for a few request/response cycles. You should use a
+ <literal>Session</literal> only for a single conversation, as it will soon also
+ have stale data.
+ </para>
+
+ <para>
+ (Note that earlier Hibernate versions required explicit disconnection and reconnection
+ of a <literal>Session</literal>. These methods are deprecated, as beginning and
+ ending a transaction has the same effect.)
+ </para>
+
+ <para>
+ Also note that you should keep the disconnected <literal>Session</literal> close
+ to the persistence layer. In other words, use an EJB stateful session bean to
+ hold the <literal>Session</literal> in a three-tier environment, and don't transfer
+ it to the web layer (or even serialize it to a separate tier) to store it in the
+ <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">
+ <title>Detached objects and automatic versioning</title>
+
+ <para>
+ Each interaction with the persistent store occurs in a new <literal>Session</literal>.
+ However, the same persistent instances are reused for each interaction with the database.
+ The application manipulates the state of detached instances originally loaded in another
+ <literal>Session</literal> and then reattaches them using <literal>Session.update()</literal>,
+ <literal>Session.saveOrUpdate()</literal>, or <literal>Session.merge()</literal>.
+ </para>
+
+ <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+foo.setProperty("bar");
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+session.saveOrUpdate(foo); // Use merge() if "foo" might have been loaded already
+t.commit();
+session.close();]]></programlisting>
+
+ <para>
+ Again, Hibernate will check instance versions during flush, throwing an
+ exception if conflicting updates occured.
+ </para>
+
+ <para>
+ You may also call <literal>lock()</literal> instead of <literal>update()</literal>
+ and use <literal>LockMode.READ</literal> (performing a version check, bypassing all
+ caches) if you are sure that the object has not been modified.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-optimistic-customizing">
+ <title>Customizing automatic versioning</title>
+
+ <para>
+ You may disable Hibernate's automatic version increment for particular properties and
+ collections by setting the <literal>optimistic-lock</literal> mapping attribute to
+ <literal>false</literal>. Hibernate will then no longer increment versions if the
+ property is dirty.
+ </para>
+
+ <para>
+ Legacy database schemas are often static and can't be modified. Or, other applications
+ might also access the same database and don't know how to handle version numbers or
+ even timestamps. In both cases, versioning can't rely on a particular column in a table.
+ To force a version check without a version or timestamp property mapping, with a
+ comparison of the state of all fields in a row, turn on <literal>optimistic-lock="all"</literal>
+ in the <literal><class></literal> mapping. Note that this concepetually only works
+ if Hibernate can compare the old and new state, i.e. if you use a single long
+ <literal>Session</literal> and not session-per-request-with-detached-objects.
+ </para>
+
+ <para>
+ Sometimes concurrent modification can be permitted as long as the changes that have been
+ made don't overlap. If you set <literal>optimistic-lock="dirty"</literal> when mapping the
+ <literal><class></literal>, Hibernate will only compare dirty fields during flush.
+ </para>
+
+ <para>
+ In both cases, with dedicated version/timestamp columns or with full/dirty field
+ comparison, Hibernate uses a single <literal>UPDATE</literal> statement (with an
+ appropriate <literal>WHERE</literal> clause) per entity to execute the version check
+ and update the information. If you use transitive persistence to cascade reattachment
+ to associated entities, Hibernate might execute uneccessary updates. This is usually
+ not a problem, but <emphasis>on update</emphasis> triggers in the database might be
+ executed even when no changes have been made to detached instances. You can customize
+ this behavior by setting <literal>select-before-update="true"</literal> in the
+ <literal><class></literal> mapping, forcing Hibernate to <literal>SELECT</literal>
+ the instance to ensure that changes did actually occur, before updating the row.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="transactions-locking">
+ <title>Pessimistic Locking</title>
+
+ <para>
+ It is not intended that users spend much time worring about locking strategies. Its usually
+ enough to specify an isolation level for the JDBC connections and then simply let the
+ database do all the work. However, advanced users may sometimes wish to obtain
+ exclusive pessimistic locks, or re-obtain locks at the start of a new transaction.
+ </para>
+
+ <para>
+ Hibernate will always use the locking mechanism of the database, never lock objects
+ in memory!
+ </para>
+
+ <para>
+ The <literal>LockMode</literal> class defines the different lock levels that may be acquired
+ by Hibernate. A lock is obtained by the following mechanisms:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>LockMode.WRITE</literal> is acquired automatically when Hibernate updates or inserts
+ a row.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.UPGRADE</literal> may be acquired upon explicit user request using
+ <literal>SELECT ... FOR UPDATE</literal> on databases which support that syntax.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.UPGRADE_NOWAIT</literal> may be acquired upon explicit user request using a
+ <literal>SELECT ... FOR UPDATE NOWAIT</literal> under Oracle.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.READ</literal> is acquired automatically when Hibernate reads data
+ under Repeatable Read or Serializable isolation level. May be re-acquired by explicit user
+ request.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.NONE</literal> represents the absence of a lock. All objects switch to this
+ lock mode at the end of a <literal>Transaction</literal>. Objects associated with the session
+ via a call to <literal>update()</literal> or <literal>saveOrUpdate()</literal> also start out
+ in this lock mode.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The "explicit user request" is expressed in one of the following ways:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ A call to <literal>Session.load()</literal>, specifying a <literal>LockMode</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A call to <literal>Session.lock()</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A call to <literal>Query.setLockMode()</literal>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ If <literal>Session.load()</literal> is called with <literal>UPGRADE</literal> or
+ <literal>UPGRADE_NOWAIT</literal>, and the requested object was not yet loaded by
+ the session, the object is loaded using <literal>SELECT ... FOR UPDATE</literal>.
+ If <literal>load()</literal> is called for an object that is already loaded with
+ a less restrictive lock than the one requested, Hibernate calls
+ <literal>lock()</literal> for that object.
+ </para>
+
+ <para>
+ <literal>Session.lock()</literal> performs a version number check if the specified lock
+ mode is <literal>READ</literal>, <literal>UPGRADE</literal> or
+ <literal>UPGRADE_NOWAIT</literal>. (In the case of <literal>UPGRADE</literal> or
+ <literal>UPGRADE_NOWAIT</literal>, <literal>SELECT ... FOR UPDATE</literal> is used.)
+ </para>
+
+ <para>
+ If the database does not support the requested lock mode, Hibernate will use an appropriate
+ alternate mode (instead of throwing an exception). This ensures that applications will
+ be portable.
+ </para>
+
+ </sect1>
+
+ <sect1 id="transactions-connection-release">
+ <title>Connection Release Modes</title>
+
+ <para>
+ The legacy (2.x) behavior of Hibernate in regards to JDBC connection management
+ was that a <literal>Session</literal> would obtain a connection when it was first
+ needed and then hold unto that connection until the session was closed.
+ Hibernate 3.x introduced the notion of connection release modes to tell a session
+ how to handle its JDBC connections. Note that the following discussion is pertinent
+ only to connections provided through a configured <literal>ConnectionProvider</literal>;
+ user-supplied connections are outside the breadth of this discussion. The different
+ release modes are identified by the enumerated values of
+ <literal>org.hibernate.ConnectionReleaseMode</literal>:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>ON_CLOSE</literal> - is essentially the legacy behavior described above. The
+ Hibernate session obatins a connection when it first needs to perform some JDBC access
+ and holds unto that connection until the session is closed.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>AFTER_TRANSACTION</literal> - says to release connections after a
+ <literal>org.hibernate.Transaction</literal> has completed.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>AFTER_STATEMENT</literal> (also referred to as aggressive release) - says to
+ release connections after each and every statement execution. This aggressive releasing
+ is skipped if that statement leaves open resources associated with the given session;
+ currently the only situation where this occurs is through the use of
+ <literal>org.hibernate.ScrollableResults</literal>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The configuration parameter <literal>hibernate.connection.release_mode</literal> is used
+ to specify which release mode to use. The possible values:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>auto</literal> (the default) - this choice delegates to the release mode
+ returned by the <literal>org.hibernate.transaction.TransactionFactory.getDefaultReleaseMode()</literal>
+ method. For JTATransactionFactory, this returns ConnectionReleaseMode.AFTER_STATEMENT; for
+ JDBCTransactionFactory, this returns ConnectionReleaseMode.AFTER_TRANSACTION. It is rarely
+ a good idea to change this default behavior as failures due to the value of this setting
+ tend to indicate bugs and/or invalid assumptions in user code.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>on_close</literal> - says to use ConnectionReleaseMode.ON_CLOSE. This setting
+ is left for backwards compatibility, but its use is highly discouraged.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>after_transaction</literal> - says to use ConnectionReleaseMode.AFTER_TRANSACTION.
+ This setting should not be used in JTA environments. Also note that with
+ ConnectionReleaseMode.AFTER_TRANSACTION, if a session is considered to be in auto-commit
+ mode connections will be released as if the release mode were AFTER_STATEMENT.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>after_statement</literal> - says to use ConnectionReleaseMode.AFTER_STATEMENT. Additionally,
+ the configured <literal>ConnectionProvider</literal> is consulted to see if it supports this
+ setting (<literal>supportsAggressiveRelease()</literal>). If not, the release mode is reset
+ to ConnectionReleaseMode.AFTER_TRANSACTION. This setting is only safe in environments where
+ we can either re-acquire the same underlying JDBC connection each time we make a call into
+ <literal>ConnectionProvider.getConnection()</literal> or in auto-commit environments where
+ it does not matter whether we get back the same connection.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/tutorial.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/tutorial.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/tutorial.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,1532 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="tutorial">
+ <title>Introduction to Hibernate</title>
+
+ <sect1 id="tutorial-intro" revision="1">
+ <title>Preface</title>
+
+ <para>
+ This chapter is an introductory tutorial for new users of Hibernate. We start
+ with a simple command line application using an in-memory database and develop
+ it in easy to understand steps.
+ </para>
+
+ <para>
+ This tutorial is intended for new users of Hibernate but requires Java and
+ SQL knowledge. It is based on a tutorial by Michael Gloegl, the third-party
+ libraries we name are for JDK 1.4 and 5.0. You might need others for JDK 1.3.
+ </para>
+
+ <para>
+ The source code for the tutorial is included in the distribution in the
+ <literal>doc/reference/tutorial/</literal> directory.
+ </para>
+
+ </sect1>
+
+ <sect1 id="tutorial-firstapp" revision="2">
+ <title>Part 1 - The first Hibernate Application</title>
+
+ <para>
+ First, we'll create a simple console-based Hibernate application. We use an
+ Java database (HSQL DB), so we do not have to install any database server.
+ </para>
+
+ <para>
+ Let's assume we need a small database application that can store events we want to
+ attend, and information about the hosts of these events.
+ </para>
+
+ <para>
+ The first thing we do, is set up our development directory and put all the
+ Java libraries we need into it. Download the Hibernate distribution from the
+ Hibernate website. Extract the package and place all required libraries
+ found in <literal>/lib</literal> into into the <literal>/lib</literal> directory
+ of your new development working directory. It should look like this:
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ antlr.jar
+ cglib.jar
+ asm.jar
+ asm-attrs.jars
+ commons-collections.jar
+ commons-logging.jar
+ hibernate3.jar
+ jta.jar
+ dom4j.jar
+ log4j.jar ]]></programlisting>
+
+ <para>
+ This is the minimum set of required libraries (note that we also copied
+ hibernate3.jar, the main archive) for Hibernate <emphasis>at the time of writing</emphasis>.
+ The Hibernate release you are using might require more or less libraries. See the
+ <literal>README.txt</literal> file in the <literal>lib/</literal> directory of the
+ Hibernate distribution for more information about required and optional third-party
+ libraries. (Actually, Log4j is not required but preferred by many developers.)
+ </para>
+
+ <para>
+ Next we create a class that represents the event we want to store in database.
+ </para>
+
+ <sect2 id="tutorial-firstapp-firstclass" revision="1">
+ <title>The first class</title>
+
+ <para>
+ Our first persistent class is a simple JavaBean class with some properties:
+ </para>
+
+ <programlisting><![CDATA[package events;
+
+import java.util.Date;
+
+public class Event {
+ private Long id;
+
+ private String title;
+ private Date date;
+
+ public Event() {}
+
+ public Long getId() {
+ return id;
+ }
+
+ private void setId(Long id) {
+ this.id = id;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+}]]></programlisting>
+
+ <para>
+ You can see that this class uses standard JavaBean naming conventions for property
+ getter and setter methods, as well as private visibility for the fields. This is
+ a recommended design - but not required. Hibernate can also access fields directly,
+ the benefit of accessor methods is robustness for refactoring. The no-argument
+ constructor is required to instantiate an object of this class through reflection.
+ </para>
+
+ <para>
+ The <literal>id</literal> property holds a unique identifier value for a particular event.
+ All persistent entity classes (there are less important dependent classes as well) will need
+ such an identifier property if we want to use the full feature set of Hibernate. In fact,
+ most applications (esp. web applications) need to distinguish objects by identifier, so you
+ should consider this a feature rather than a limitation. However, we usually don't manipulate
+ the identity of an object, hence the setter method should be private. Only Hibernate will assign
+ identifiers when an object is saved. You can see that Hibernate can access public, private,
+ and protected accessor methods, as well as (public, private, protected) fields directly. The
+ choice is up to you and you can match it to fit your application design.
+ </para>
+
+ <para>
+ The no-argument constructor is a requirement for all persistent classes; Hibernate
+ has to create objects for you, using Java Reflection. The constructor can be
+ private, however, package visibility is required for runtime proxy generation and
+ efficient data retrieval without bytecode instrumentation.
+ </para>
+
+ <para>
+ Place this Java source file in a directory called <literal>src</literal> in the
+ development folder, and in its correct package. The directory should now look like this:
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ <Hibernate and third-party libraries>
++src
+ +events
+ Event.java]]></programlisting>
+
+ <para>
+ In the next step, we tell Hibernate about this persistent class.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-mapping" revision="1">
+ <title>The mapping file</title>
+
+ <para>
+ Hibernate needs to know how to load and store objects of the persistent class.
+ This is where the Hibernate mapping file comes into play. The mapping file
+ tells Hibernate what table in the database it has to access, and what columns
+ in that table it should use.
+ </para>
+
+ <para>
+ The basic structure of a mapping file looks like this:
+ </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">
+
+<hibernate-mapping>
+[...]
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Note that the Hibernate DTD is very sophisticated. You can use it for
+ auto-completion of XML mapping elements and attributes in your editor or
+ IDE. You also should open up the DTD file in your text editor - it's the
+ easiest way to get an overview of all elements and attributes and to see
+ the defaults, as well as some comments. Note that Hibernate will not
+ load the DTD file from the web, but first look it up from the classpath
+ of the application. The DTD file is included in <literal>hibernate3.jar</literal>
+ as well as in the <literal>src/</literal> directory of the Hibernate distribution.
+ </para>
+
+ <para>
+ We will omit the DTD declaration in future examples to shorten the code. It is
+ of course not optional.
+ </para>
+
+ <para>
+ Between the two <literal>hibernate-mapping</literal> tags, include a
+ <literal>class</literal> element. All persistent entity classes (again, there
+ might be dependent classes later on, which are not first-class entities) need
+ such a mapping, to a table in the SQL database:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="events.Event" table="EVENTS">
+
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ So far we told Hibernate how to persist and load object of class <literal>Event</literal>
+ to the table <literal>EVENTS</literal>, each instance represented by a row in that table.
+ Now we continue with a mapping of the unique identifier property to the tables primary key.
+ In addition, as we don't want to care about handling this identifier, we configure Hibernate's
+ identifier generation strategy for a surrogate primary key column:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="events.Event" table="EVENTS">
+ <id name="id" column="EVENT_ID">
+ <generator class="native"/>
+ </id>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ The <literal>id</literal> element is the declaration of the identifer property,
+ <literal>name="id"</literal> declares the name of the Java property -
+ Hibernate will use the getter and setter methods to access the property.
+ The column attribute tells Hibernate which column of the
+ <literal>EVENTS</literal> table we use for this primary key. The nested
+ <literal>generator</literal> element specifies the identifier generation strategy,
+ in this case we used <literal>native</literal>, which picks the best strategy depending
+ on the configured database (dialect). Hibernate supports database generated, globally
+ unique, as well as application assigned identifiers (or any strategy you have written
+ an extension for).
+ </para>
+
+ <para>
+ Finally we include declarations for the persistent properties of the class in
+ the mapping file. By default, no properties of the class are considered
+ persistent:
+ </para>
+
+ <programlisting><![CDATA[
+<hibernate-mapping>
+
+ <class name="events.Event" table="EVENTS">
+ <id name="id" column="EVENT_ID">
+ <generator class="native"/>
+ </id>
+ <property name="date" type="timestamp" column="EVENT_DATE"/>
+ <property name="title"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Just as with the <literal>id</literal> element, the <literal>name</literal>
+ attribute of the <literal>property</literal> element tells Hibernate which getter
+ and setter methods to use. So, in this case, Hibernate will look for
+ <literal>getDate()/setDate()</literal>, as well as <literal>getTitle()/setTitle()</literal>.
+ </para>
+
+ <para>
+ Why does the <literal>date</literal> property mapping include the
+ <literal>column</literal> attribute, but the <literal>title</literal>
+ doesn't? Without the <literal>column</literal> attribute Hibernate
+ by default uses the property name as the column name. This works fine for
+ <literal>title</literal>. However, <literal>date</literal> is a reserved
+ keyword in most database, so we better map it to a different name.
+ </para>
+
+ <para>
+ The next interesting thing is that the <literal>title</literal> mapping also lacks
+ a <literal>type</literal> attribute. The types we declare and use in the mapping
+ files are not, as you might expect, Java data types. They are also not SQL
+ database types. These types are so called <emphasis>Hibernate mapping types</emphasis>,
+ converters which can translate from Java to SQL data types and vice versa. Again,
+ Hibernate will try to determine the correct conversion and mapping type itself if
+ the <literal>type</literal> attribute is not present in the mapping. In some cases this
+ automatic detection (using Reflection on the Java class) might not have the default you
+ expect or need. This is the case with the <literal>date</literal> property. Hibernate can't
+ know if the property (which is of <literal>java.util.Date</literal>) should map to a
+ SQL <literal>date</literal>, <literal>timestamp</literal>, or <literal>time</literal> column.
+ We preserve full date and time information by mapping the property with a
+ <literal>timestamp</literal> converter.
+ </para>
+
+ <para>
+ This mapping file should be saved as <literal>Event.hbm.xml</literal>, right in
+ the directory next to the <literal>Event</literal> Java class source file.
+ The naming of mapping files can be arbitrary, however the <literal>hbm.xml</literal>
+ suffix is a convention in the Hibernate developer community. The directory structure
+ should now look like this:
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ <Hibernate and third-party libraries>
++src
+ +events
+ Event.java
+ Event.hbm.xml]]></programlisting>
+
+ <para>
+ We continue with the main configuration of Hibernate.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-configuration" revision="2">
+ <title>Hibernate configuration</title>
+
+ <para>
+ We now have a persistent class and its mapping file in place. It is time to configure
+ Hibernate. Before we do this, we will need a database. HSQL DB, a java-based SQL DBMS,
+ can be downloaded from the HSQL DB website. Actually, you only need the <literal>hsqldb.jar</literal>
+ from this download. Place this file in the <literal>lib/</literal> directory of the
+ development folder.
+ </para>
+
+ <para>
+ Create a directory called <literal>data</literal> in the root of the development directory -
+ this is where HSQL DB will store its data files. Now start the database by running
+ <literal>java -classpath ../lib/hsqldb.jar org.hsqldb.Server</literal> in this data directory.
+ You can see it start up and bind to a TCP/IP socket, this is where our application
+ will connect later. If you want to start with a fresh database during this tutorial,
+ shutdown HSQL DB (press <literal>CTRL + C</literal> in the window), delete all files in the
+ <literal>data/</literal> directory, and start HSQL DB again.
+ </para>
+
+ <para>
+ Hibernate is the layer in your application which connects to this database, so it needs
+ connection information. The connections are made through a JDBC connection pool, which we
+ also have to configure. The Hibernate distribution contains several open source JDBC connection
+ pooling tools, but will use the Hibernate built-in connection pool for this tutorial. Note that
+ you have to copy the required library into your classpath and use different
+ connection pooling settings if you want to use a production-quality third party
+ JDBC pooling software.
+ </para>
+
+ <para>
+ For Hibernate's configuration, we can use a simple <literal>hibernate.properties</literal> file, a
+ slightly more sophisticated <literal>hibernate.cfg.xml</literal> file, or even complete
+ programmatic setup. Most users prefer the XML configuration file:
+ </para>
+
+ <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+ "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+ <session-factory>
+
+ <!-- Database connection settings -->
+ <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
+ <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
+ <property name="connection.username">sa</property>
+ <property name="connection.password"></property>
+
+ <!-- JDBC connection pool (use the built-in) -->
+ <property name="connection.pool_size">1</property>
+
+ <!-- SQL dialect -->
+ <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
+
+ <!-- Enable Hibernate's automatic session context management -->
+ <property name="current_session_context_class">thread</property>
+
+ <!-- Disable the second-level cache -->
+ <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
+
+ <!-- Echo all executed SQL to stdout -->
+ <property name="show_sql">true</property>
+
+ <!-- Drop and re-create the database schema on startup -->
+ <property name="hbm2ddl.auto">create</property>
+
+ <mapping resource="events/Event.hbm.xml"/>
+
+ </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+ <para>
+ Note that this XML configuration uses a different DTD. We configure
+ Hibernate's <literal>SessionFactory</literal> - a global factory responsible
+ for a particular database. If you have several databases, use several
+ <literal><session-factory></literal> configurations, usually in
+ several configuration files (for easier startup).
+ </para>
+
+ <para>
+ The first four <literal>property</literal> elements contain the necessary
+ configuration for the JDBC connection. The dialect <literal>property</literal>
+ element specifies the particular SQL variant Hibernate generates.
+ Hibernate's automatic session management for persistence contexts will
+ come in handy as you will soon see.
+ The <literal>hbm2ddl.auto</literal> option turns on automatic generation of
+ database schemas - directly into the database. This can of course also be turned
+ off (by removing the config option) or redirected to a file with the help of
+ the <literal>SchemaExport</literal> Ant task. Finally, we add the mapping file(s)
+ for persistent classes to the configuration.
+ </para>
+
+ <para>
+ Copy this file into the source directory, so it will end up in the
+ root of the classpath. Hibernate automatically looks for a file called
+ <literal>hibernate.cfg.xml</literal> in the root of the classpath, on startup.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-ant" revision="1">
+ <title>Building with Ant</title>
+
+ <para>
+ We'll now build the tutorial with Ant. You will need to have Ant installed - get
+ it from the <ulink url="http://ant.apache.org/bindownload.cgi">Ant download page</ulink>.
+ How to install Ant will not be covered here. Please refer to the
+ <ulink url="http://ant.apache.org/manual/index.html">Ant manual</ulink>. After you
+ have installed Ant, we can start to create the buildfile. It will be called
+ <literal>build.xml</literal> and placed directly in the development directory.
+ </para>
+
+ <para>
+ A basic build file looks like this:
+ </para>
+
+ <programlisting><![CDATA[<project name="hibernate-tutorial" default="compile">
+
+ <property name="sourcedir" value="${basedir}/src"/>
+ <property name="targetdir" value="${basedir}/bin"/>
+ <property name="librarydir" value="${basedir}/lib"/>
+
+ <path id="libraries">
+ <fileset dir="${librarydir}">
+ <include name="*.jar"/>
+ </fileset>
+ </path>
+
+ <target name="clean">
+ <delete dir="${targetdir}"/>
+ <mkdir dir="${targetdir}"/>
+ </target>
+
+ <target name="compile" depends="clean, copy-resources">
+ <javac srcdir="${sourcedir}"
+ destdir="${targetdir}"
+ classpathref="libraries"/>
+ </target>
+
+ <target name="copy-resources">
+ <copy todir="${targetdir}">
+ <fileset dir="${sourcedir}">
+ <exclude name="**/*.java"/>
+ </fileset>
+ </copy>
+ </target>
+
+</project>]]></programlisting>
+
+ <para>
+ This will tell Ant to add all files in the lib directory ending with <literal>.jar</literal>
+ to the classpath used for compilation. It will also copy all non-Java source files to the
+ target directory, e.g. configuration and Hibernate mapping files. If you now run Ant, you
+ should get this output:
+ </para>
+
+ <programlisting><![CDATA[C:\hibernateTutorial\>ant
+Buildfile: build.xml
+
+copy-resources:
+ [copy] Copying 2 files to C:\hibernateTutorial\bin
+
+compile:
+ [javac] Compiling 1 source file to C:\hibernateTutorial\bin
+
+BUILD SUCCESSFUL
+Total time: 1 second ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-helpers" revision="3">
+ <title>Startup and helpers</title>
+
+ <para>
+ It's time to load and store some <literal>Event</literal> objects, but first
+ we have to complete the setup with some infrastructure code. We have to startup
+ Hibernate. This startup includes building a global <literal>SessionFactory</literal>
+ object and to store it somewhere for easy access in application code.
+ A <literal>SessionFactory</literal> can open up new <literal>Session</literal>'s.
+ A <literal>Session</literal> represents a single-threaded unit of work, the
+ <literal>SessionFactory</literal> is a thread-safe global object, instantiated once.
+ </para>
+
+ <para>
+ We'll create a <literal>HibernateUtil</literal> helper class which takes care
+ of startup and makes accessing a <literal>SessionFactory</literal> convenient.
+ Let's have a look at the implementation:
+ </para>
+
+ <programlisting><![CDATA[package util;
+
+import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+
+ private static final SessionFactory sessionFactory;
+
+ static {
+ try {
+ // Create the SessionFactory from hibernate.cfg.xml
+ sessionFactory = new Configuration().configure().buildSessionFactory();
+ } catch (Throwable ex) {
+ // Make sure you log the exception, as it might be swallowed
+ System.err.println("Initial SessionFactory creation failed." + ex);
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ public static SessionFactory getSessionFactory() {
+ return sessionFactory;
+ }
+
+}]]></programlisting>
+
+ <para>
+ This class does not only produce the global <literal>SessionFactory</literal> in
+ its static initializer (called once by the JVM when the class is loaded), but also
+ hides the fact that it uses a static singleton. It might as well lookup the
+ <literal>SessionFactory</literal> from JNDI in an application server.
+ </para>
+
+ <para>
+ If you give the <literal>SessionFactory</literal> a name in your configuration
+ file, Hibernate will in fact try to bind it to JNDI after it has been built.
+ To avoid this code completely you could also use JMX deployment and let the
+ JMX-capable container instantiate and bind a <literal>HibernateService</literal>
+ to JNDI. These advanced options are discussed in the Hibernate reference
+ documentation.
+ </para>
+
+ <para>
+ Place <literal>HibernateUtil.java</literal> in the development source directory, in
+ a package next to <literal>events</literal>:
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ <Hibernate and third-party libraries>
++src
+ +events
+ Event.java
+ Event.hbm.xml
+ +util
+ HibernateUtil.java
+ hibernate.cfg.xml
++data
+build.xml]]></programlisting>
+
+ <para>
+ This should again compile without problems. We finally need to configure a logging
+ system - Hibernate uses commons logging and leaves you the choice between Log4j and
+ JDK 1.4 logging. Most developers prefer Log4j: copy <literal>log4j.properties</literal>
+ from the Hibernate distribution (it's in the <literal>etc/</literal> directory) to
+ your <literal>src</literal> directory, next to <literal>hibernate.cfg.xml</literal>.
+ Have a look at the example configuration and change the settings if you like to have
+ more verbose output. By default, only Hibernate startup message are shown on stdout.
+ </para>
+
+ <para>
+ The tutorial infrastructure is complete - and we are ready to do some real work with
+ Hibernate.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-workingpersistence" revision="4">
+ <title>Loading and storing objects</title>
+
+ <para>
+ Finally, we can use Hibernate to load and store objects. We write an
+ <literal>EventManager</literal> class with a <literal>main()</literal> method:
+ </para>
+
+ <programlisting><![CDATA[package events;
+import org.hibernate.Session;
+
+import java.util.Date;
+
+import util.HibernateUtil;
+
+public class EventManager {
+
+ public static void main(String[] args) {
+ EventManager mgr = new EventManager();
+
+ if (args[0].equals("store")) {
+ mgr.createAndStoreEvent("My Event", new Date());
+ }
+
+ HibernateUtil.getSessionFactory().close();
+ }
+
+ private void createAndStoreEvent(String title, Date theDate) {
+
+ Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+ session.beginTransaction();
+
+ Event theEvent = new Event();
+ theEvent.setTitle(title);
+ theEvent.setDate(theDate);
+
+ session.save(theEvent);
+
+ session.getTransaction().commit();
+ }
+
+}]]></programlisting>
+
+ <para>
+ We create a new <literal>Event</literal> object, and hand it over to Hibernate.
+ Hibernate now takes care of the SQL and executes <literal>INSERT</literal>s
+ on the database. Let's have a look at the <literal>Session</literal> and
+ <literal>Transaction</literal>-handling code before we run this.
+ </para>
+
+ <para>
+ A <literal>Session</literal> is a single unit of work. For now we'll keep things
+ simple and assume a one-to-one granularity between a Hibernate <literal>Session</literal>
+ and a database transaction. To shield our code from the actual underlying transaction
+ system (in this case plain JDBC, but it could also run with JTA) we use the
+ <literal>Transaction</literal> API that is available on the Hibernate <literal>Session</literal>.
+ </para>
+
+ <para>
+ What does <literal>sessionFactory.getCurrentSession()</literal> do? First, you can call it
+ as many times and anywhere you like, once you get hold of your <literal>SessionFactory</literal>
+ (easy thanks to <literal>HibernateUtil</literal>). The <literal>getCurrentSession()</literal>
+ method always returns the "current" unit of work. Remember that we switched the configuration
+ option for this mechanism to "thread" in <literal>hibernate.cfg.xml</literal>? Hence, the scope
+ of the current unit of work is the current Java thread that executes our application. However, this
+ is not the full truth. A <literal>Session</literal> begins when it is
+ first needed, when the first call to <literal>getCurrentSession()</literal> is made.
+ It is then bound by Hibernate to the current thread. When the transaction ends,
+ either committed or rolled back, Hibernate also unbinds the <literal>Session</literal>
+ from the thread and closes it for you. If you call <literal>getCurrentSession()</literal>
+ again, you get a new <literal>Session</literal> and can start a new unit of work. This
+ <emphasis>thread-bound</emphasis> programming model is the most popular way of using
+ Hibernate.
+ </para>
+
+ <para>
+ Have a look at <xref linkend="transactions"/> for more information
+ about transaction handling and demarcation. We also skipped any error handling and
+ rollback in the previous example.
+ </para>
+
+ <para>
+ To run this first routine we have to add a callable target to the Ant build file:
+ </para>
+
+ <programlisting><![CDATA[<target name="run" depends="compile">
+ <java fork="true" classname="events.EventManager" classpathref="libraries">
+ <classpath path="${targetdir}"/>
+ <arg value="${action}"/>
+ </java>
+</target>]]></programlisting>
+
+ <para>
+ The value of the <literal>action</literal> argument is set on the command line when
+ calling the target:
+ </para>
+
+ <programlisting><![CDATA[C:\hibernateTutorial\>ant run -Daction=store]]></programlisting>
+
+ <para>
+ You should see, after compilation, Hibernate starting up and, depending on your
+ configuration, lots of log output. At the end you will find the following line:
+ </para>
+
+ <programlisting><![CDATA[[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)]]></programlisting>
+
+ <para>
+ This is the <literal>INSERT</literal> executed by Hibernate, the question marks
+ represent JDBC bind parameters. To see the values bound as arguments, or to reduce
+ the verbosity of the log, check your <literal>log4j.properties</literal>.
+ </para>
+
+ <para>
+ Now we'd like to list stored events as well, so we add an option to the main method:
+ </para>
+
+ <programlisting><![CDATA[if (args[0].equals("store")) {
+ mgr.createAndStoreEvent("My Event", new Date());
+}
+else if (args[0].equals("list")) {
+ List events = mgr.listEvents();
+ for (int i = 0; i < events.size(); i++) {
+ Event theEvent = (Event) events.get(i);
+ System.out.println("Event: " + theEvent.getTitle() +
+ " Time: " + theEvent.getDate());
+ }
+}]]></programlisting>
+
+ <para>
+ We also add a new <literal>listEvents() method</literal>:
+ </para>
+
+ <programlisting><![CDATA[private List listEvents() {
+
+ Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+ session.beginTransaction();
+
+ List result = session.createQuery("from Event").list();
+
+ session.getTransaction().commit();
+
+ return result;
+}]]></programlisting>
+
+ <para>
+ What we do here is use an HQL (Hibernate Query Language) query to load all existing
+ <literal>Event</literal> objects from the database. Hibernate will generate the
+ appropriate SQL, send it to the database and populate <literal>Event</literal> objects
+ with the data. You can create more complex queries with HQL, of course.
+ </para>
+
+ <para>
+ Now, to execute and test all of this, follow these steps:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Run <literal>ant run -Daction=store</literal> to store something into the database
+ and, of course, to generate the database schema before through hbm2ddl.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Now disable hbm2ddl by commenting out the property in your <literal>hibernate.cfg.xml</literal>
+ file. Usually you only leave it turned on in continous unit testing, but another
+ run of hbm2ddl would <emphasis>drop</emphasis> everything you have stored - the
+ <literal>create</literal> configuration setting actually translates into "drop all
+ tables from the schema, then re-create all tables, when the SessionFactory is build".
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ If you now call Ant with <literal>-Daction=list</literal>, you should see the events
+ you have stored so far. You can of course also call the <literal>store</literal> action a few
+ times more.
+ </para>
+
+ <para>
+ 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>
+
+ <sect1 id="tutorial-associations">
+ <title>Part 2 - Mapping associations</title>
+
+ <para>
+ We mapped a persistent entity class to a table. Let's build on this and add some class associations.
+ First we'll add people to our application, and store a list of events they participate in.
+ </para>
+
+ <sect2 id="tutorial-associations-mappinguser" revision="1">
+ <title>Mapping the Person class</title>
+
+ <para>
+ The first cut of the <literal>Person</literal> class is simple:
+ </para>
+
+ <programlisting><![CDATA[package events;
+
+public class Person {
+
+ private Long id;
+ private int age;
+ private String firstname;
+ private String lastname;
+
+ public Person() {}
+
+ // Accessor methods for all properties, private setter for 'id'
+
+}]]></programlisting>
+
+ <para>
+ Create a new mapping file called <literal>Person.hbm.xml</literal> (don't forget the
+ DTD reference at the top):
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="events.Person" table="PERSON">
+ <id name="id" column="PERSON_ID">
+ <generator class="native"/>
+ </id>
+ <property name="age"/>
+ <property name="firstname"/>
+ <property name="lastname"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Finally, add the new mapping to Hibernate's configuration:
+ </para>
+
+ <programlisting><![CDATA[<mapping resource="events/Event.hbm.xml"/>
+<mapping resource="events/Person.hbm.xml"/>]]></programlisting>
+
+ <para>
+ We'll now create an association between these two entities. Obviously, persons
+ can participate in events, and events have participants. The design questions
+ we have to deal with are: directionality, multiplicity, and collection
+ behavior.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-unidirset" revision="3">
+ <title>A unidirectional Set-based association</title>
+
+ <para>
+ We'll add a collection of events to the <literal>Person</literal> class. That way we can
+ easily navigate to the events for a particular person, without executing an explicit query -
+ by calling <literal>aPerson.getEvents()</literal>. We use a Java collection, a <literal>Set</literal>,
+ because the collection will not contain duplicate elements and the ordering is not relevant for us.
+ </para>
+
+ <para>
+ We need a unidirectional, many-valued associations, implemented with a <literal>Set</literal>.
+ Let's write the code for this in the Java classes and then map it:
+ </para>
+
+ <programlisting><![CDATA[public class Person {
+
+ private Set events = new HashSet();
+
+ public Set getEvents() {
+ return events;
+ }
+
+ public void setEvents(Set events) {
+ this.events = events;
+ }
+}]]></programlisting>
+
+ <para>
+ Before we map this association, think about the other side. Clearly, we could just keep this
+ unidirectional. Or, we could create another collection on the <literal>Event</literal>, if we
+ want to be able to navigate it bi-directional, i.e. <literal>anEvent.getParticipants()</literal>.
+ This is not necessary, from a functional perspective. You could always execute an explicit query
+ to retrieve the participants for a particular event. This is a design choice left to you, but what
+ is clear from this discussion is the multiplicity of the association: "many" valued on both sides,
+ we call this a <emphasis>many-to-many</emphasis> association. Hence, we use Hibernate's
+ many-to-many mapping:
+ </para>
+
+ <programlisting><![CDATA[<class name="events.Person" table="PERSON">
+ <id name="id" column="PERSON_ID">
+ <generator class="native"/>
+ </id>
+ <property name="age"/>
+ <property name="firstname"/>
+ <property name="lastname"/>
+
+ <set name="events" table="PERSON_EVENT">
+ <key column="PERSON_ID"/>
+ <many-to-many column="EVENT_ID" class="events.Event"/>
+ </set>
+
+</class>]]></programlisting>
+
+ <para>
+ Hibernate supports all kinds of collection mappings, a <literal><set></literal> being most
+ common. For a many-to-many association (or <emphasis>n:m</emphasis> entity relationship), an
+ association table is needed. Each row in this table represents a link between a person and an event.
+ The table name is configured with the <literal>table</literal> attribute of the <literal>set</literal>
+ element. The identifier column name in the association, for the person's side, is defined with the
+ <literal><key></literal> element, the column name for the event's side with the
+ <literal>column</literal> attribute of the <literal><many-to-many></literal>. You also
+ have to tell Hibernate the class of the objects in your collection (correct: the class on the
+ other side of the collection of references).
+ </para>
+
+ <para>
+ The database schema for this mapping is therefore:
+ </para>
+
+ <programlisting><![CDATA[
+ _____________ __________________
+ | | | | _____________
+ | EVENTS | | PERSON_EVENT | | |
+ |_____________| |__________________| | PERSON |
+ | | | | |_____________|
+ | *EVENT_ID | <--> | *EVENT_ID | | |
+ | EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID |
+ | TITLE | |__________________| | AGE |
+ |_____________| | FIRSTNAME |
+ | LASTNAME |
+ |_____________|
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-working" revision="1">
+ <title>Working the association</title>
+
+ <para>
+ Let's bring some people and events together in a new method in <literal>EventManager</literal>:
+ </para>
+
+ <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+ Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+ session.beginTransaction();
+
+ Person aPerson = (Person) session.load(Person.class, personId);
+ Event anEvent = (Event) session.load(Event.class, eventId);
+
+ aPerson.getEvents().add(anEvent);
+
+ session.getTransaction().commit();
+}]]></programlisting>
+
+ <para>
+ After loading a <literal>Person</literal> and an <literal>Event</literal>, simply
+ modify the collection using the normal collection methods. As you can see, there is no explicit call
+ to <literal>update()</literal> or <literal>save()</literal>, Hibernate automatically
+ detects that the collection has been modified and needs to be updated. This is called <emphasis>automatic
+ dirty checking</emphasis>, and you can also try it by modifying the name or the date property of
+ any of your objects. As long as they are in <emphasis>persistent</emphasis> state, that is, bound
+ to a particular Hibernate <literal>Session</literal> (i.e. they have been just loaded or saved in
+ a unit of work), Hibernate monitors any changes and executes SQL in a write-behind fashion. The
+ process of synchronizing the memory state with the database, usually only at the end of a unit of
+ work, is called <emphasis>flushing</emphasis>. In our code, the unit of work ends with a commit
+ (or rollback) of the database transaction - as defined by the <literal>thread</literal> configuration
+ option for the <literal>CurrentSessionContext</literal> class.
+ </para>
+
+ <para>
+ You might of course load person and event in different units of work. Or you modify an object
+ outside of a <literal>Session</literal>, when it is not in persistent state (if it was persistent
+ before, we call this state <emphasis>detached</emphasis>). You can even modify a collection when
+ it is detached:
+ </para>
+
+ <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+ Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+ session.beginTransaction();
+
+ Person aPerson = (Person) session
+ .createQuery("select p from Person p left join fetch p.events where p.id = :pid")
+ .setParameter("pid", personId)
+ .uniqueResult(); // Eager fetch the collection so we can use it detached
+
+ Event anEvent = (Event) session.load(Event.class, eventId);
+
+ session.getTransaction().commit();
+
+ // End of first unit of work
+
+ aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached
+
+ // Begin second unit of work
+
+ Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
+ session2.beginTransaction();
+
+ session2.update(aPerson); // Reattachment of aPerson
+
+ session2.getTransaction().commit();
+}]]></programlisting>
+
+ <para>
+ The call to <literal>update</literal> makes a detached object persistent again, you could
+ say it binds it to a new unit of work, so any modifications you made to it while detached
+ can be saved to the database. This includes any modifications (additions/deletions) you
+ made to a collection of that entity object.
+ </para>
+
+ <para>
+ Well, this is not much use in our current situation, but it's an important concept you can
+ design into your own application. For now, complete this exercise by adding a new action
+ to the <literal>EventManager</literal>'s main method and call it from the command line. If
+ you need the identifiers of a person and an event - the <literal>save()</literal> method
+ returns it (you might have to modify some of the previous methods to return that identifier):
+ </para>
+
+ <programlisting><![CDATA[else if (args[0].equals("addpersontoevent")) {
+ Long eventId = mgr.createAndStoreEvent("My Event", new Date());
+ Long personId = mgr.createAndStorePerson("Foo", "Bar");
+ mgr.addPersonToEvent(personId, eventId);
+ System.out.println("Added person " + personId + " to event " + eventId);]]></programlisting>
+
+ <para>
+ This was an example of an association between two equally important classes, two entities.
+ As mentioned earlier, there are other classes and types in a typical model, usually "less
+ important". Some you have already seen, like an <literal>int</literal> or a <literal>String</literal>.
+ We call these classes <emphasis>value types</emphasis>, and their instances <emphasis>depend</emphasis>
+ on a particular entity. Instances of these types don't have their own identity, nor are they
+ shared between entities (two persons don't reference the same <literal>firstname</literal>
+ object, even if they have the same first name). Of course, value types can not only be found in
+ the JDK (in fact, in a Hibernate application all JDK classes are considered value types), but
+ you can also write dependent classes yourself, <literal>Address</literal> or <literal>MonetaryAmount</literal>,
+ for example.
+ </para>
+
+ <para>
+ You can also design a collection of value types. This is conceptually very different from a
+ collection of references to other entities, but looks almost the same in Java.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-valuecollections">
+ <title>Collection of values</title>
+
+ <para>
+ We add a collection of value typed objects to the <literal>Person</literal> entity. We want to
+ store email addresses, so the type we use is <literal>String</literal>, and the collection is
+ again a <literal>Set</literal>:
+ </para>
+ <programlisting><![CDATA[private Set emailAddresses = new HashSet();
+
+public Set getEmailAddresses() {
+ return emailAddresses;
+}
+
+public void setEmailAddresses(Set emailAddresses) {
+ this.emailAddresses = emailAddresses;
+}]]></programlisting>
+
+ <para>
+ The mapping of this <literal>Set</literal>:
+ </para>
+
+ <programlisting><![CDATA[<set name="emailAddresses" table="PERSON_EMAIL_ADDR">
+ <key column="PERSON_ID"/>
+ <element type="string" column="EMAIL_ADDR"/>
+</set>]]></programlisting>
+
+ <para>
+ The difference compared with the earlier mapping is the <literal>element</literal> part, which tells Hibernate that the collection
+ does not contain references to another entity, but a collection of elements of type
+ <literal>String</literal> (the lowercase name tells you it's a Hibernate mapping type/converter).
+ Once again, the <literal>table</literal> attribute of the <literal>set</literal> element determines
+ the table name for the collection. The <literal>key</literal> element defines the foreign-key column
+ name in the collection table. The <literal>column</literal> attribute in the <literal>element</literal>
+ element defines the column name where the <literal>String</literal> values will actually be stored.
+ </para>
+
+ <para>
+ Have a look at the updated schema:
+ </para>
+
+ <programlisting><![CDATA[
+ _____________ __________________
+ | | | | _____________
+ | EVENTS | | PERSON_EVENT | | | ___________________
+ |_____________| |__________________| | PERSON | | |
+ | | | | |_____________| | PERSON_EMAIL_ADDR |
+ | *EVENT_ID | <--> | *EVENT_ID | | | |___________________|
+ | EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID | <--> | *PERSON_ID |
+ | TITLE | |__________________| | AGE | | *EMAIL_ADDR |
+ |_____________| | FIRSTNAME | |___________________|
+ | LASTNAME |
+ |_____________|
+ ]]></programlisting>
+
+ <para>
+ You can see that the primary key of the collection table is in fact a composite key,
+ using both columns. This also implies that there can't be duplicate email addresses
+ per person, which is exactly the semantics we need for a set in Java.
+ </para>
+
+ <para>
+ You can now try and add elements to this collection, just like we did before by
+ linking persons and events. It's the same code in Java:
+ </para>
+
+ <programlisting><![CDATA[private void addEmailToPerson(Long personId, String emailAddress) {
+
+ Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+ session.beginTransaction();
+
+ Person aPerson = (Person) session.load(Person.class, personId);
+
+ // The getEmailAddresses() might trigger a lazy load of the collection
+ aPerson.getEmailAddresses().add(emailAddress);
+
+ session.getTransaction().commit();
+}]]></programlisting>
+
+ <para>
+ This time we didnt' use a <emphasis>fetch</emphasis> query to initialize the collection.
+ Hence, the call to its getter method will trigger an additional select to initialize
+ it, so we can add an element to it. Monitor the SQL log and try to optimize this with
+ an eager fetch.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-bidirectional" revision="1">
+ <title>Bi-directional associations</title>
+
+ <para>
+ Next we are going to map a bi-directional association - making the association between
+ person and event work from both sides in Java. Of course, the database schema doesn't
+ change, we still have many-to-many multiplicity. A relational database is more flexible
+ than a network programming language, so it doesn't need anything like a navigation
+ direction - data can be viewed and retrieved in any possible way.
+ </para>
+
+ <para>
+ First, add a collection of participants to the <literal>Event</literal> Event class:
+ </para>
+
+ <programlisting><![CDATA[private Set participants = new HashSet();
+
+public Set getParticipants() {
+ return participants;
+}
+
+public void setParticipants(Set participants) {
+ this.participants = participants;
+}]]></programlisting>
+
+ <para>
+ Now map this side of the association too, in <literal>Event.hbm.xml</literal>.
+ </para>
+
+ <programlisting><![CDATA[<set name="participants" table="PERSON_EVENT" inverse="true">
+ <key column="EVENT_ID"/>
+ <many-to-many column="PERSON_ID" class="events.Person"/>
+</set>]]></programlisting>
+
+ <para>
+ As you see, these are normal <literal>set</literal> mappings in both mapping documents.
+ Notice that the column names in <literal>key</literal> and <literal>many-to-many</literal> are
+ swapped in both mapping documents. The most important addition here is the
+ <literal>inverse="true"</literal> attribute in the <literal>set</literal> element of the
+ <literal>Event</literal>'s collection mapping.
+ </para>
+
+ <para>
+ What this means is that Hibernate should take the other side - the <literal>Person</literal> class -
+ when it needs to find out information about the link between the two. This will be a lot easier to
+ understand once you see how the bi-directional link between our two entities is created .
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-usingbidir">
+ <title>Working bi-directional links</title>
+
+ <para>
+ First, keep in mind that Hibernate does not affect normal Java semantics. How did we create a
+ link between a <literal>Person</literal> and an <literal>Event</literal> in the unidirectional
+ example? We added an instance of <literal>Event</literal> to the collection of event references,
+ of an instance of <literal>Person</literal>. So, obviously, if we want to make this link working
+ bi-directional, we have to do the same on the other side - adding a <literal>Person</literal>
+ reference to the collection in an <literal>Event</literal>. This "setting the link on both sides"
+ is absolutely necessary and you should never forget doing it.
+ </para>
+
+ <para>
+ Many developers program defensive and create a link management methods to
+ correctly set both sides, e.g. in <literal>Person</literal>:
+ </para>
+
+ <programlisting><![CDATA[protected Set getEvents() {
+ return events;
+}
+
+protected void setEvents(Set events) {
+ this.events = events;
+}
+
+public void addToEvent(Event event) {
+ this.getEvents().add(event);
+ event.getParticipants().add(this);
+}
+
+public void removeFromEvent(Event event) {
+ this.getEvents().remove(event);
+ event.getParticipants().remove(this);
+}]]></programlisting>
+
+ <para>
+ Notice that the get and set methods for the collection are now protected - this allows classes in the
+ same package and subclasses to still access the methods, but prevents everybody else from messing
+ with the collections directly (well, almost). You should probably do the same with the collection
+ on the other side.
+ </para>
+
+ <para>
+ What about the <literal>inverse</literal> mapping attribute? For you, and for Java, a bi-directional
+ link is simply a matter of setting the references on both sides correctly. Hibernate however doesn't
+ have enough information to correctly arrange SQL <literal>INSERT</literal> and <literal>UPDATE</literal>
+ statements (to avoid constraint violations), and needs some help to handle bi-directional associations
+ properly. Making one side of the association <literal>inverse</literal> tells Hibernate to basically
+ ignore it, to consider it a <emphasis>mirror</emphasis> of the other side. That's all that is necessary
+ for Hibernate to work out all of the issues when transformation a directional navigation model to
+ a SQL database schema. The rules you have to remember are straightforward: All bi-directional associations
+ need one side as <literal>inverse</literal>. In a one-to-many association it has to be the many-side,
+ in many-to-many association you can pick either side, there is no difference.
+ </para>
+
+ </sect2>
+
+ <para>
+ Let's turn this into a small web application.
+ </para>
+
+ </sect1>
+
+ <sect1 id="tutorial-webapp">
+ <title>Part 3 - The EventManager web application</title>
+
+ <para>
+ A Hibernate web application uses <literal>Session</literal> and <literal>Transaction</literal>
+ almost like a standalone application. However, some common patterns are useful. We now write
+ an <literal>EventManagerServlet</literal>. This servlet can list all events stored in the
+ database, and it provides an HTML form to enter new events.
+ </para>
+
+ <sect2 id="tutorial-webapp-servlet" revision="1">
+ <title>Writing the basic servlet</title>
+
+ <para>
+ Create a new class in your source directory, in the <literal>events</literal>
+ package:
+ </para>
+
+ <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,
+ HttpServletResponse response)
+ throws ServletException, IOException {
+
+ SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");
+
+ try {
+ // Begin unit of work
+ HibernateUtil.getSessionFactory()
+ .getCurrentSession().beginTransaction();
+
+ // Process request and render page...
+
+ // End unit of work
+ HibernateUtil.getSessionFactory()
+ .getCurrentSession().getTransaction().commit();
+
+ } catch (Exception ex) {
+ HibernateUtil.getSessionFactory()
+ .getCurrentSession().getTransaction().rollback();
+ throw new ServletException(ex);
+ }
+
+}]]></programlisting>
+
+ <para>
+ The pattern we are applying here is called <emphasis>session-per-request</emphasis>.
+ When a request hits the servlet, a new Hibernate <literal>Session</literal> is
+ opened through the first call to <literal>getCurrentSession()</literal> on the
+ <literal>SessionFactory</literal>. Then a database transaction is started—all
+ data access as to occur inside a transaction, no matter if data is read or written
+ (we don't use the auto-commit mode in applications).
+ </para>
+
+ <para>
+ Next, the possible actions of the request are processed and the response HTML
+ is rendered. We'll get to that part soon.
+ </para>
+
+ <para>
+ Finally, the unit of work ends when processing and rendering is complete. If any
+ problem occured during processing or rendering, an exception will be thrown
+ and the database transaction rolled back. This completes the
+ <literal>session-per-request</literal> pattern. Instead of the transaction
+ demarcation code in every servlet you could also write a servlet filter.
+ See the Hibernate website and Wiki for more information about this pattern,
+ called <emphasis>Open Session in View</emphasis>—you'll need it as soon
+ as you consider rendering your view in JSP, not in a servlet.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-webapp-processing" revision="1">
+ <title>Processing and rendering</title>
+
+ <para>
+ Let's implement the processing of the request and rendering of the page.
+ </para>
+
+<programlisting><![CDATA[// Write HTML header
+PrintWriter out = response.getWriter();
+out.println("<html><head><title>Event Manager</title></head><body>");
+
+// Handle actions
+if ( "store".equals(request.getParameter("action")) ) {
+
+ String eventTitle = request.getParameter("eventTitle");
+ String eventDate = request.getParameter("eventDate");
+
+ if ( "".equals(eventTitle) || "".equals(eventDate) ) {
+ out.println("<b><i>Please enter event title and date.</i></b>");
+ } else {
+ createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
+ out.println("<b><i>Added event.</i></b>");
+ }
+}
+
+// Print page
+printEventForm(out);
+listEvents(out, dateFormatter);
+
+// Write HTML footer
+out.println("</body></html>");
+out.flush();
+out.close();]]></programlisting>
+
+ <para>
+ Granted, this coding style with a mix of Java and HTML would not scale
+ in a more complex application—keep in mind that we are only illustrating
+ basic Hibernate concepts in this tutorial. The code prints an HTML
+ header and a footer. Inside this page, an HTML form for event entry and
+ a list of all events in the database are printed. The first method is
+ trivial and only outputs HTML:
+ </para>
+
+ <programlisting><![CDATA[private void printEventForm(PrintWriter out) {
+ out.println("<h2>Add new event:</h2>");
+ out.println("<form>");
+ out.println("Title: <input name='eventTitle' length='50'/><br/>");
+ out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>");
+ out.println("<input type='submit' name='action' value='store'/>");
+ out.println("</form>");
+}]]></programlisting>
+
+ <para>
+ The <literal>listEvents()</literal> method uses the Hibernate
+ <literal>Session</literal> bound to the current thread to execute
+ a query:
+ </para>
+
+ <programlisting><![CDATA[private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) {
+
+ List result = HibernateUtil.getSessionFactory()
+ .getCurrentSession().createCriteria(Event.class).list();
+ if (result.size() > 0) {
+ out.println("<h2>Events in database:</h2>");
+ out.println("<table border='1'>");
+ out.println("<tr>");
+ out.println("<th>Event title</th>");
+ out.println("<th>Event date</th>");
+ out.println("</tr>");
+ for (Iterator it = result.iterator(); it.hasNext();) {
+ Event event = (Event) it.next();
+ out.println("<tr>");
+ out.println("<td>" + event.getTitle() + "</td>");
+ out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");
+ out.println("</tr>");
+ }
+ out.println("</table>");
+ }
+}]]></programlisting>
+
+ <para>
+ Finally, the <literal>store</literal> action is dispatched to the
+ <literal>createAndStoreEvent()</literal> method, which also uses
+ the <literal>Session</literal> of the current thread:
+ </para>
+
+ <programlisting><![CDATA[protected void createAndStoreEvent(String title, Date theDate) {
+ Event theEvent = new Event();
+ theEvent.setTitle(title);
+ theEvent.setDate(theDate);
+
+ HibernateUtil.getSessionFactory()
+ .getCurrentSession().save(theEvent);
+}]]></programlisting>
+
+ <para>
+ That's it, the servlet is complete. A request to the servlet will be processed
+ in a single <literal>Session</literal> and <literal>Transaction</literal>. As
+ earlier in the standalone application, Hibernate can automatically bind these
+ ojects to the current thread of execution. This gives you the freedom to layer
+ your code and access the <literal>SessionFactory</literal> in any way you like.
+ Usually you'd use a more sophisticated design and move the data access code
+ into data access objects (the DAO pattern). See the Hibernate Wiki for more
+ examples.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-webapp-deploy">
+ <title>Deploying and testing</title>
+
+ <para>
+ To deploy this application you have to create a web archive, a WAR. Add the
+ following Ant target to your <literal>build.xml</literal>:
+ </para>
+
+<programlisting><![CDATA[<target name="war" depends="compile">
+ <war destfile="hibernate-tutorial.war" webxml="web.xml">
+ <lib dir="${librarydir}">
+ <exclude name="jsdk*.jar"/>
+ </lib>
+
+ <classes dir="${targetdir}"/>
+ </war>
+</target>]]></programlisting>
+
+ <para>
+ This target creates a file called <literal>hibernate-tutorial.war</literal>
+ in your project directory. It packages all libraries and the <literal>web.xml</literal>
+ descriptor, which is expected in the base directory of your project:
+ </para>
+
+ <programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4"
+ xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+ <servlet>
+ <servlet-name>Event Manager</servlet-name>
+ <servlet-class>events.EventManagerServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Event Manager</servlet-name>
+ <url-pattern>/eventmanager</url-pattern>
+ </servlet-mapping>
+</web-app>]]></programlisting>
+
+ <para>
+ Before you compile and deploy the web application, note that an additional library
+ is required: <literal>jsdk.jar</literal>. This is the Java servlet development kit,
+ if you don't have this library already, get it from the Sun website and copy it to
+ your library directory. However, it will be only used for compliation and excluded
+ from the WAR package.
+ </para>
+
+ <para>
+ To build and deploy call <literal>ant war</literal> in your project directory
+ and copy the <literal>hibernate-tutorial.war</literal> file into your Tomcat
+ <literal>webapp</literal> directory. If you don't have Tomcat installed, download
+ it and follow the installation instructions. You don't have to change any Tomcat
+ configuration to deploy this application though.
+ </para>
+
+ <para>
+ Once deployed and Tomcat is running, access the application at
+ <literal>http://localhost:8080/hibernate-tutorial/eventmanager</literal>. Make
+ sure you watch the Tomcat log to see Hibernate initialize when the first
+ request hits your servlet (the static initializer in <literal>HibernateUtil</literal>
+ is called) and to get the detailed output if any exceptions occurs.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="tutorial-summary" revision="1">
+ <title>Summary</title>
+
+ <para>
+ This tutorial covered the basics of writing a simple standalone Hibernate application
+ and a small web application.
+ </para>
+
+ <para>
+ If you already feel confident with Hibernate, continue browsing through the reference
+ documentation table of contents for topics you find interesting - most asked are
+ transactional processing (<xref linkend="transactions"/>), fetch
+ performance (<xref linkend="performance"/>), or the usage of the API (<xref linkend="objectstate"/>)
+ and the query features (<xref linkend="objectstate-querying"/>).
+ </para>
+
+ <para>
+ Don't forget to check the Hibernate website for more (specialized) tutorials.
+ </para>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/xml.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/xml.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/docbook/modules/xml.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,288 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+
+<chapter id="xml">
+ <title>XML Mapping</title>
+
+ <para><emphasis>
+ Note that this is an experimental feature in Hibernate 3.0 and is under
+ extremely active development.
+ </emphasis></para>
+
+ <sect1 id="xml-intro" revision="1">
+ <title>Working with XML data</title>
+
+ <para>
+ Hibernate lets you work with persistent XML data in much the same way
+ you work with persistent POJOs. A parsed XML tree can be thought of
+ as just another way to represent the relational data at the object level,
+ instead of POJOs.
+ </para>
+
+ <para>
+ Hibernate supports dom4j as API for manipulating XML trees. You can write
+ queries that retrieve dom4j trees from the database and have any
+ modification you make to the tree automatically synchronized to the
+ database. You can even take an XML document, parse it using dom4j, and
+ write it to the database with any of Hibernate's basic operations:
+ <literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal>
+ (merging is not yet supported).
+ </para>
+
+ <para>
+ This feature has many applications including data import/export,
+ externalization of entity data via JMS or SOAP and XSLT-based reporting.
+ </para>
+
+ <para>
+ A single mapping may be used to simultaneously map properties of a class
+ and nodes of an XML document to the database, or, if there is no class to map,
+ it may be used to map just the XML.
+ </para>
+
+ <sect2 id="xml-intro-mapping">
+ <title>Specifying XML and class mapping together</title>
+
+ <para>
+ Here is an example of mapping a POJO and XML simultaneously:
+ </para>
+
+ <programlisting><![CDATA[<class name="Account"
+ table="ACCOUNTS"
+ node="account">
+
+ <id name="accountId"
+ column="ACCOUNT_ID"
+ node="@id"/>
+
+ <many-to-one name="customer"
+ column="CUSTOMER_ID"
+ node="customer/@id"
+ embed-xml="false"/>
+
+ <property name="balance"
+ column="BALANCE"
+ node="balance"/>
+
+ ...
+
+</class>]]></programlisting>
+ </sect2>
+
+ <sect2 id="xml-onlyxml">
+ <title>Specifying only an XML mapping</title>
+
+ <para>
+ Here is an example where there is no POJO class:
+ </para>
+
+ <programlisting><![CDATA[<class entity-name="Account"
+ table="ACCOUNTS"
+ node="account">
+
+ <id name="id"
+ column="ACCOUNT_ID"
+ node="@id"
+ type="string"/>
+
+ <many-to-one name="customerId"
+ column="CUSTOMER_ID"
+ node="customer/@id"
+ embed-xml="false"
+ entity-name="Customer"/>
+
+ <property name="balance"
+ column="BALANCE"
+ node="balance"
+ type="big_decimal"/>
+
+ ...
+
+</class>]]></programlisting>
+
+ <para>
+ This mapping allows you to access the data as a dom4j tree, or as a graph of
+ property name/value pairs (java <literal>Map</literal>s). The property names
+ are purely logical constructs that may be referred to in HQL queries.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="xml-mapping" revision="1">
+ <title>XML mapping metadata</title>
+
+ <para>
+ Many Hibernate mapping elements accept the <literal>node</literal> attribute.
+ This let's you specify the name of an XML attribute or element that holds the
+ property or entity data. The format of the <literal>node</literal> attribute
+ must be one of the following:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para><literal>"element-name"</literal> - map to the named XML element</para>
+ </listitem>
+ <listitem>
+ <para><literal>"@attribute-name"</literal> - map to the named XML attribute</para>
+ </listitem>
+ <listitem>
+ <para><literal>"."</literal> - map to the parent element</para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>"element-name/@attribute-name"</literal> -
+ map to the named attribute of the named element
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ For collections and single valued associations, there is an additional
+ <literal>embed-xml</literal> attribute. If <literal>embed-xml="true"</literal>,
+ the default, the XML tree for the associated entity (or collection of value type)
+ will be embedded directly in the XML tree for the entity that owns the association.
+ Otherwise, if <literal>embed-xml="false"</literal>, then only the referenced
+ identifier value will appear in the XML for single point associations and
+ collections will simply not appear at all.
+ </para>
+
+ <para>
+ You should be careful not to leave <literal>embed-xml="true"</literal> for
+ too many associations, since XML does not deal well with circularity!
+ </para>
+
+ <programlisting><![CDATA[<class name="Customer"
+ table="CUSTOMER"
+ node="customer">
+
+ <id name="id"
+ column="CUST_ID"
+ node="@id"/>
+
+ <map name="accounts"
+ node="."
+ embed-xml="true">
+ <key column="CUSTOMER_ID"
+ not-null="true"/>
+ <map-key column="SHORT_DESC"
+ node="@short-desc"
+ type="string"/>
+ <one-to-many entity-name="Account"
+ embed-xml="false"
+ node="account"/>
+ </map>
+
+ <component name="name"
+ node="name">
+ <property name="firstName"
+ node="first-name"/>
+ <property name="initial"
+ node="initial"/>
+ <property name="lastName"
+ node="last-name"/>
+ </component>
+
+ ...
+
+</class>]]></programlisting>
+
+ <para>
+ in this case, we have decided to embed the collection of account ids, but not
+ the actual account data. The following HQL query:
+ </para>
+
+ <programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
+
+ <para>
+ Would return datasets such as this:
+ </para>
+
+ <programlisting><![CDATA[<customer id="123456789">
+ <account short-desc="Savings">987632567</account>
+ <account short-desc="Credit Card">985612323</account>
+ <name>
+ <first-name>Gavin</first-name>
+ <initial>A</initial>
+ <last-name>King</last-name>
+ </name>
+ ...
+</customer>]]></programlisting>
+
+ <para>
+ If you set <literal>embed-xml="true"</literal> on the <literal><one-to-many></literal>
+ mapping, the data might look more like this:
+ </para>
+
+ <programlisting><![CDATA[<customer id="123456789">
+ <account id="987632567" short-desc="Savings">
+ <customer id="123456789"/>
+ <balance>100.29</balance>
+ </account>
+ <account id="985612323" short-desc="Credit Card">
+ <customer id="123456789"/>
+ <balance>-2370.34</balance>
+ </account>
+ <name>
+ <first-name>Gavin</first-name>
+ <initial>A</initial>
+ <last-name>King</last-name>
+ </name>
+ ...
+</customer>]]></programlisting>
+
+ </sect1>
+
+
+ <sect1 id="xml-manipulation" revision="1">
+ <title>Manipulating XML data</title>
+
+ <para>
+ Let's rearead and update XML documents in the application. We do this by
+ obtaining a dom4j session:
+ </para>
+
+ <programlisting><![CDATA[Document doc = ....;
+
+Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+List results = dom4jSession
+ .createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName")
+ .list();
+for ( int i=0; i<results.size(); i++ ) {
+ //add the customer data to the XML document
+ Element customer = (Element) results.get(i);
+ doc.add(customer);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ <programlisting><![CDATA[Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+Element cust = (Element) dom4jSession.get("Customer", customerId);
+for ( int i=0; i<results.size(); i++ ) {
+ Element customer = (Element) results.get(i);
+ //change the customer name in the XML and database
+ Element name = customer.element("name");
+ name.element("first-name").setText(firstName);
+ name.element("initial").setText(initial);
+ name.element("last-name").setText(lastName);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ It is extremely useful to combine this feature with Hibernate's <literal>replicate()</literal>
+ operation to implement XML-based data import/export.
+ </para>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/css/html.css
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/css/html.css (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/css/html.css 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,97 @@
+A {
+ color: #003399;
+}
+
+A:active {
+ color: #003399;
+}
+
+A:visited {
+ color: #888888;
+}
+
+P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE {
+ color: #000000;
+}
+
+TD, TH, SPAN {
+ color: #000000;
+}
+
+BLOCKQUOTE {
+ margin-right: 0px;
+}
+
+
+H1, H2, H3, H4, H5, H6 {
+ color: #000000;
+ font-weight:500;
+ margin-top:10px;
+ padding-top:15px;
+}
+
+TABLE {
+ border-collapse: collapse;
+ border-spacing:0;
+ border: 1px thin black;
+ empty-cells: hide;
+}
+
+TD {
+ padding: 4pt;
+}
+
+H1 { font-size: 150%; }
+H2 { font-size: 140%; }
+H3 { font-size: 110%; font-weight: bold; }
+H4 { font-size: 110%; font-weight: bold;}
+H5 { font-size: 100%; font-style: italic; }
+H6 { font-size: 100%; font-style: italic; }
+
+TT {
+font-size: 90%;
+ font-family: "Courier New", Courier, monospace;
+ color: #000000;
+}
+
+PRE {
+font-size: 100%;
+ padding: 5px;
+ border-style: solid;
+ border-width: 1px;
+ border-color: #CCCCCC;
+ background-color: #F4F4F4;
+}
+
+UL, OL, LI {
+ list-style: disc;
+}
+
+HR {
+ width: 100%;
+ height: 1px;
+ background-color: #CCCCCC;
+ border-width: 0px;
+ padding: 0px;
+ color: #CCCCCC;
+}
+
+.variablelist {
+ padding-top: 10;
+ padding-bottom:10;
+ margin:0;
+}
+
+.itemizedlist, UL {
+ padding-top: 0;
+ padding-bottom:0;
+ margin:0;
+}
+
+.term {
+ font-weight:bold;
+}
+
+
+
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/AuthorWork.gif
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/AuthorWork.gif (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/AuthorWork.gif 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,62 @@
+GIF89aüñ
+Ä¢ñL*̦ó J§ÔªõÍj·Ü®÷Çä²ùN«×ì¶û
+ËçôºýÏë÷ü¾ÿ(8HXhx¨¸ÈØèø)9IYiy©¹ÉÙéù *:JZjzªºÊÚêú
++;K[k{«»ËÛëû,<L\l|¬¼ÌÜìü-=M]m}½ÍÝíý
+.>N^n~®¾ÎÞî/?O_o¯¿ÏßïÿoÀ<x0
+Â
:)+Z¼1£Æþ;zü2$Æ
+r(£¢H:U©Ô
+Ó§T«
+Uh5ëѨ¦jýj+¯`Ëþ¬Ùµ"ÑRË6nN·XåÚåéò®^tÁ-{30Ç¿lû!\±
+¸a})²8`zêɨâ¦Ùeá!ÆÄÔtÞ·#`ûÉ&Ô°8d %K'FIåU/VÉ MXn¹Q^üÈåS^NfÄÙh&crQf¶éffhÆIå£Ñ¥P´§Oö¥Â
+ NðIhHÒh¢¥MéhcWF*[D]i¦
+ ¤i§~:B Jê?sRª_¨¦zتþéê]^«ÖÔ¬ªâÊ*òú®Jü
+ìb§RxþY±0 K¦FA¦¬dƸbFÄBÉì%mJÙF±-´Ý§µâk,¬B-ù,æçºéÂã,»Ô)½À~kgúâ/¼þ9ÊïXõ¶8RÜQ¨lÁìa .|m¯eøðºÓ¨Ãj`±ÆØÇL\Ä#«ÉA Ìð+gL§Ë·ú73IJÍI´¦$Íîβ«>û
+3yCûÞ'?æÁíSàê¡´Õ
+1^ÓDÁ+¥? Z$È$!±': XØöµËsÖÚÆÃ$jA"ü×2øM9y£$îÌ0.8¬ÆJÔ4ÃL:à µ ¦icûáþ»Ä:Ý7íâ"ÅεDódQNêÜ3EµÍhD`=EÀ
:z¡ñÔ(6ÿåiu$ú8¢<ZlIÓ!í§2<*ÍË«I÷äÈøu][kQùÉ4=bË1ª$yÈEVèXMª"(ï#Hý±Nf©DäÞÖȳ*½`$1YI".îxaÛxɶï)o¡ÑM0{èK
+`3ýqHÐGYFçðqÚ3;ÐaþGÔ{LÿÚHLõó]p ün¸ÎN|gJ'=å£Þ5Ùܧ·¸éO~úèI9Ê;{"tziQ8þûvÐ
èøPUÚ¤TíèB8åÑôD¹ÞHO
+ªV(mi?VÊÊôýæ`j=âÔ¦%`^F¦Òò´8hC¸Ó ¦wÜNbF¾Èî¨QÞ.I6`É㧴ÕuµKShûîÕT¹½¬Y-£ùÖ&`ò쪮âO¡Ö$uñB]óÕWYæ¬Û<È×uAuÓ¥[Y)ÍV±¼á¾Å¦2KÃÏÕN·h6¶gh+ò±4hq&Õ²&Y5=p6sÞl+ÐÚÄ¢q¨
,g÷ÈY
sµ#ã+iÃþv\YiÕ·Q%-lÛÌÛJR
}_$×-V׺
+D!vg½¸uQ¬°¬ZiÍ«h~ïÛKØ{Q±¼¦L.zå©Z 6qH´o}7)ÉøÍoº$0IpB;òndßh#ÆßÊN;
+n<Ý(:Ø»HÕï|Ïû\Qbs\ã¹V®úñü=¬c7"Ò
+ÁaæXÃëC«í¸Ãwrmn¼áîVõ¶9¾°áZJ¸*1`,¾+ozgeW
Þ1x/l*xÆc>pµ$#
+Ì2^²½|V©Q¹ý´kaÎ\¨ëÉdærÙÌþ=%9뤩9³L.¿9Àns«:<oEÒ«sQjæowÏî÷hÂ&oÚ§fè«êNP¿Õ|³P*Ñ¡Â
+í{ÿÝ^M¶Ç7màÿöw¿ï·úÐ¸Æ kWÌØo9àù2Úì×°Ïó´$~EÄzÐâ$záÊn¬Á»¼Ð¥¹Ø>{pþiKE¾pÌ>|Z;VÙj}>%5öb_ÛsæR¸£kz]K3¤û×ä·²:Þ°^4{ÒHYs³(vSãþ0}'+õßóä§ämØçzÞÿr®ìUdeÓ>õk+Þní~óîp²=äCVúá·®ïÒñ=Å'îeõŶ½qѲ«ÒÌ0SY®9åûyó#·ææ_Èz²U(q 4µ'\ö¤ò-ËÞÿí>~wO+9_w¸½?é-ÍWí:}ÚRøßÍócýäeÿeÝÇ4ñ=þT_ð,¿A¯¿ýÍþÀ4ýÁs²Ïïkú_`ýì¬6ú¿_láW<ú§^¹'g'Q>Æ
+WL9G¸EØ15G¢{÷CG´
æUG|aH
+7Üòpd´xxE˸w§Wçr)BG1tBIX_1§wo?ÖWë±Xt~q5|ÈzÇAåÈôA
W-78Bv¶:2uÄTW\UèpÊt_MñàÄsÎE
+uõ%z·t·
gÄXÙÑCrgE9BYcø9ùeuPÈKhØJM²p'3ºM¨´ÒôKt3+{ ×0$W\:8p~×[¿³þ\[èt:ès
§wT¨#(uj´-§V£Øx#&öF
Ly5]uµÓ6ÇT#vx7¤èyå`hwØ_¾ZL8^E'c7a¦¥ÇSX'6^>7
+öA8>WØqP¶o8¸R¸UøKväÊ8ÕKÆäzcÅhWOÜ·TÐ0è;e(Á¾
xÉ~mp
+H:þ(Ef]¢¦FöÇÛã~ù
+¥órQؤ÷bzqÉ<¥~4"bDÖXÖnp¨¦»©zæã-DôðH¡KZkP-ÉxºtH¸7g@:N¥ÍT¨yꧡ3{Ü?k½Æ/I;z:þlû(nD';imzºO[©Éö§¢ú©Z=f¦zeª%5S³+ù ïЮzªøGºç& Gª{;W;³§¬ n
+ç£ö¨E6Joêéi
k¬ú¬PXBx<Ø"TC=È{Õ½Ù´HpgßêgXÏh;¨ly¹Öz©ýU°¦y°¯[ Xqm(Ø9êdØ8Çtb¢Öò+Û°ð`(±¾U%(tÇÇ®Cv¡Ïi¤§¯Ô $%;'[t8*¿W/þ»4J3k:+Ó³®âÈ¥'çʯñ8t¦ÿ2Gå*£¬Gy={¯KûMI6U{¨_«b;¶IÍê:¥¬âãjë¼ °
+~tÛ£Êy¨úzË|«f¾Zjs¸i·Jú1Gy¸y ¸@)´Û¸xð¸×ê·9¹¸Ë%¹ëxDùÆxˬer-J²Ë(}é¯õæccº»XY${ »ËX꺨rx¨Y®o%$*GrV®:LÂË9¤9¯04Ôk¥D¦²;¹ÁÛB2K2)ëxÚk®a6{þVËÌ»1$ê!AU§Å³Õ,àûºí¹¦ó;µ8ÀtMú±k^WH_×±h yÃjZzX"ûvù«¿¹» 8ê¾%úJ¢Iú¶,¯];´
+\³'Âü½à«Á;K¾ZæÕÁ÷ÁÐ+¤»Ø£F´ÈxÃÂÁˤXhÃQ¶»XWrÝ£C,ûÃX[bÊk\d±¤µ×{
uZÁn»,ºQ3Y|¹%ÃŨóÅáÑVb¹K¸Öî[¹ÇÊ«Æk|¸JOoü¹q|JÇu<´*È£ÇrÈ~1ÀÇswÈТÇ@øǼþ¶øÈ
+ZJhÊÖ;q(
©e¬´«ÌʯÚ,¾LÊq=ë¿®ä±ô«ÌËw`>TÐÌ £±öɲmJøËÌÌú!GvÍÿ+ëÍÛ¢'Óv:s1;uÒÃ-9ç\.ëüOdÑù¾»åÉô¿ g¨ôÜÆ[1¨VéM.KÐvÜÊÞv¦¥
+²·ÎÚÐÚÒ)ѪmeÉ<©ýÑ, <H$í+&Él¬ÒðÀÒ¶ºª/Í(1=±JÓÚbÓ9þ-;п[Ísy£l¶ÊìÓk
+ÚºÝÒÂÜ´!ÛÐêÒÍý7ÏílÝ!ÝÎÜÙÍÝÝLÝÝ
+ÞÁóÝáMÞ:
+ß´ôÞñMß:ßõß"pÞùÍß9tßý
+àê÷ßNà°ßàú=à Îàò³à
+áv!NáÛóààáÎá®á.ânVÜ#nâlVâ'®â!®âÎâ-á/ã.ã3á5nãã9à;Îãîã?àA.äüMäEÞ×ä
+îäjåmcSNå¿jßX¾´UÞ§!¹äÅåàåãÛc^YVÑýwæòæj.Æçr®
+ʽüÜæÃç§Àæ=÷YfKPè¨h}±oøæ¶þgç¾²B¤þç|©oNé¦@k&ÒNv TSí'>
+Ê÷Ï|ê6inê§ê¡@Ñ<I£îIºlT³þ "Ùç~.ê¶Á¡^Ìë PæÀîêÂNÂÙ\ìpìöè²gÅ¥ÊØìÆ®åÑè×Î Ïîè·èÜîìaNîù0w.îÝíà;é¾ ÞnÎÚ=î ðNìì¾íôn åÚiÜ=åNÈú £+"Omìí.ðû>ÑÙ»äH¥²\ïó¾ðàI°«nåÉ®ðoÜ´ýØÎk"v®ì)òÆ=¬
+Ù;ÎòMýëØòþæ½HlëñÅÉÛA'+˧óË
+HR
+ñDûµøóN»ÈxyÈïGܵèçÞ¨eòüíVÔõ*ÿòJF
+í`ö,©òQ_Úó_¯öxíÆZ¿õyÂîkôsÏÑóg÷ùÎ÷¢}oñ/ø=
+õoøùZ¸>_Ùßöù&; a©ÿøÝh÷ôáÎùßðÛnñ
+ÂN
+Úv¿áqù^·ßñ:iß÷ÿØpö¿<@ÍÎ]×ò$')+-/135}ö
+É;Óú7cegikmoçXCwyam
+="F #TW:Ãte~q£¥§©«ñƲµ·¹»½¿ÁÃÅÇÉ!F-zÓ+ ¯ÛÝßáãþÛÕëíØ5èSïýGä8`A;ûþ%T/B
+8bÅfô1F,9¤5Ïú±TB'?¦ãXfM7¡{èËb¾gQ£GÑY¢Ø0/@añ¢TKTNϸ
+Сg&;lÈ¥«©ªÊo+´øxbeë6ׯÃÕ»ï<bÙÒ>Mö×2¹§}T÷ÜÝyûF<YÓYº-È0ÃÜ
+±µ?Ù͸
+× ¦!SV½uËÅÀ~«ö-Ík
+î¢Î1÷uqãÇ]ÿägØ÷Óå¸ÿ2
+¢_þ³ÅÎu7Þo¶â¾9<Úî@S#W¿ý¦Ï®ç'*ØöÍ/bùí¶µ iOÀ ¬aìâ[Ã'_ÎÙF¿òÄp?ÞSkè,PÃ
+/ÁwÛ¸ ¡PÄíxúì¶8lÑEÊ<ü0¾g1ÅTô«ÑFÿ
+ó.½Ò¢e¼Fê¨K)V<ñ¹Äzì/!©¬ò&"j7¼ÆÈÊ/Á2Ë1E¡Ì
ÂLSM°</íÜdlÍ9鬦Í8]ÏêìÓÏZî\Ò@ÑX0¸)¶Ü³§?mô³lóBI±«ôTtPG9íô åÆ{©¤þêPQ¿ËªÔTNU<ô¥rhÕÖ[ÇðT×]ÛxMEÿ£j6cò0«¤:xmÖÙÁpIë¾(¯C=»-Êý
+W\!Í[sé*´t{7pÇW^ÖÔµñ×{ëE÷ºvsÖ\æ
+Xà½,Ûª9î¢tuTæüuU
ê¼ÅL®Øb£(
+KI5¢çÇAÙ{áö1CYå "YÓ]>fYæ3qùåùhÎYç[l¾Ïº2³Yè£N¢g¢7MÚé§áXéI¡®Új&¤:«¹îZ@IÛhVÁòÚì³ÍäX>Q^1R^þF[î!ð<ô¦zXaVíu8YQMfpîÁÏö5áSªë]Ù¦[ößмëh]N¾]·¸®nÉA¯Úð¾ÏVsÐ÷uÈCoéÑÑ»3ÕO=óÍw]wºAE¸_AU¯îªÔÄüÔEwOæ÷àÖzJå¡_ùÀ¶'u¤è±9kë»ÊÞû·çþïÉ7|ñ-(_}qÏG¿Ìõáßµ}÷]ß~Oç§ûùo4ý¯×?ÒéNaóÅ?&Fµ.PMåªÔñª§BÐtdà«T7e(ìRѪø&
+öçØi
+àþ&Ï¥-¯
ª$ðv¤þHÞj±Ø
.ôá(lvE´¡µNgÃÎQE?t¢òµñp¿K¢¾®H¸=d"²|EY
}»»Æõ,VnCálg)}+û2a¤dA5îq5ÿã6V/ñªñ£Út3ÈB.²/ I½8[ä%[öÈ7aÓäc:Ê+á¥4å)¿!JU®tå+aKYε´å-qK]î½ôå/LaÅ4æ1Le.Ítæ3¡MiNÕ´æ5±MmnÝôæ7ÁNqå4ç9ÑNu®ítç;á¹
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/AuthorWork.zargo
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/AuthorWork.zargo (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/AuthorWork.zargo 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,70 @@
+PK
+
+2õëçyü}RÜ'Ñl1(üGï^½¨Q0¯û}5±oÉ*ÔÉ7?¬ñ=Õ÷Ô«ÇÙ¬ dkÉJ¼¼~H&é,-/4k¡á \³òÿÉ4)ï>Z.Óñp.>Ì8¤qõ¸`MÉp3"z¸ý2o_¹hëÁ£Çå´HçÓ4N/[º5å;ê7zxHQ2hGy4{Hj4ª_K"ú¶öp0Í>'yÅSÃÁr>ßüÿEýy/ö>°M²[RÀ £ßÞçy,Wç,£ê%ü'zûlü¥ü´
à®ü
+ÞeãdJ_ëíøæ±ú
+ XüòkmJ?'ѤFøú~QäQLתÉ5Ã|HÆ¿GÓeÒd§ÛÝOô¸}Ñ0ÇQ® ßÝ8î
+nn|ÿÆÇ7Èó&0~9AØñ¼±Ø/o˲ÌI=yT a±&Kód²I
+îÚ"h°ßÞ%«ô~»ufgÉxMß\ÖN£Å^Ð`Çdù§áà)]¤÷é´bòÝ|yO8]b;Y±CMäø£ü2.Ò§Á2]Øfë¬ãO&aãÙrìsI±:°<Km)HæÉlLÔÚÖ¬sEqLv°,<$ÅÛñW_^{]kÃ^#6ÉDËûaKÑ\[þâÊ>¢G²ø¢¶FX-=çæ&n¬LûQðrb^âÙhLyß^<Ö
+ÅӴͧ[ÂM!bÍËæ2Æþ{7°
+ ¡Ìyx]yz¿,ZÜéÈs÷&]Iuº0Z[#RR##©Kª¯±¤ì3õ6-¦Öí2uÐöökhõ`aÅÂùÜyJaÅ}¬a +¶!
50Âz¸°Jj½ÖÕfíÎWB82ÉG$*9ÓÛÐ\Ê-±üÊà=ʯRþCÍ?ÄÙÊcÎE4+çÉ¿IþEà¬kya·:íjsqã¸Û"#BÄ?º=t/rAÝDcÆR²p»Ñ÷ÉÇè)ÍòhúãJ|Fó('BQð·_6µWB9«óÜhÖAnÊ¿OélL]Ì!x~1L>ôT>³ÍhúÎüT],ËSLbvZû:³ìÈrß¶Õ gïýd¡ýö@aÆÄâc6®1ÐÒiͳºí¨qE3ÏâdLÏFÙT4ª9YÑ!·u[ßêªbúúnêë¶ W²«iã}ü º=M(¯ù»3da2Bæ*¨ÙC4ÖWv¡2Ûé¡Bf+öPkF!kRr2Û;B&djê¸fPmÙ7eËâLÜÀr/'üÄáÞ&å5¶æ£¶9á¾* 9áÔhz©7Áßía¶m<}äxc½fÛªWM
Ì/û ù|4¨¨9°'ƱÜE¾É±;:DÑÃ.§Üj4R÷o0Ü©ä¸x
+'¢¿ÿ
+Yßln·²téøË]<ÓûÏ.W_q8»I
+¥©ºâN9r-H9r%GüÀS骽*Ê3«PlÜÁѯ°¾ÜM¿¢Kq6sù¦rÅظ¦_½^IÈI;\ÁãùIÍâeWAêhúï,910O;¤Èè´"¢H4Î
+
+Q¸}Q¸°!¦f
+Ã8yogjÅMû×=qâ^^æïà%`¶ün[>lzW¢±lËú¸åÃV%'wkfËoR*ö¨êäq>;$Éâ@¾>c¸Ú5*w5ÃÖMÊk×d°U3^o¾ÞWªÞçuÀ?Ø),kF9v)6LìpêvXÃ0'NRÚµ¹§M;|湬£F×9]
,.Eó@£Ñ¶¾»?DMP«ªÂìÔÜPFyã(oXäv9å
+6+Ùá9ê ¾`Ê[ØCåÍïJ!ÃGÖ0òÖ¤TÐæS©wÅ¥KlØz£ÖAù6K}RÀ ñ
ðÆ5¤hòí"&ß!¿ß$Ñ8
+Ä$á#c¬~"üP$ô·ÍídÅ2DÉ*~Å@Ê>lì{ÂÛdøöÉ
+±DtjÇ")ûÔGÏJ(ä#ÒwÛ>E.Pò1¸äcÀ|4J(Þ£e$õpIUïñRÊÂ</ߧi´0º]&HØóHãðüñªìyÀO"9©°ìcÕk½Ç
+dMb¤1véÑÂJj½ÖÕg at R,¤ÜæÆ{öUÌìa cqÝ¡Ãa3ûB`
+Y b¶^[k865«G+dȲz¨!3ÆT¶¦Ðë|=daÁ)oÊS[S0&ÅÓÆëÙl
+d¹JÈ2iÜãLÏ:?^z¨¬ /Êȶ4.»ë/¦2BíÐ
+GB}DUF¨C¸cÿ Æ©öÐA¢ N0AâI`²UÄUFH¾
+C`e 0"Ñ4ADé4B]Îv/|ú¬P£FBÍ56kú5-ë,ÿÄCÙ<EȲ٦´'FÙDfScC,dú³0Ð&§¬5ãòmR^;"aé@£Í³é³¸'ª
+$ѸlÓ§ôgÓÇ°)¨ §Ô5³é7)USc»¯÷
+¬csJ[Xã0QREGM)üóõ.¼ÇÖ÷MMk
+Fß/ùL=¾ïXjëûN²·ýú¾Æx ú>ѽÏ^ûìס¯¹i¦ü¹ÖS¯ü9°Ñ@Sõ§
+Nè³ à±}üóì=Ñ[¢ûª=ì°Èer\>NòtöP~³Uñp@¦'Û;̲Y[Ñ(¢ü!)ø#Q
+h7ÔÍS.bXmFËiÎÉìÈõ<>xGÑÔNT H_5ÊËQcú׸þ bL³ÏIJ!ÉÛZÎç«ÿßj©1´I9Ýeé@5(õs¢1Gãs¢ /pñûä°¬>êôýYä]÷-
+Ð<ªz÷«~ çâdÁï\Þ;pÇeÑå`v.åÞºZlݬEÖÔîâOQS (¤wz¾Ùï9b$ó\/ßÅ1>¥Þ>´C9æ0®éÊ9{¹ÇÍåÔWJ«¶ÔÐÎú]PÝÒYqgq×v²Óud0§lØ©»Ù?ô)7§è»uÈKÜÏn&ݼàvC>Å· ÖåUío mLx¹yÁ!)Õ~§¨*±dÄ'4 GÍö±m
+WÓr)ÍíCQ:·ÎÂmåÄ~JÎÎ÷3 gÔ¬QhÂ͸vmzìÓJ7L³èN× CRâ~nã´ZeBnãnw«åü%/(¬/
nv´,ÒiÏ})$N¨qX/¥;¸:)ëöCrU»!¤/%ä@X£Ðd7ܲ´öè^п'qå×þ9!§1
+k° [ý9%o»(Á:Ì£8N¡Ô£gÇgXîjNg }<!åîjâlûÒ,Û(¦¬!xÜIùiÏv
+ÇI°iÞ5óRçm«ts½æA{wTÝ¿úZð6$Ïkäýr»¸ôyÉGÀ0©¡ÆÀ>;&\WóÞÕ'äwnÜóæËùPrKýÝçv£à3èþÛ7é:HkÒº0ÒZ_$PCPcÌ
+æÆI{JV2ø¶Íг¬ò}©Z-Ø2TOc
+´[NAË°Õ!)ÃI¦ëEk
+G1Ýúð-¯uÞ(Ð0
+1ÍèoLý-d¡ã]^Åb(\¹üéoÈê£þ:Ô Ëpç$`ÃèoMJAg1¢ÂÁwâJÕÀËblÉ6)ûcÅim}Iû¹ÒöGuÉæÇj}c~ðS(
+,ÿíi8çjÜþ¡[8DÊü,±zS¾÷,~6Öt¤ 5`[¸±T¯\á¬é>¶pÁ¶
gÐHZS0Í.!Æq£1q×`H9
+ìϱc¿ _æF÷F
ã©p*váø.I Sá°ÛK®gJÀRk
+ý`ÊÖ¿U/W3J§Ö]BØ,dèP*Ø%¶%m¬Ç§abCb{¦ Q-Ìåzîq:§a[X©¡fGlÃÆó],·ÄéÀçèmçhk·ÑphýÊ:tâ¶j>颰}¦Cئ;!ªã
+°
+YuMáÍ;T¹áÄNE%ÌExUíýIïViØfU1¯:vãr,7.6¥Öå`45IÖÆUBÜõ§UZ¡;4Â}ÕMájñù°«ÿ;á¹6ýÿ§dFÌÕiú¿òÙ\ñ°ýgüT£hZºN3%p5ª®Ïªt, v8 Gd4¹AM¡Ö 4«|¢Ã¹s<j£Êv.rÊغÀº0GÆAëãÖUæèbë²@?É {<Î3#°»uÌD=ÀîXp?±ËÏh?ÀzìÖlC`!Ûõ¼#°!_`¥Î¶þ
+ìêÇ3
+Q
+|Oç\XÛ` %Xv2<u£®h FbO9Ú-
+x°<[c¸x°b÷±Àfñ2Xã0y×MÊëÍ»öÖyÓ!qï\yØ<Xͺ>´RÈÃö CkÆý
Aò°ÑµºõQ£Ôq:%+D=ØtR[cÈ[8¥.è¥Rìµ2)ô»BÔ§`ï:*cåß%JD}`£Ááê&åõ*>fiQ
+*¾-mªT"N¾½SÅXñ; aì7V4.1VE§3Vê[fÐ+UâÆÛUÇÖ¸îÌXñ½>+>°Ùk [S8ÚXaÝwCêj°ÎU»°«ºJ²Q@±@óÅ5.,QìN
+ÎQìýd;®bǯV¿ bÀzY°Æ%`]ÐËÔ
+_l
+[S0æÊÕ<&¥ ¹ÈwļôD+c°@¶
+Dø5W®íÀ,fô/lãTõø÷YöéñNBØ!"²âqh\ÞIØÜ%ñNBn5ösaj;wËZqñØñµg¬í´;i1vÈ-Æ6òJ/h-¶Æ¥q
+®7I§ã(þNÆ+é lx%NÆáÜõdrpoXnÊóÁ[²¨:pt(*
+9GÃæY;`¼áh£fÊt9Z"¸N-nõÍ«¾{[6Ä+V4ÕgòïÿPK»s§A×
+gÙ
+.
ãn÷Üáâ&ûÜâ$H
+Tâ©Æ1³M¡³à.cË[\<äØÅ àÞËïùÅ
+Ð%¿ãäs-Ýhc<'ññ8Ê?^dÏ4PÇbyP)RÊØF
+¸Od>@¤
u+[ëRa+¬³GEü
$LG`>Z%A,IÎ$O¿!7¢ylµ
+?17Û$]Ù%fݪ¼+˼õýîrsK¸ªµà)&.BÉñ®Ýl¦2K¬¨Òú
+¬ÔZÙo³'OÛ/R^ÏÒ8¥Ä×álB6"ÛÈcO;dÜÈ?¯³8IiK_Y#µ£HmY®vØé;¸]Eñ· H'¾¹Í]UzhGý§ò&/TRn¨Êíh÷$BZ=羦Ãô$GZ1J³?
+Ãõ®|êCõÐÏ!pxÌ6wui>ѨAýC¶ûìôÙí2¬FVöº¶s±kñ·±½Ø
+ÄÓQìBNìÚ»AHfvíbô+æ$ã{5V-Ì.¬7»Zª]X¯vµCÉ.kjí.ÔI½9½k[*ù]»Øs¿9¿+¶Ý¥ÒOðÂ/MØ`±»jxaÉðÚì¬ BñÚÌDÅÛ(^¦7vÛñÂ6W¤ÕPòúQè§ê(yiäRËKµl¯«¡+Z^1teWº¸
+N»-4¯Ø»íyaÏ+"w\ôÂ6¢WdÖÓôí</lãyEhMEoN½Ñ¼IÍÛhÞ¼÷=&´ÍóÉEo\OÓ»!_Ñÿ&ùVs»#ez¨Ýó }Q<¢´õûÜS÷líÀÓ-ø5}DÛ_ðïP{#½þ!û¼1÷ðå:«æõ:eÇïºÇOµp÷qüp,VßäÇàÛ-äß)¦bF
+§æ#I~\âZË_ ¥åÇ,µ_;ò#u¨ÖóóDôüÑáêE?(
+tÑëV·â¥âÏô㢦úiÞÛÄÝUÕOªALØTº~v®r4
+C¦Cv[öSÜFY(âjhû ºìÇøÙ~¼ÔöàEfgW´ýbðÊl¿,xy®Q¼-l¿Ø»mû)³rw\÷SèFß/Bëéûßa¨¶r7*[SåOÁ¯ Ûk|{¸üÓêáúO«@ÐêsÓW6bØ,Â
+::Ý$õ L7ÀN ÎvÊ 'iprïC¢lèeVFkbˬµ:Áð©¼7#wÓ»ª>I=4õfä¶ëÍ'D½7#íVÆåé»Î¥
.-§n'%ê±vÒ7Kcêkrx¹÷G·güoçW=\Pz¸ Ô,¨Í£óióÏiOCZÅå
+ 6»7L|~¼N¦Áû8Ép¹Ä¿é2öó_÷½gÿ4ÈUìMêg×+?»a+r7L¨ô÷qôØ6ÙÍÃ&DEz¿¿YL6`wþ¯}eÀ(\nÎæ>ìCv6®\
+ýå2ÎÉÒËâ*qhqÙáZHÿG{q§ëtKuVYolÝåÕ£MÕx#qÈãçVË°í+"M¦ä¾õ`ÇB=8Þõ`F?P²¾`:]ë_ÉçYì[$$$]x]ï
+çgBª¨¡?
+KÔ°ôI
¬Ò°M>§]X*uǺ²;¢íìKuJÝXuG¯ÝÑB@Ú¡¼?ÊO¿¯[ÜFþPKú¦F
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/CustomerOrderProduct.gif
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/CustomerOrderProduct.gif (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/CustomerOrderProduct.gif 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,44 @@
+GIF89aÑ
+Ä¢ñL*̦ó J§ÔªõÍj·Ü®÷Çä²ùN«×ì¶û
+ËçôºýÏë÷ü¾ÿ(8HXhx¨¸ÈØèø)9IYiY©¹ÉÙéù *:JZjúÉvªºÊÚêú
+ÛK[k{û
+»ËÛëû[
+ @\l|¬¼ÌÜìü*m}½ÍMÍ3Ü->N^ýín¾ÎÞîþÎÞ _o-FÏßï?ëÀÞt<0!Àû:ÜïLÃ+.Ü1Ñ¢ÆþwudÜ2$Da"K&ëXæ£ÉQÖPÉ2æ37`ʼ)¦8êó§Pr?cz³è£H
+üÉt&§ÊzZ2S3¬=ºàZ^P°½Â »r>ªÝ úc¶e5¶áTÆeiÅ]v\ë"ÍûmÕbcg
+®J_C¿Ä´Nm¬nãÈì½æ²B±-C¦LØ3UÀ*4ãìYlåÇWK6MÔàác«Ek%|qëÖ°Ë&¾·¸³há¶!ïf\·÷Ö¹NQç\¹\pK=ûäáIëM;ôóâäusoù·½àÃ+k×þXz<æM¶ÿ°wòþ!Cþ¾çÛým¢^cê
5
+qäGà}ýìgÅþGPYR8¢{÷÷)hèSx
+VxxnmÈámÙè¡ÀÑW_'êÈâ
!Vdß7îc²5䧣®gãu»YXåP*Æc}òõ
+ÙÝT&ØÞxbn¶$zMâö_ E©ß
+r¹Fw¤b zîyZ(C
+ç¡:HÝ¢Y êh¤1ð'¡}NQ©¤]:B¦Nѧ¢:3ã¨
ªá©©ë©jBúÙj¬:ê¯W²òµâºî:+
+hrðÀ]½Ké´é*(º(!Ì/Äkñ|ã/Ç;eS´æj·²¢¹"
+²¥·L¹¿swS`r¬(lCÎ5»ñd¬Ìf}ôæ2>ºrÇ°ÖÒ;ÞÛ4H»¨ôÏÕÑõ`LcápÊó¬ÖëT½SØ<WÛ{mÙîÎ3W
+LRk46 ggªÝ
+mz'ÝamaMp¨J«ùx§æØoZþÉÚlhwpõãCÏZ·7DG9Í .z¤8bdrYöq¦h`ÖFÂ]é1¶Ë¼ÿ^âĨ×kãí_Aæg2Þv§.ôHï|ó¬oN©j}?üÝ¥½Q½÷ËþÓaï¾Õ·d¹H¾êô¿¾ÏÝûßô*Ý°~»`z^G@ÈÏ=_RÞ-)'áoßËÖ×µ49 LRJÞèH¸¹¾Íno&â!§ùÍÎ~1
+1¸¿Vî<ÓÍ;ÈÐÇM¨"Hçs>É p(®ñ
Ù+"þШè@bKÊabe Ä+zñk|¡¸ª³Ðd£ÃØÆ
qZaVǸQ*×ÈãÁ&ÆG9Ò*gdÛ^GC
+ÍR¤LÂÇB:òTK×$ÉHK^Ò$lÀ>éM¦±g(¥Ò0RJS¤ ócUÉ«$ê´ü×,ôK>I±Ìå9jÉ _zÁ&vÙ6,--
ÔÌèÊ ËHÌä4hÁó
ðv)+ù²MôÉL~[ñ4ÞwGNZócÔ¦4Ù Î+E%.ëÂ×\ióßó·mÑj7
+¥s#k\¶&þðÆ)ö·EjégTã,p:¥Öe8Bû©ä+ÌjXÚ±eµç¤áomÕת_³Ó~JWµ7½,í.JÁz·ôqPJÍíì}
+]³²É (V»¤¡¥äí*~±DÚEݳp[!á*ÇY®5}#lqË×þ>8¾ìM1!\*¡iHb¡o;ËKúÎ6®;j¹xªSómwJp\@ì-8òR[]q:_ Çu£Üd<`ÖPËKq¤¾IÜÏÌÉͪÚú*T±W¯í)lKFMJêUbûroélW5ÃsÈ(*ÁkþüFøJb0oÜÞDówÏÞËtÕ^Æy&iÞé¼[öR,ÊZk>ÍåÎ
+èÈV!eõëoqâÒvV´eX@=ZaX%Ö¤§ãKÏ9¶¬æwñÑEY#×i'nµzko!ÓbµNb²Û²hc×W¾Ä^/£§aÙ·Ê*»¦¶±3
+×g_V¼àk6#Å-ÀGÜ:uur{V&×&&s}nê~Î7mXKïhÞT51<!|á·4})ðÒ4|âZfîø;Y¸7ÎeC,ã=¹5H~mX¢\È&ÈiÝo¯àÂ~eËá1ëþÚz¬ÈK TKª
+}³ >m?½|àÓþ7_îËÿ'ø¿[7×ß¿ÔÏ~ÿ·Ov¯ç}Ú·{á7núB±c~ Va°f|´sÕeX&èTä|ùçu(4¼ÇÿGHH2&hùä6jVÄEy#B)h ÈQf-ëwåwì3y8ø\ÄZó¤\Ö~-HuV±fuxÞ¢ã§Y)2hjí§x5z«5Z5xj|ßåx$¥éÀuÝFoawÊæ,iÕqÐlÃä?çr6WzmX/70EF7¶ÆI|wS#~X¦Un1r4(L|xMrJIkÿquªä4H9çþ>W®wøqm¸_H8v
Hg£xhJ(®h9æ·XM×N£È}ôU'}i\'tMÇTQøS×P1pxZwÚx±:´Owâ8*ªui¸z·8èX8våwÜøvgxkÒ
Ezq'~»XC
WXúH/(j¬W4÷uÅH[Yu
+¬x/8c¡%+Ôg6×x|=(y
+¸: ø+ø~ÏG'"ø)ªHxøÈY¥eü sç8²SÇÁé&
{§eE53#þFX(ù;A)ÿì%îG|JÙw|fy~cd>)y:Èý5²aUId8ÌÆ}¯Ç!yAYyØ58u$)ÜS}5HéÙUU×7_¹8)Ùf©MhI9ØS§oèw6ÈéâXh©v^IyKbXR¹Lû"f2x عe¬Gwõû§_ éUæbç
+è
+Zû ¡ þf¡¢d Ê«Y{*ºI!*¢:ÏBÛ¡(zI*º¢Â #סù&£D£5Úz7ÊswÁ±)/tÈTν;êH=ê
+©Z_·¤ë¨tc}4Xí4&©¥î)¤òx¥TçxX5Ú^:
+ïxþ!OÊlIǤ=·o)¹X:6ªWw½a¤tóp÷y«æ#%ï§ÓÙ%7æù©þ}T¥Óø
+4)ÕyÿäQeÕ<!bµAJªö§x%È|ÎVçWR}n8ôiC°W"µú|.¥]J§£Ø³jþ5z&E×QË
+Ò
4Ú«÷%VxRbÕaÛe«¢&µÖ ð{V¨V'Zk)|<y ·:`ÓÃùY§Î¶\ûר¨©\å&n)®oJ}çZ¯zc¹z;¯Ó¥¯@ק9¤æe,:~°bæ§dj«x"a]by&-}Ç0RتV°à
+±9§/~Ô©\§þVs
+é7²¯
+·<ä¶sX®ÇJÓè³XÉ°Wi>Éi
ûgûo êr²73&CGë>'b
ùª(û*#ên¿yáYwB(BÖóÔ$+ªKwU¡ »)fª¶v=ý©¡ô©»a7j#Ç»K§õè»'¼Õ±'Pê£Ó·¡x£¥Û¼<¡Ñû¸ÓqÕ+nNZpÙ«½1¤{è½Ï¾*¾þãû@ÜKçlé»ë;¾ê¢ð{k3Wqûô«½öë
+
z £É¾»»Ò8EÝÄq&êIzt?'¼%¥GE¥ôØÁ3mQ¥Ú¸¥tºuêÁ¼õ¤bú6Ruf.<hØD´\¦:|ÂJV
°¬P
+U°*DèR³¨¥Û[·#¬ôJR;»úħO'ÅJl$ÍúÃjÃyàÂzj}õ"¨¹7cj\ªøÑÆZªpÅP¨«Ãª¬¿:{/ÆtüÔS¹Jd`jÅ7¤|?(zöÈ@)þUÚue|ÃæyÛz±À*¬kdëÀÊ·»Mk®Åt¼·ÖG°¹°HǸ}6*±÷×°,«&ÕZ³!{©¸Éw TØ°v´cÊ«·lE¹º)¨¨ÉK¶ÊrUÛD{ڰʹ±£Èa[`ÜÊåÜ´Áy@zXÌvëZè·³xTálª;»[´%LÎ[ÜÍóÇí¼ä«´÷éL¸ë|ÍÏ»ì±ôÎuÏÔ8Ïbk¸j~YË|±ÍC%¹GX¹.b9·#·)¸\ÒUȼé
]É_¨·ÀlzIÇýþxHMѶ)»1]Ó3}?
+BÔ>ÔVæÐͪ19¹&/]¾ÀÁDËÛ,ÔKW}1YÀ3hY\½"1ÚÕt`»TÖ-Ài=kýÉË¡lf-×GzÀÒk×Ô×~¨×{ý}í×cݽ}sMØ¥aØ]Ê+ÊØÍüÙípî;pýmÙ¡t=yÝr -Ú©MÜ¥cCÎÚ"ÀÚ¦ÇËLªÛÃz@jÚÚÆéÎS,ØxË÷ÛÉ= gÆÅZYNÌÍÙÅ"Üýv{Ò,w´ÝÓjì!Æ_ÜÝwJÌÊmÞþ`ÌÆ ¼È¼
+µtkÝçÑß¼áZîºUçíßpÌìÍ?Ìø*ZÕü¥ñª°¸ç´È'ÒÉ`Ru¶H=ÆÕýßNémµ¶%[Éä´Â|¯éÇ
+ºÀíÜY+Ïá-.nÈÖ,Ï©õázÛ!
+³*±áÁã©?íâEþÌÍÄÓ·hÇKÔ þÀ"¾XO=+À]å8yå.*7näan®=¡Zåß+æinÆ[aÛáß¿+ j.çA¦-ssçq@ÚÈûæÌç¿gçÀè
ÞçíÙjèu}èqÍþè{ÎþÙé]@éÝhNêU`v§¦dlÎèÔýD©Öæå꯻ýt½©¤ëÁjÙ»ñMÜÕXÁ(ÜÇÁ
+ëÃîÌ]Åö1ÇÏÚåÉ`:Ýþ©MÅF,&Ñ*ÞN|È"ĨI<Þ¬%&ÈíØ.ÅÄNîIÞÜÓ:«ËÊè®1Ò~¨#õÈù\âV¼µ]Êú$åðæ È<à ·ôªÞ<ðXðïÞ¸|ðÁì
*Ëí=ñÎ\í ¬ßèÚà`ð^ÑCKàæù
NöÀ£+"]3{Ñ)ÞνM0¯Ñûñ7?!þÏÎþݤ¶'§ô±]AZ<òÝÕòÌÏ BANñ,ß¾8/õ{ºó%ÊëͪŲ*.Ôl˶\¾ºyëÜÍÎð$[ð Fö»ù¶Õ>õqf4èq.÷wO©X÷÷}ïÕuèì÷£oæNøïØoé®øo*ùE®Ù
+ê¿xùïùÖ/ú£¯¯~¤ú©oPDq¼CÚêÛ¦ú±/ûv§'¾À9å8û»ûH~ì2=å±Õ·ñÆûÇÿù9ÞË!íámà÷üÑßùZüìd]&ýÝÿøÊOËîáþ%Þoþþ<+þÙÿ²P;çÿqïûwKcùP~[cùøeñÏÿRÿkvO
+Çr»reË« GÖLiòeÏA/ʼô ΡQ§Vfti×pN¯=v«×·EÅ®½woqçâxqã¿'W¾ysçÏ¡G>zuêDZg×¾{wïßÁ?|yóçѧW¿>}
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/CustomerOrderProduct.zargo
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/CustomerOrderProduct.zargo (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/CustomerOrderProduct.zargo 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,58 @@
+PK
+'ÑÄ>õ¡}ÏsÎî¨É¥ÀIÔc~³[4éÎ0xuÖ
+?e/˳ßsý;(»ä BSÑínó¶^>W¯;JXö0_9ÜG¨èÉhaú.ó±nPnѪ }qñü0¶¦¿H=WZ´(LY\Õér§c<ÝÃÅÅ-ä}ý
+ôòõüÁ°Çøi£yÞô#æ(ß|~øfÅÕ=J˨Ämxøáá'ôuå%ÊÒbDüß<Áß½xV`^÷Û¶cßáQ¨ï~xhÆ3v;¶ßS-ÞÜ<ÎÒí®Å#ñüC´|
IK7CÌÉDæxDÆü¹û´ªùx·k'$Þ<,¢UÆ»~ÑòÃëö¶<½¯Ve²^%qRþ¹{|KýF·ÐSÙi¥KTaH½'Bômíñh}AùF§Æ£j½ÞýÿYýyÏ>°-rgRÀ£ßÞÛlVtãÃ[»ßüf
+^þå}í7oP´¨ þ0+Ê<)áúëÜ´äõÃëÆ°DóߢU
/óÃá'ºÝ®¨ó¨¶Wàï&;±ÉÄ÷'¾51=o±ãçÓr<oîöó¿=jPOX?YÁ²-õþwm 4^þÑ!Û4éÝ~âʾ¤hþ ßÖ«¨(èõð&IÑMîÇ£ÏI̱#üýºa]0èJÔUENGÈq|Fµé¢:ÇÔÇUwÜx¶
+=J¤TI¬NTJ^ö¯Ð¥s¼×&ßà _Q£¢ÈòÑ¿TQZbýú×77ÂÜZÛ¼Ò¡L4Æ·{Æ
+°dÎkÄe'³ªl*§iÉ4s÷¦¼µ6Ã\m®msu ÍÕÖæúxsu¯Ú\·?J¬Âx5åÓÊ*g£f/v]Øþ§so!Á<ùH
+?ÒÜü6ζ4/I1Nc©©â ¶é¢¼ÀW×:o˼±E«·ê$³¯ðÐ~hÏܦÏ5©ûoE÷JËÒèæä°[È÷MAN½i6¯AÆWüR¡üO Þ|xFþ\ëqí=ng7îxAÍE÷¹Åõès@Í85cO]3þú}N2ÊÌÖQ-£ä¯t?ïj¯$<XTðÒKùû#IçÔÅüÒAèÃÒ#«³Ñ#éç5C¤K´|g}Ú\,«SLavûº²5.KÄ¡EGïßã¼lå÷«
+so³yMÑxë´´Vλyôt͹3ýÏy£9îâë¯ëÓ¸ÆÒha°·Òe-7Íý_ô9È
+ɧþÃ4¾ÝÝnkª£$ü¿RZ¹.X6$õ²Ô]^XA$àfÄíiAyXç̬аNëL»¸Îê°u"³+¼×
ë,w¸æs6áXÍи®)ÉÁuÖqP©©£§»OÝÁùÛéufUy&µaÕpXÍÐjݼfºbÕ?ºbÒtegèø»þpÛä,¦º³ðONÅYl»¶5Õ}^Åå)K¥qç°±÷Oï$Z1öÓZ,cðçêÚc°ÈlXÆàÇZ5» hOÄ]'í«ÀUÂs«óa¦P.P7CÝÙ}Â!"Ǭ±ºYO>!³ÍÔµ(DäØDD0²4"jvaÐ{¨ó×»)ºï;¨0̵R7» a~äcÎó ß0¿ÃiÆQï/Ô
)0ß9³Æö¡ë9%BÛ 6t©sò9ʯ8ÑÝvHdaËÇ£c®ÅH¼ëà¦ÝAzØù±c5à'í'7¹N\©+ðXD×cÇ"jC=Qxöãªð±ØÓ
+Asý²WÔWQ´©îòl@wðNµ©R<Sõúßï]&¾ßãÄ÷kS¥ 2¶_壧jbûOgªgíw©m|mQýì®þLáp`¨~ïBQý®Ss¥¼i«síAò÷øÀ¯ÖfbóÖ
+ürùsÖå¿<ØþsجC9-xCè÷aú#}¾Ûê«áEÃ8âõÍÖRÓ_¿sì~2¿|z¦ ðÔq,8V8¿§Ôü=5lcÂ6¯°Íõum
+¶ùC¾ña |ÄIËÇjmMÉúú>¯/, p §R¼r¶XÍÐÚÛ¼jÒ¶RHG`HÍw}àAïºã³M ná£'âUãï»ú
2kÈóì§gIE£pÞ
+(ä8DþlÕ^´/«;5%oR,µâ&x
+X{&
+<ýÊ úå(¼Bãì¸(¬ÇÞk\ÔÑ~Bàè{
-
+
C¾£ïõh«Þ
+©mþÕaî{ü}¯·J[]Ðp«iýûa¿á~
+÷®÷gæ©à¾QÛ}YevÏ
+«×h¿a>¦\@Há°BT9@¼o°Ä1àGV;42jJ²2+â¡=ÃE¦!$gÃE¦áöF¦r)Q²zRR_Û ÕШ«ÁzEùÚ*4bLiÂlSÕ
+=Ü5éjÎñ~îû^¨ié*e.hÈOôLè«u>Èo:ýüf_¤ã_a¼RÉà'
+a<C2¯¡ü¥Ï:®d¨ë_\¥iÂgOáD«`äÙ$y¶`ɳÇÉÊj&MIùâеÜôuXsbèwù5ÓMÁÙôRa #Ì §:ðÜÚpl
+Ô]ÀY°þ»ÂY}Á
+{®[ºrÛA]¼Â´YÕ+té¶ú¯`h%«×8s?¹x
i÷¡z
iós²ÒI¯º|ÇX;0¤ãƪpz%
+Fä
+õA=§PÏ.£°«)ÔóY0Æ.Ã9SgµCC½¦dOR|jÇë®xB#8fñaq ³¶º yÑ3W
+'©
+0Ððn.Gä¢Èâ¤Í|ἡtg']t^¬ï¼Ä6ãM22zøM¿@RêýOã,MQÌÙ)É×i}¨ðå'{&Å;¼-£ÙJ"3Êò9[Ó%ùªJ7Ð|<Â]ËÑrÇ4K±låd¿¬EµO?âYE¶î¾Xñ^|}¦÷ÕªLÖ¸{øz¼¥dê&:A ¯æ¤U¢~Oë"ÞÌÙÍ
+5ÆoªZ¯·ÿg[©6´E9ZÝeè@Á W´Ì¤ °cBãbXâ¸ø¨,XË_¥ïÏï:gQ±Ûka¾,ù-¾ÆÔUæU·«ù$ÞDvéKß :syÔÌeR3lTîLá K7
+×£ÎÇjÌã´¦«æÓË
+>µVj hzhÎ^«h`Óý«Ö½úY
+óòc$rÕ¼åõä¤NeµB+GÔ¦Fñ1˯
+ÛîvèôªÍ¸íög¹½gÔæì¾Ií«Te²ø¾ º¯¢púnû*7iò®¿*
+É-º¦éÐ¥º:[aó½>Éz_åxAß¡£?üê|Íè9ÛûxW5ÛAò\Îj
"ÊÆíNþ(¥M¶B÷üARbWálòÝÀ_{'Ƥð¯ïß\ùRI]Þ¼½Ì7áÝ`3ÀZ¡¥²ôîÊ,Jú?²ý,*ÐÖ þݧ9óeuÈWs\çaWãü²<(IS}ÚDÆ NQ^VEÝsS9T£Ì§pºÔaËF&9!_^6uY·ÕÌ2°eµç§ÑRZ¯ä«p*'µ,~Ò¶óµ,~y¤SÖl¶,a¬
6ÖÚR?
k
+
+`Ã=kNÝ~ÿSLÐRóæaJòuZ*¤3'Æ'Iñ/"Ëh¶ÚÜ·Ì+Â6 JÒ%ù¦J7Ð|<Â=ÌÑr4KÛÀ¨ò%*L5þ§pºÈ³¿
+0az_Êd{¯å©Á[J¦>n"çúªiN(Tié÷D¸þ âm}Á8ÄBµ^ïþ/o¥Ðåèu]a6
£Àïú¿Àu$Wdß9¿J?%ÞuÞ
+ÚDk°³ÖîðÎ\¢Ì®3WhP3AÍ\%¦®6l.P86ÌÔåg¹ZlhÖÛÿ¶ýE«ÂÍ7/ýþö<§ÜÊl>ãÿPK| 4¹
+Êí¾NÜU-$=$U
+ápÇîÛ<¡§ýy#|+|[>öë(\ÀEõl»ºÞúD8öF#CߤïÓlÿ¼ÊÉMÓw6vçså©ýÛ1yÇO°$¬«®6,¸ú°àÕp;KCªf¦Ò5&Ú^ÒÆzNDiÈ ¤!X;VAÿÅÒqr¯KÝÒQ/
+U R2ê¥!á ¼nT§V¢ñôR2(]HÕ,PI²ÓèB¥1Ö»díñt!ã@]óµ¶fös-mt!"e*u!ç#Gvôµ´ÑF"¢QT]È_À¥T®½ÚuBÛ¸fÑêÇnh08!Þðµf(á´5µ|¥Ù}Í[VcóÖ$Ñuy]pÒÄm!±¡lê¢
2RC^/°Ò"{[è_,d9ÆoýÅA®½6¢y"¤ÖÿXãÑ~ãÇõÑFób ¤Ü¹ä[Säæ±7:{@Rñ|±påFxìóFôfgôºpS4þz'Ûæ-Í`uö)ÜE
+èH<ßãÝÐyK±2S$t"È
+B*Ý ¡
+R8,_ÐËjÕnR/Õn@A¶A"bånU)Ì=Ü
+è:HÆÜrÌ=Þ
+-ÄÄæÌÝWÁ+!´©R¼ vDñJ!ì·äá6ªf,\5ïØ`¿wÛÕg7Àoȧ¡×ªßàÐ
+PÄHþÆIÜ×
+PP.e#sø¤% U
+(Õý¿A«úOsÏõoЪê-¦
+AÁÀ*AÁ}¦Ho:ÛëáÉu] Z'Ý¢¬X:ǾE4
+&(Õ)I
+u !áýÒZFT0¨Ê]Z«µ0çDº]Z«q=¢*vhh¦a²î&V®mTÄ
+¯!<{¨`fX:ÃRôÞfmé>hj¼y ¼¬
8mÚ¶ÐÀ~(¬U襵*
+Ùö|½SdñUqó
+Jú ½oÐ8rÐ;ÉcØ\rôTã²J·®SÊÕߪUß«üoVèrE¦çí}Bï0pY'hãò!Q":áÉSêxÁÄG1ÕüXú`ÄôùAɨ&¦Z^2ȳ8Õ@K ´¤*ÄÑ«¨§Áñzw§%Ð-%u:=úÅ}MìTç
+EëºÎ¸BtEwb¦²b&ÛyPf5ÔdÔQ¨ä&£7©ýà&J¶H_©ÖÎå&ê.}^ïîܤvã&âñIù§ëb'äT
h"¦*?À©#Ï
+ZïÜàpï7îVñèÍN¢«f·
+®ÎþPK
¬&*
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/EmployerEmployee.gif
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/EmployerEmployee.gif (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/EmployerEmployee.gif 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,79 @@
+GIF89a¨Uñ
+Ä¢ñL*̦ó J§ÔªõÍj·Ü®÷Çä²ùN«×ì¶û
+ËçôºýÏë÷ü¾ÿ(8HXhx¨¸ÈØèø)9IYiy©¹ÉÙéù *:JZjzªºÊÚêú
++0K[k{«»ËÛëûKL\l|¬¼Äü-=Mm\SM ð
+.>N^n~®¾Î>0Ü/?O_o¯þäïÿ0 ÀíöÍèG0¡Â
+F@È0¢ÄtÁ@1£Æþ\Ü2¤È×F<i¯£([ÎSÙ
¥Ë49:«3gH-dêüç@s
+ÕB´¨R G}$]
+5깦)J½Zê«XwÂë
+v¦Ö\ÃÅ9ÖDÙ³lÃ¥]ë¯VÁ¥i©Àm)ÝݶèêâØ5ï:À|)ì0Ø·÷*úUªc
Eú½QéËÂ/ȼ³èÀÝ»0µèÔß·6jÈcF=5-Ù_·ÛµìÕ¶1z>ÌùôpoºYÏîý;ºsÕÉÉQ<¨ïÝ¿ÃÎN[ø¾Í©oÞ}¸ôñS#.ýó×Í3ÿùÕëþ«»
ß|øéàyþÁÜ~À[~¾aÅØm¼Hazªé¶M°·D
+bøqgà~7¨_ªH\(¶ döö¡`&NÀa9®X#¼
F í¨bôñÈ |7!¤IDöÈbt?¾ZAg¤&!YJyQî¸Õ^>X_J)Ùù%S¦ø¢IPlq²ÆíF¡sÂMIbdÒèiR÷c
¡þÉè¢Óy(ètZYf£úÈ]¤8¢¥X#Ø)xfX*:JêªÆjª¬J«DÒÄ®ú ªìÃSS¾7þX®cò£¬¬ú4û*
+ÇBÛÔ´³d»í¶
+5íµ5 Û»ò¦Äé¼Jíjo>UD¬¸ïtî¹÷kn¿ßÖe°¶Þ6Ðn¾'ÁËBÃ/)ÄËïÅôü{¿ãlpÈ ®ÀèÀ¿Ãj¬¬J÷`1ËEA|AÌ26êÍ/rÏüóÏ |òu6ëÌPGCûÜÒ,ÓlÁÑN/ê6V_ÝL¸Z-rÐæ
+¶xaWuÙf¶c¯òh¿
+wÜV_#wÝv+cíÔ8]r×%üò¾GýuÆz¦ôÚC÷áò2Þ¸ã#þ.9Õ9RWÚms+-çóf.èGnzhEzÍ©³øç9lþºqõÖå|&E;Hÿ0^¨qiZ{ì¿gàS}áN×íæÍ<ñÊÕºuË~¨³×ûèÆ|N¸Ë
Ï>«öÌÿtüJµBÿ @ÊS«;¾Ïè4V>DGÜr®×?,Rº
+x¾ÆÔëQbNyæ#(û|§{Â0Õ»åÌzÜ#ávDD§¶$PÉ ÁÔ@¦0I»a]²B´°<¡"8¦l/LQ}4!þ`òa¿'ðLøË^þ£þ#'BÐ5ÒØE qulß÷DÛ
N{í³ý(À§¸gÙU^¤ØC:rf6à"Ô4GG%ËK3|3B)ºB"Åÿ-òYD£Y¢È<ZqV\Ó¦,RÄZD/WÆïÑJ7Ú)¿ED3FªL%)اr1 ÂÅN^ê;ù ÅËÝÍÂ3$³Ø8?ÖïtÚ+wª?úÑ$¦rB FØU/iø»Üùsc'èÔÕÝUM½3OÀfmÚÙ¼gþ)¦tÞëY¦yVîMÃ'S`eP¾\3¡C¨äþZ1¢¡½¤?+*ÂÒE¢1à§A9J6*ô¢"-CR·W]iÖèÒ{ÄOt)uGñ¹B;Ý4¦Ñ*(O7vÒðuò§jÛîDTQáèTIª.qWÓx5Õ+KMYÁ8æ1
+dÀ"×TIs2Ðe5]Ý"±¾v;EÐ=eÊÀáµõ¥F
+W¹æ5®.¯KIÉ°Uo³jÛî
+0¡QsjìTÔÐÏ¢oMI&{=lÒô![ßô×r«oÝfÿW¾Í¸¥U«ÐZ×FsaíSqãÍî(ñlaz[SUÖ:GÄ¢
+þãÀ^b0õ#lXÃöY¾ºC$n
+b©BÞIfÔ[
+È·ö*,ϤZq¥»'\Ô÷ÄË@$bï¶|wðÈØA5è²Næz¾D§HnϾtnU·Þïõ¼[)íx¯%6HÂ#2~¡_h×®±}-,å ÀqÏûæ\;T=jò¨Lä'q(L82·Û|l8åнEaÑýYÛ±j6Tàmïh"dÚ¸t×_+[(wË4 ï¾IãÙQÆH¤qyºÊ>ÒU®ò( yâ0
+XbFzô3cm<é¿jøvä37YÞHãÂq5â0áãw
+UÆ[\&j&W«X¨úl±`lå+ÖèR¨í 6ÄbøqúÔo
+³K#cÿi®¥¡Ö ¶TfÍÆO£ÝÈâ%Ç6¶6msÛUýöÞ
+¾Kbx\ä¶U8Ê;'ðµàg9]n¾þB6ÚÝ
+g¶ÌõòÕ.9zû£ÍÏaÓnän:À{¾²¸ì|i¹nkg[VèFÏ\Ü+?¤Ûç¶lØ-TêB]}\¦Ö#ÇtØÞµ «ÄL¼÷nÚ®ÑÆùºY°4¿k\U3½Ð+óJ×ΰKó¹Û¯}gíâýòÍùµØFõØ7ïü%æ1\zùôh&$ÿËxËZîö³K!Ï
+h|^¹HXlÔóL]9j0Dëw!{&~+[ÉW)êH%åfq¤h )uwÙÇW3Wª$bYcø¨{·¤CÉ~l¤Yhg8ww"¸l0p%ä^õJ¢éj9,épy¹DÕ3Ĩ@¬§ if_Wj¹)Ç9MµT ¶øyt\Y`±×HOkh¨8i~N6£à4è?^$ËuLø\þÊkî zäå+XÅ5ùlÅädÑÙÁÉÕIxcgj*¨4Iô´|Ðå©CT·ºù%KV^ÚÈv
+úsJÖÆ/$ÊóÇp¦è&z¢îÃ_åÔ£:3znq7êLÈ£²HC
+Èo¸¤½h¤MZ)z_xB:¤2
+¥&¤!§¤C¡H¥ªS¤a15:U@ê¥9JXJ¦ie¦M
¦Iú -ê Á¢µ¢Å§äÁOl*¡
wø¦*:^ôÄu¨r*XEç¦ÜV§×óè¡1!yØÙþvð
ÙXÃ'©(ZÞ8tlØÐS[r¨êv³up: Û'_(*ªÛé«$éf)J"ùjƪ]÷¬Çºczl9kyvÔ§í´¡
+ë{ªTÌèýJt¤fIJDø:±áú°`· }Ë%K~I·û¨8'56ý¨îI{«¹¬ZÄL8z¹*2ËõWþi¸F/KLÕº±åç®ç'w&éF¹kÄ1P¨ ¯³ø§©IôÇh[;c\FÃ)bv*©i°¶Y{\QÛzFrÊ;eÎ*¾¶"o{µ
+np^¶¨6¶V¶|K±ùÚµO
+¶ ¸£ ±ò§R«e°Ô J®ù
+ÉMï¹C¢rªÍJ¸{ýêÉ«ÿy°·Ûºç
+¹Öë!'µ¹ï¨¯Vº6³èªÁSþzIæ{I¯ªPÍ[+j*¿C¿ÅS¨lqªcö[øÛ¦é£5×¥é±HÀm[: À¬
+ìÀõÁ(Áb$ÀYhÁ,ol£¼¢\¢;êÀì;¥ú:_JFaúÁ Ì"|¦$j1,Ãï%Àg»ªCR§-ˤH¢¿©Ñ¾¿:x:Ê5·×¿®
+è=¹Rµ«W<$é{ª.|+^ü6zÚF
+«ªWË¡+¾Î{mîÈ©&Ç]G«¼k«ÍY»ãº»¸
«|¬¹öA¼:«³_ÇæÇ6xˬ®ëjÇr&þ`¼Í*_Jf
q,¿÷`ºÕ^û^~W»NØü*'óªA¶ ½Gj¦®± ƨÄx¹_»my¹)[EA{²n:r+ÌÕ©h±¹wª¼¿Â}$Ë
©}IÓ²l¼²1ù?;~«Ùz}¥
+ÎÙjÊOj´À·»·ÚzÜÎT{É©M[<v³iɵ²Ì¦+¶ÊI&VK·ßÌBûÍil¼sÕ\·wPÆ,ÊhË°ÊÊ
+[ÏðzµY»ÏpÛ½-¦E¯øl=ÇÙÅå<ªÚ¶¥ÎC»É»°ÙË-°4
+}LÞ³ªÇþƺÿYi:ð¬.$Iä{ÙßYŹ;¼-󴻺ÑÛ»ØÔÄ\̪º&k©¼Ü¼Ä[Ñ.Cî;¡=ÒhìÁ(üfݪq»oKü|ölMa4ËÈ㧨Ã:AÎé¶}]Q
+ÃS¼¾Ý£ý2ÑÙè»Ã<ܹ¥-êí§-©Â¶Ø´ÒúrÄÂxªØù±½mÄäÔOÁMÜb,N4
MꮤEbmwbw
+¤Êg\ÆZgÝmKÑÄXÝþZòØÆrmÀ=ªÓ½©ºÜñÝ+ãÍÛApÝz|Ô|Z¼´<xÝû¬QíßTàÜ»=^»åÅ
ü=È`XÜîmúìeL,MK[gµJk÷
+©IlðÑ3}ѽ·âͨë®ÒOÔâuÙ·¿UaÃìC¼°§ÓÓ5$ýW·üf½Y_ÁÕ«hâøí}»[¬9Îd4ëvy oÍVÞäÕÐ|ÒK ¼Vy&)LÆÑ`Õ4çåhýøË2{àO~â*ÑTÎÕP|¹e¹d>¹G¨
+}{Î
+ºzDèxç»ç#è-Îç Í¢%nÜ[êpãɪ{éZ«æ6PÏ»në7®éw®é0söé"Õ*k zȦÔX´+©»b
+tä½Õ1~k·´àüX)ìºöÑÈ{Ó®L:=çûy½MÔ(4¡½î :Ü
+|ÛÞÍ9)Û¡±îNîúcÛ4ÞÜïÞÌ*U¬]ï,tï§Û¹-¥»ýï
+Û ÌðIêððµ=ð¬Û]ñðíñDZðßñ}tñMòhé+Wò&ÿñøò½òݧ0@ÆóþnÚ'ü¾éÍÜæ®ÜÌíîp§i8ß:2Äã;ò\¬Åo=Ko-¯ÕTôXW³QÐÄ¥_àÖõ
DÏj
e!Ýèm¡Ë-«3ÌÉOoõ~©Þ¥Um5o
+ç)¬U.iot~ ®ä,â÷|üá¹ÍHüÀÎøgç¬Ò]NâÌáÙ$©çù¼|þÉ,ò+¼þºö¡Çéz¬ë®ÜjKõ³¶ìêNíK}È·ã¹z^_fîân\è-æXf¶:d[a÷,ü2ý`2ÉãË ËûªmS¯ÿâZ"áÁ×üò¬@ÎËÙúîíÎo>üþû»Ã[ûJµÌKĽíæc`}¼²
Âûé/¨¯³ÝÜ««ÉbëÑI
+XéÚ¾ñ\ßùÞÿAáKYL%Ò%Rv ¤ÒÙÊdª§cE;âºÙfØ5ÑèíKÙNMßÒ6*\o.O=þn²«Bàä
+ï¾Æ"©V%§Ê25+;=?ACEGwM¹"
+öÿ¨0Ù%ùeÅV7ÏH{M'ãRgý@rÿ`OmÉ!/çòuz}~±mk-¥o«E,Å7ÑÓ³µÙÛÝßá{þ¸)4r¹âÌ¿Âé=ÊMràèÁ
eµ¢=ÊgmW¼OÜìùóFÁ¸zúÄEü Oú¥J¦1¤Ä{
+±qhc^A!ÐÈÊ#yÞÌl:V:è6M=ZIº):¤Mò*ä)T«W]©kWrR
n¥ÔlÙ±fLU»»§ÑÎ; ]u`Ûêko_¿\á-ú6â_Ã,^qcÇ?ö*<¹/ÞÇ4"SÖ¼y³e9ìùriÓlAV½:éÒ©YÇÍÔõ;سq_}wox·s×¼Û1páÇggyó2Ê}GþÐyþuÙÐó2·¾½óTíÜ·c><ïàÑ/Zk{÷ïáÇ?~}û÷ñç׿¿¾÷ôÿÓY¯¼ ¬á<
+Â1¬Â
+9ì³AÔÀÃËûî £^(l¦æëBÄHQÆMôéDëZQ®è®4EÄhq*¯JÒ
+|xÄñBL&RÊ)Û²ì'ª³¥I|Ê1×jIö!&°à¦zäÀ ¦3éócÌpóÎhÔdbúLMÉ,ÔÐxÌ´s£7áÜ@K:rBóQä´SPF¯Àó"¹¢<TÔ! þ§pêÂÓq®)Ì¢E:Í¢M éÉ?§¦QyíÕR¯J/^ù×n¨qØq2}3k-f1_©¥¢`Âè$ôäô¢gõVAG*é¤WÉõjÙm·l±¥FÙt£K½4he?5$±}sõ2TwÝmQZÒåÖS]XÉXFX~P
+ØaB Î`UöÙ=*¾eRpAN8ß,¦d`©å¸X¹ÕvÛ½1egk(gYBÞå«uSQîYÚjHnÅäQÞ' ¡6" M%Òg¡zK Ò´ÆYS8 ÝS5lº7¢NÛP¸ÂÑ?þÇîèX°oÄn¢õUßctÚ¤ÕÕQÉ¿V\ñè?L«ÿzJ|q)ÇÑð+|òÍ«ür´zÄó=ÿ<ÍGO½LÓ#D]õKgÝ:×_¯}¥Øe¯ÌövqÏ9Úw~9ß!¾eâçÄøå/ë=y³g¾Äç©VúëÕâOûí¹ïÞûï±?ÔùêY>üóÑO_øñÉWÍ|õá_þ´Ïú¹ö_ÿýù_j;6¬àÏ/ïëßÀ Z]c*D'öeÈ
+´à18`¹"b{²è%Åî-haLCÎpz`þòZÊä´ò=ôá³Á
+±E-ª¡ *¸E1ùb%TdÅçmãÕX at 7Î@cùÆ:î©»#é¢Ç>ôdYHE.wQ"II®Íä%1©º?V²,Ìä'AI¡éK/ãdTBJUÎâýÀÔENzòWß³å-qK[®JÔÂ¥%¹)XýÚ¤shÙcRL½t¦· ähcÐÛÉâÌD0³|Ïô¦oP6yM3_74â27trStßtþgqZ!í7cZ6uÏDZS4Ú|ç?ßKy¶êH;'3ýÉE~z
+mÛ$HqóT 7Z3Z© ʨCA:¸@0üü(©2G§0Ýå,
Ë\Hað¤±'ÂFé´µ<=SqòB¦Ä¦°*ê.¦EýÍBÑcSªd.!©ÙmÕ¨kZD5êUµ±N¤Úè¦D°ÌÌÃT]"\Ö@=«G¬®ZÝ*K¯²$ùªXÉ¥®FðZhu
aÊÖUºõ
+ë` ÈàÜcyغÖu±«¬eEê8¿N-iäÑ^*XÑ*³°³ãþXëØÇ®¶±,kåºZÖn³çDV¶qÄq£õBKÛ׸g²°5®jaÛZÅV6²$5a±ØßfºÁMËa[\Õn7»ìk+ÛêF÷rÒî%ë:̹4+êÅsO[îB¹à=®v»Yëö¼ý5@³d9õT%5ãÕM|[\Ìf·¾ù/ìÜýZÕ¿¾¥¥fuZnã)u·ª)ÊÃË6f`G×Â"Ãb¢«sði5f³,Fã='+Sñ!YÜbB3UæÚì0T8ÍYUâú±J4¨O)OʹòÍzzì y%eKþ¹¼Ù¥Î¯übû1¹H+\²yb«ÓÌgFs1üD¹#>Z
+ât ´¨,Eã¹½õô] IëÒ®|Ë=iCæM3:Ñ.sz*)UÐË <¡I¥ÔxÍyÕ¬nõlFkª²²q¿ZZ¥êµ¯`K
+1 ír"F±0WÝ|öylæi_ø[lY³@8[ßw´¯èê´ØÆa0Ð*q»ìÞï¾
+´¤¹d·æ Æmç4YsPÐúæ÷oým]H¸;øÃþh"÷RÀ¦ézO'ïzÇx9£³*+ßgL^WxÏ%æ'á/øç
+ë%nê×"Åáëá%ûðpD>s²ÔÜæ&Ãb<p³ÆNú¢^ì.è8ç0OºÒÓt¶YnïrË:NJó ÚÈh¾ö«Bãlí9æûcë^ÕÝ»ój¹îWµûÍ=*âpÛFTü¤z+øÁϽðE
(²µÍgBçÞ´Û®Îs@?+dNÄÈôÊ_Ðy{yp\¯jÆõ^½C[ÿi«À^÷À{?|ûÖ¾°5GÑ ÆWcq¾['òeþfW¤Ä«ñßüÁ®×Ifï=EÕÑ}dR?¤Öß*öAnrcÙÞ¿XIf~Õ¿æG*úÕ÷y±_ú8aÍB,ä诡ìo¡ðKtͺa+ÈFün;æo
+Õã
+½ìÍìØÌíÕúîì(Åí|¯ÍÐÐÔðÌMo8þ¢ÛâPÌÔÍÙ¢¬Êñ±?ò°öñükþÙîÞ"Ñáìðh«ù
+5q3åzæ"
+°¯èUÉtci1ApöÈËEZCiÍjætqq1òXò²Oú:Ç_Ô1b¡'ùÐÂíê¬f§rÍmz²1¶ñJ°aâOªÆh¥
+
+ÎÒ!Ñ"íL+QïæI8!52#þ/8
+.]^ÎÈÝþ¼pÃÐÉþ,"ÿ0D0S DRÿöRÎÆì¯Ñïô±-%³(³2Gæ²$q3«)5ßO3'£G3+J³.çj CÑ
+bRÈÊCï G¯mÞäds6a¤6)÷|1Õ®¦þ$6³:½1:ÁiAg4q¨Þ¡¬:÷¨%Wì%k±ý¤4{1 NMäiÌó<§tÔÍraP
ê1õLÄüÉe.× è¯Ýê³Ð3ø$òæ.Ʊ
+/Gð·æn&²<ÔÐo O
&úpÿ)EáS]s!ôBt±FmôFù#?ñæTRýEýof>Ó"gFy¯HÚN5[Þ8óAHôH©tynsÄÈø`t²&gÂG
S\eáÌ1V@´JÑ´vüm`.6ÓôMÕôþÒEà´NGgDY'íþtO³ç>×OÕüô-µP5OMGO
+uQ«dP Q!µWõs5R-ÕZµ.uSB²ò==+SIõ¦2ýË«TY5H0áTFaÚúzÒ¯Ï=;©U}õ²I¿
+£¥^îñGªÄÏö~µYD
+ñEE}T!¿²ÙïÿÞðäµ[¤ð kíc
ã¦õCeR¼u]\=æ§PTÿ$f;Ã[³*Ù5_#T'1ïÒ¼ôt7[ð%00`·[õ5a»<GCÚÜTa!ö4x±Ë2F5bIuRWc9¶14¾:6dQ#SþePdMv(>NveedIeaö¨\VCb¶f}afiÖfuäSwÏæ´Wwvh1Wß5Úi5hV£ºÍùfUW£=O¦ÖÄjUCeµN´M¥iÅÖ«²ð5uûu_èél{ÆBªÐvWÕviǶnO0ÓÄ0_3[«UXäÕnþªýÔjêí_ÏÔnÜ,5ÿ6$ÐoåD&KεIÍn7s+
+Òrù>W^w¤ã5XTtJ5wue.Ðü8ÿ8Áù`/VK;Âô+X÷wõǺwhëQqÃÍ8iÐx·2nSö7s×¢7q§ª×zqöp³iqô{Á7ºw|É·|Í÷|Ñ7}Õw}7¤
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/EmployerEmployee.zargo
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/EmployerEmployee.zargo (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/EmployerEmployee.zargo 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,79 @@
+PK
+àºQpºÎÅ;¢ÊVÅtÀ*U{ËkìÇñѶJ÷\bÊè
+Ìê"£§(fôgQº<µÀêCØÖ9·þ¢fW
¦ÔbO2ºF³nÔ¨K¸+ Hí¨EÏèeÇ Ñ»þäºl½ZuBÇý[?ó×#<åuhn§rè !
:5¡^Nýê¡Ýº<ósÁÍeÝÕ¹¸Æ*=Õ¢ÃÅB¹
+]}PK÷Fl&
+8(
+
+â,KÙ.«i§'2àìU¹ê3,u«-µôLKe<<Ö
+q»<7`C]þù}MÖm¢4·^Üþv(9Î(êüD«fS|þ¬æÔÁði Bôa©ºk¬QðTo¬NûEU)ÌÑÒF¾¬+Wm§ÉÚpÑÕóWÄ
+
+I>òìx¨ö«ð2EäÙiç) F¡æÕ[çÂKÃe8#!!c~¸FSGqÃ35à°Y¦~ÂùìÊåay%2¯qÛ qk¡.¸ºÆ
Û\{¸ÍÅ¥ï¾ÆmÕ[µÓÃ¥"WWðÖ
+¦^ªÇà
+*ÌÛ=xK¢¿¤CO¨öz°çé²gyÈRÄ2^·TiK¥AK
sïßRCöú9úm,ɧÝë¤ÚhÏå Äp^7ZWíÍFëà ¶?£õ
o³Wm´l£EMs´ÑÞn´2¢ëÎh»(ÄÁô
+ûÞÑ|ñzïÒt?+í÷[ÿ½Ëo0pQÝÓ§YqÝÒÀPSX¡»¬Üãlåõ:e}Ô*±ÎD«ÝB;¯VÀ
+ä½g^àJóX7ugpWUºåi«;¡c¸ªün\U<08CȨiù±Â5
+±ÀP0Æ´ü
+èèõåd¦pΨ{.0|~5PÚ'cá5ßf¦pd)Ýâ5ïeÄ°F¡iEUòË}
¾CñÄ
+¨Y/
+÷Àà
+Ôê3
£¼°Pi#m¦ZµaøYÃи*)¡3Ã4l.{öPYÃÐê[¼gÚa®eMÃaaÓ@MS¸§
+ñ·»r|øTjsFgq@>:giàÖT8Qj¼%}³´1õ«Ö^ÝZ«xuý8Qxíy5§¾ù¼5:&Ô¼º=¯6ÇØoÑ4q.j^]»],×2·è[I|Ålܱ%à.&fz-©ª°@ ä_Àiñ]9MüòFÆyWp/ß/Î3q;4*{óÆb¸=':kçU%eôý9»!¼+&.6jYÃÐÊ]¼_c<D%!±¸i%%S²øÂÿ"±0sPÂõAPèL7Mæ? U>6é>ÒÇÅ#ºãâǦ
f°`Ô?5ÌCÈ4øfÑÀ$öCl[ýØ´\v©Æ§,J³é]ñíò¬ß_Äê<*LâK¾/AÍ7Öe¥Æ|cjÔF[7Z³¸*Q¸I{£µe¨®:ÑÚ@£w«¹6Ùò¬½Eî,`²2ô0íaÊ6Ðq@lÍd1CMÂÍÄLVÆÃ,Ðz at 7 ¡îÿÜÞZ)0±3LËÓzhk¥j(Â]¬UVZëáGÜ^ÌÔ
_¼§m«óRÎ#îÕ8ZrÍðR:ÜÔ0ðE ^w"A
+¢Q¹gIûüÓé¾ÛòlÊãCD¶çx8vÆî\Ô**Ý1Dð.z:yï0ÙEÍ6":¹}8³k1ÙE-çJt8síÚE|²WËxFòé:Ð#a¸§ë6ÍY;óF <]ÔØ
ë3cxòºJX+¢èøjï¸øNʲ.ê Q¸b¾cGÓEÍèéˬah|W1]Í£rq·7À²â3DªÊç@"kZ±«wL\<ÂRO¼ØÆÙÔó_e¢/ªYáî(ô
(Ý})ï¼<C¼ì#¹%$/j¹ÂéIhäÅe
+ÏÖ04Æ«JÞ3ÆØkÀÚ>VHì|ÔX_
kæâ »þÛÏ 4ÒÈì¤ìBããnº(ìüQø¨asݼvãÞö©=gÒ!6¥}\æä3±¡Õº*yÇÅ÷Ø8JBÂâûÂåhæÅ´D¤¥A§ë¤EáDÒÒië6iñÃÒîÀ_×»tùí~yK¼^Å»4Ý
½Íÿ{?ô$Z2®vK]µnm(@Í:+7ÆQö®P{WÎØFÖ04¼ªJ2áUÀJX¾g$ð*ຠûÃN7yxl F+L|N kWØ(ðKDDc£æ6ÚIp®p¼6
+ÇB\
+¸×XÃÐب*)ãjH#~þnÑ [§!.¶vZXÃÐú[¼clrOýaûÐÛ
+<×±½Âùå(Ø>è4]Å¡ËɼçÂ,hjÜ¢^_Uf at z»
+zܬà 8¯»-yâu¨ësæ%Åçö £í¬óÔ¡¤Ì
+Q£g:¶=EG¢æÂF:¶v)2s¸h$Ã2Új#ç°ñ6vÇàñd>|e v¬S¡PNèÎÜN¹·FoLôæÈØxÛ2P#}#
Nb¡7ËpFÞ,5¶6²JYÃÐè*)¡Ã2¨ Øç¹ðoX*t.kí4ù8(ZPKRñÌÕý!ÏRp5gUá'îÑM»l÷°ÌòÎñ¡ýuѧ^8äABõëG:e´=þ7í1âµ%{¤SFk·Ð2@ĸôdrYfpɼOÀ³Í&TVT
Y ¥`T)æ¡QCÂõF*Üû
+YÆ
Z%Ò+YÃÐÀ¨*)ãƨEò×l£®H'uÖnAãú\ËäÈé´,¹s:-3§ªª®(ÁÁõý×»°*ݸ^gtVåABÍètF'®cF§e£ftF:£³víwÀÈæ²ÇþmÉ
+ì4å:0R¸¦=
+0 E÷¥Øj`ÔÜpø®¥ì1¶
°lÜP: ðkU%eÜð¤ËÌK¸áiã:~ÜzÖ0´úV%ï×;\öØ®w¸IgÃãz3»j1¤(AÁõu%9ü°7öüØÜt£(úÛâ˶ÛuÔ s¥Ük¤9o¢ó|}G
+£[0^TÙoRt!%ç+x宾þiÎÀV$¦aJòݪ2»sí§|ÅxfËýÛÉÒ]AÓ9IÕKñÍnµÿÌ&ùý¤äå|ÂÕzËfQúB²:Ó¬^(þÏ×$ºõôÅZ'Ê7>}Ý-³dß]~<ôâ?R2å'ÅÛñ¦¦Å¨x³(-ýK!\¾PQ~ýkó?óÕr·ÙþÿÈa
ÆPT¹É£Ã]øPý
³+¯0ÇqYþþ6Ñ*Þ ÓÏnÁù»ÂW`7©Â{ êk;wU¯MeÏ]./ÃsîrMjî2©¹K©ËEÍ)Y
+ØeBe»eqµ¨Åu¹îiºëIÝP³tªaõ
+·µ¸(â±ô&ÀÇ
+19Q¬p-Õö6·G
+al6´Ù«¬¶ÙºÍb^Æ
+ùC°Y¡n¼6+¼ysÙa·qÆ
+ûgïÁ¤ÉW¾§úª
ìqÖt¯ÃÑk@%¡ð¶H×ÆEP+Ô
áúSîâ\Û/e²xË+¡ØtCèì57»Ú:Õí¯îOjX.´KÃÆcx¨µõ»½áÙHexìJ½Sja ìv(>uzûr°H ÎÕhÁeF7Í®iŶê:!
+£p¬JÁ¶a°R°m ö"@uGÖ0îÞ-]ÕJ²±Ùe<㨵jìõ¦A-ª±Ú·ýÔïgßÎw0ÔÉ/~7x¡VÛÀÁu¡Öv
Z9nËÎ0å³ÖÁ°ÎÖáî(\qÖ£u¸,Hpg
+Cúª¤
+ lêãü5EcÅg¾¶ËzuB}í4Y)ÔÌb¢( Éiç_?KÃWLTO²Â`¯ÐI74KÛ?B. ÍXöae2µeQ¸4c1ÇزÎ6q©¯®çP»
vØí«¼g,Ø.
+xc²â3Ä´
Ë~uÙÚ-hÒR¨ ) Iå¡Ò21Ì*A1àdRôà08ÇIº~ǶÅu»ËÙIÁ¶0u2,²X¢Ê~¢P£CmºCZé¨Ëmó*!v²m[á.C¶Û)¨P¦ÂÂwW
+ÒlÚÇû²Þ¥ËÜr2Ý"|<yõÔÞ17<¥'/Üî
+ìB¼>&¯À=ÒjÅ7÷À(
+"În¬M:¶äð4óï.»ü]Ì~11£_ÌÝàþSJ.£ÂJÍÎOgݹâùêT£zªåi;¨$Ü¿21÷jzPjTÔA¹kBõ6²Êsß
+ض¬í
+;ÑEa?
+?i=?)5pTá³ö&ëÊPÖv© k»@MXm²5EMäS¸çÉÊPv8eAã|ý9Òȸj³¨È\Ô6K Â6+2váüÒNmÖ3Øˬ¶ÙÍz
+vH¯Û¬ÂýÛÛ¬'´Â×f?öPz½`ägû_¶°z.f ¨y.*Ç·/®ÌÙéé´¶r±;M§¿uZ'>î=P&>z¨¡¬ÐÖîÑÑ=w^¬x
+YÃÐ bUIáEâ2äy>´âH æq{e°ªZQ¡ÉajÌÂ1òÉa¼@®ÊZ~L:SÃ;.¼²Ì²¬¨rX
+·tSBïg¡ê=,£Q'µ¨I-³¹ºÚ<⤷Ü7ïgH¥5ßg¡KHÄCÔY¬®£ñp9-!jNËèÛÍf,UÉû
+}`Á®4Ni9AB¸
+fFÊè«tÆÆvUÚÐØí<VC¹¡±c &´Ìî¶
íc -Ð2
+X°¡±]URB'cÐ -Ëæ¬øàeq\òt`
+CëuUòn9c¸
+Þ@¹«¯ÿæ>iè>¥C VÉ+gØêÐ1-
[:&ª?v®pD%N«CÎPmZ*;¸ÂؾS£A«còZD ÎZÒ³jøn¬p.άô1kÕög=üÂ-CL=Âý7ß¿ùçÇÅu²ÌþïüßÿPK¤9X·
+nì°tÚ·/®ÿòæ¯?þöávÐw¿Ý}|ûN[àÕ>Û/Ðù=Lý$<gùÝâ$XyI_ÐIøgzAâWiæe¡¿K³äâg®.áê_ï~yyiú¦8çKk½îré8K,]ßúc}Ø°9¦cÂíÒÕu}ñBË?'ïoùõZyͨ¦¾¡£úÊæÞÇÞ!|w²ð
~=Ü,^ÂÅ[tÚuÄsyïÂ|Ûxè.y%ÿí~§
+h\±(8©á
+©MÅ'EܤHk]×]uåyÍÕÕørue5{E¾\kÑí,0]ð°:'0
'¬Ùñ ëôßñ°NNöïÔ½JÑÕ©"Vu»t·Myû;ÝmyZS9îj+{EU¦
+ÓbmZ\·I
Ú´h?¹®üöº '
+
+z±tC¤W¢.-µrCÜêÍ
+õ«p¬n¸ÒÎ(ÞI¢
+Æ8îçhÏFNEçÈj8G ´fÔt"³`MäYýÎQ%#«ß9RKá`ô¢êõ¨féY
+ïÔÞÖ\
+ç·NëY
+ï©-ÏqÞþrµe5üÞQ®Ûf¥ÛksOó
+Á³
+QÆvd=#4¥¾«4+NPXÀ-c«h¥4ôQî-þ«ßP±D3.
+ºH¨õßâ-Þöö\A')ïÊÇ`»i|}$Ôîÿ/IôðkÕôïâÌâäáÇc|iNØZ£0è¦qQ$ÿQºPQHpha¸78ÒqpÌÈøç³+LòJëËùçôF40å¾\Ú7wÛ:ö.
+ßTï¥`JÁÇó¶Ún}Cz¨ÖJõªl.ºùùôx8J÷|ªùá×%uÛ~¯Kìn¸ãmÚ:Öèõ¶k6t*¾/±{2mQª½jë§äó-¹µeRm)J¾1±erm
+ç I¤Ü
+.°s£þ%IàÉ@Ð_Âïì§HÀ¶Yy®ËtíÁ\QÌϺR×lõ4Ù,F1ùTSÑ#2q«Óô»BÕ¶uúí{LV.Ø¨ç¶ PYÞÚ½t~®i¨çµ¤ú]¥ïÛªhåPCþ*,·®´åàØz¡éà
+Çá8ì9·á8 ÜÔ$ÏЬtdâ&Md8¸ýC%ý·ßoP»2ÃÓk24ñÌ27ÓmxmÐÈNÅûxÓZnÃb`j˱¯ítûH!Wl³Rì¹æfºÁ@Q¦37~(éøToT57ó&i¾@NlÑ+â.°°ÌÎOaND ý{¯ÿU¯+ÉBV0;úºº×Mqé¦äÂgiæC͹.gv97
U®¶,Í6åzÞåÌ®Âvh5³4ªÔKtÑ£+⥰ØÍÓ¬Áï·-vl
+´¢)©ùs!äyûH¹ÂW3S³¾+e[~¸Ý359øjfjþâÉ0?îf~&Á¾«éã×8פþ*4*gOÈB+³Ó4öÃ=¹\<-Ç2èüøøðC õØõÇQF¢~µ}q*{ïasµ7¾>P^Ãkg/»§ãX!d:Î8z¨®+zNï>Î!Ô?Æ`sëhâµe-¨ÑQʳRßv6
+
+
+C¹íNq,½%W1²CÇ î¤ÿ[ú®ÀfCä8t²Î°Ñ¡ÓùÂn%êÒ¢v5B!×W«¿6
W<¸çýG
+B³fW°íÿ¸b:H,ÕLê6±,Q²dÉ,Y Ásüé¥ÆKû¶³åeÉ£¤eé%-kCâÔv¶èä§2uFí@°-%K¿Lø)dz¥8,Ù£dÉ%0gYÂIÀºD./L at RZÆ
+®Ú|uO×æeÏo¦úB¼Ü?Ý\ n/A/]!^óà¥c-Dë.4\鶳åYiʱÒi>ç0\8±oý;颣ÛÿPK|ûóÞ
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/full_cream.gif
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/full_cream.gif (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/full_cream.gif 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,79 @@
+GIF89aâÕ2
+
+
+²²²LLLrrr???YYY&&&ØØØÒÒÒpppßßßxxxËËËåååËËË
+H° A|ú®l;È°¡Ã#Jh0¡
3jÜȱ£Çì,VÁ²¤É(Sªl'
+É0cÊI³â¾8sêÜÉS\Ëÿ)/{
+J´(ÅR]Ê´©ÓyH£(}JµªU«Q¡L½Êµ«×YlýJ¶¬Ya=˶Ûi¬}K·®Ýxq̽˷¯_pyìýK¸ðÛÀJ^̸+â$K¼ô1È3k{s³çÏB-Áº´i¢¶
+¥Òs%´Æ%<L:ÿ\§ÞðHÁ¼njª7
+¢/K'bÌ8ëC8?dºPlO«ê4 @³À¹*ª1h
+lÜôºMÂzûÍÍpÊ[qmJÇîÈ{ÜÈÉÝC7 ÈjdKH°ÀßÉê©ñ 8¡.' ôl:ͱo°ð¿=Bp8úÙ¸Só`$Ø¡o`Ï86ì¢ÿd7Kzmär"Üݲ©1Ùzo7?x¦7ñ·?»]sCë¾Upöþö="Æ-?»Þ¤«Üv
+>x¶9lþ<×£::²zóª<.ôêây"Éñìõ¤nÇùnD
+ÃV
+»±õ1Ï
+Ðf,«âØä×(ÍÐ-¹9ÿ`^zª@=ð=©}6ëÙµä§/x K ãQ"YÑ(i¿B ¥#kÑhph@:$³I^2OÜ"ò7½PnPºaáU©¨SZSÛ£ÞxBN
×Æ@ àüZÉ&UÍO?À>-r']Ïÿ¶klsfü×Ì@®Ä±ëMzX6¥µÄqCUqxt±Ûe I¨Ó^O9Í(D"TwXÈ~0³#{fO¢©Â{<à\ÑâF*`2*ÙpI
+H¥L¦Â<=`¢Kz
+p®ÔõÿpæR*Ï+
+¥DxHÓ¿T:_Aê ÂÓö姤LQz¤ILS´Ô¨Òeªª*GXîzÕ«-µVôR$Õ!gõËXTÖ¤!oåËZå£ÕÄÕ *È 3×øÔU#w-ÊÙtOÝ«Ys2ØV¬õ"UÛªÀ¤±½Pd¥9Y¨ÆIJÁ¬a"¡Ö(à´¨MjWËÚÖºöµ°lgKÛÚÂöM h"ZÈVå ®pKÜâ÷¸ÈM®rËÜæ:·¹u+c ;Ú¬ã¹ØÍ®v·ËÝî"7º®c«;u$à¼èMÿ¯z×ËÞöº÷½ð¯|çKßúη4Ùm at z«ÙßZõ³âÍ,_7û_´¼.)0qÂßûWÁºGL[Íu<À6û¡w,#ç§ÎÈTxCÍ7qxø8 ñDF/í¢,=)±*À;Öi
+A©0£ ãÅÀ±#BcoLlgÜ8qø(:-J=jÀÅôù:¡pÌtü×®é§DÌÅÔõu§|XË18Ü$G4¾43ÀYíãQõPdª+óRÈìò Úá8÷wÎt. [G±ib]c PÕPÌâ±6ÿõÁ©*4£Áåâ8ÒTVq¿·¾K«,³Sñ%dBÌT*qºP%¼7z¼r./¬ARep´©xR ³°¯G1å/ª0²
+
+!«PÞ¢
+ÿ÷'ù»ç/
+õK&Ä1
+(¸q1¦wHÑÛ¶G]·k:³AYb=a3=í'pðÀ2àf185¸{ëàAÖ¦(C(»Ó;v1å#"S>+CGbÐJGlò LXN8Pèy!ñ(Vä#èS#°Ó#)öò
+ñ
+(
+ôH)ÂMIÝ@b2Ïè¿Á(ÿc
+FÉÂ&¥fj!j5"jØYi."ùÓ
+tm¨#åâF*dbmÓDAÁ'ã
+þC(Þà'ÛÀo ñpÞùyHÑhpQ3Ý0#qTó0'Ó6_6 Cr´hÿòXÅ@y
+ì1>RB³KÔ1åú¢ÚŽè q?ß
+
+k[ûiK ëKg
+ûÛ;eëË+cÛ[ùZË!kb%{'[)a+k-K/«`1[¥·3;5[`7+ùA°úä:U j`§}X ×µR;µT[µÆPuØ'lÂ8óªôPA®%$B( ÿ643öÐd' QÐ2 j4ý*¤¶£Ô¶¨ð¶÷$-UómB{R¤g6Ô6ðC3å
+»ioçD¤¿¦ ¿a
·s-ÂV?ª:'ÒiNC"±i¨CJ<ÈtÀÏÑëzGékL$j@tоvLË#NtjïK¤`ÂñHI¥Ja%ò)r¦ÏòÅ
+GCÕ,Ú/Îë¥.½ÄCâ6Ä:¦¡Ë©<)¥ÖƶÁÞ¡x<R,T\Å$®
+dCPPÀ:ÒQ&¬Ap³±ù©´Æ5)!lÜ0t´$pÌ´ µPvIx72(âæ£ø*=êÇÃÖóU°Ë²LÙ`¯<˸Ëÿºü³à OeH13ns&q+»ÄK"Ò1ÜLk0,7,1=BÈÇ"%¹T@,Ý §Ä'M7",»0ºunÁËVC8 ænv¢1ÁÖ!'÷v
%âA-,xrÆôѼÝÐ+ÖBäG!â'G'(¢;m#"¯BÄ9#Hbm"QÜÊélë¼oáÎkS5ÏB"þk3(5çôÒ9ã#:)JÝm:¬Æå º
+SG23PK¸Á×:?ô)$4¹ÉzN-ºj»3Oíº
+^¨Ö¥Õ3QÖõqÖYÖ;\«l-níp:×Ü:ÖDq×M&ÍjÍ=ë׸×<ý`ZÝÎ_M
+MuÝ}ÝÍmÍ~=¡}£]¥Í©m«M]¯½±]³ýµ_
+¹M»í½=·ÁýÃÝÅ-ÇÉíËÍÍýY±+ÝGüÜ;íÝb¶õ (áØ%®@vzäHÓ³|]®Âá:\ÓÞð³öÖ:öýî;Á-zuHAëó/ÿ'F@ëB/lÿ=ÕmV2/õòÂLvQPÒcÀ%p(\²P¢5</a¸.G,H at t(: Ø
+ÕRÁ9yB³"â.'âa&âç´203ãäî
ä¨õvL¶;uRaÛÅ@QO~ÞïmîVN6qO·&BÎt-i2ã¿äA>¾MàBwº0± (Ãâd8 f]s¼×s¾µR&ç
+Á
+Ý3r¾9¥~Y+ó(>f
+ÿ9Gsmô,46d#sÆ2L?ªM#('èÚÅÎbF ¿ß¸±IÁmlGc3+(£9sô*PC?
-0=6Ò>ÜD"8¯nCÉI¶[íÚm?é3ãëD1ëºUëzâ¯[Ï#svn^¬(%ùm5oôMqÄnð\a´>»î&Ç{È1°è¨à³A?/ø¤)0>æ>/2c/ÙüÊ\R;yÒ)0r§&n ÿ
+üN·ñý®
+(è#ra"b(s*ZÃèßÜÜãóCnòÿfÞ+¾±«Ücftg>2å¯'#Þ)ÐöK¼K1ÄÚv÷ûþàáï(."¿iIð)¢9t8÷ÓnÙ ³0
+;¾¤&g?H¶rÆjC uG<¶ýÿâ¡ÝÜÌ*ß_3HüÿÒ
+¨áqù
+hßñùÞ÷˾òøþµî¼!#%ÍØîÞ&13Ãìô:ñ5CÓ(À?ES'ÛU_aÅ*Û.cmå8=ue at o}
ÏX»1gÝ¿rw;{aO蠟
·\±»á·j½
¡Ç_«Û®Ñaµe¸ÛåÁÀeÄçaËÍñCÕ¹ØõÓô.@yõî¥o@
þíy¨àÄy-bØWÆE;zÌTQ¤7%'ml%,[Î!ÙITîySÌKfþüeS(æv½âS) Ma
ÿªæ(´¤MN
óT«(©]ÍTÝuUiV°Äð<OµbÄê"[ÔìÛ1\íFú×Çs|ëòýWp¢½
cÄõ4Wh`Ä1?¦s¸°âh
#,YeÁõ0þ ²
+UÔQõPç*%UÕUY½4ÕVaUÖN?ÕÖ[E54Á×_µôÕ`-6Q]s3VÙea@^¿ðÙiÚkcu61l¹Í6O{íVÜU×\MµàÜu7MÜhÙ×ÕpåÒtíÍ·Qwÿ¥Wß-`}ñØ`~Qõ×à^XÞ&øÛ~áXß->â8á9ã»Ýd=nnä¯]åiM~¹äsYfem¾¹Øu¦aî¹å
¹Ö¢¯ý¹f¢Æé¦w>êe^.ç©e½kXyÞúתýÒÚkrÛÖ®ÍlÄN[Ô¶Ýí¸[]{¥²éfî¼3oRíÖ ï¿GÝðIý>\n\qN
+üÑÄ%ïñ°¯ÓÈ5_òοíÌAóÒýõÉE¿äÕ7=öf¥ÓÀ"ÝöEe]õÝm]ð×´÷Õÿ/ÞPÜÒ]yCG=ùçi?hâ©w4úÒ§ù±Ï~{лWþ{¹Â§~üÎË/þüÅÒ~}ÍÛþýË°ÏÑù¹.
+V;ý1ê~¡ß×
+äÀfYüã¸À
+
+À(ÔGÈd0
+ðC 0
+
+¢Qr¡
+R¶S§ÛYÒ+¨A5Ô&yÞ¤1äÔiLÙEÏCiÕP4tc
+íß?A*KB=±¥Úä.¥´T`AÒW¨ç õE¤
B$ÉfF²~¼l»:Rph^ûMÃ2«Eè2Ù.[Å]§I>Ñç,ÔEÂB
+>Éþ±Ô«U ÿÉ°¥p`4õ)DjÕb,E
+@'mywe®
+\ È!à`(qö¼
+`E7ßpào½Üò.º»ó²ïâ>-ëË;3òÒ¿5¯Ì¶{³ôâ?19QmæÛ¹gÎY}uþòlùL+,cÐò34)hDL7t
+çH_º"ÉéBù9o&§ iiQ:ÓxÞ´¨)MjºÿÉ:n¦fªw©êUÃÖn³5ýpÙ=º×iûuåbÝêÒÛlÇ\²<fÍÙö°9=m¯U[q×Öõªµ½5nÎÛ ÞuÀ}êWsºÜ15¸Ó}ëu_ºÝï&v¼=oI×ûÜÐÃ7²h~÷PáÆÚ¸»ìß~ûÞÑv_Àù<p|jw³ÂÃÌðlÿûÙ³ÄûMq¨Yüϯ´¹ Îk[Ûãù¹EÞ4Úä1GÍ6sº½|×8Îk]ó+Îç=º¯
þ
ÈéMwúÓ¡u©fJúÕ±uO½``ÀÖÁv±½ëÝÐö@Kÿímw»AØþv¹Ï½q§ûÝñî»çï}×ÄÞýxÁI<&ÀáxÅ/ñwüã!yÉOò·üå1yÍoó÷üçAzÑkÞ2ýéQzÕ¯õwýëa{ÙÏöµ·ýíq{Ýï÷½÷ýï|áøÅ7þñ¹P±/ùÍwþó¡}éOúÕwzD<xíoçþ÷Áov×
üåOLöÍþÁ{_ýíÇ;ûÝÿ·Ã_þõG;ýí0á_ÿý¯ÿý/
+0q°0Åý$°%-05°y=0QÿE°-M0U°Û]0±e°m0ou°U}03
°!0 ý
+Ï
+¥°
+á0%
+µP¹°ðÁP
+Å°þ@
+Ð0)XÂ
+)F
+ñ
+`" à
+(@
+NóY
+ #_à@ ÎÐj11 5m1,±8§839±4³9Ã9Ó92:]p:©Só:M0;µS¹³;=ð;ÁSÅs<-°<ÍSÑ3=p=ÙSÝó=
+0>åS
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/full_cream.svg
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/full_cream.svg (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/full_cream.svg 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,429 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+ xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="354.331"
+ height="336.614"
+ id="svg1">
+ <defs
+ id="defs3">
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop128" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop129" />
+ </linearGradient>
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient130"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ <radialGradient
+ cx="0.5"
+ cy="0.5"
+ fx="0.5"
+ fy="0.5"
+ r="0.5"
+ id="radialGradient131"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ </defs>
+ <g
+ transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+ style="font-size:12;"
+ id="g659">
+ <rect
+ width="212.257"
+ height="57.2441"
+ x="17.9576"
+ y="100.132"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect137" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ transform="matrix(0.743454,0,0,0.482981,6.46949,52.2178)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect132" />
+ </g>
+ <rect
+ width="325.86"
+ height="63.6537"
+ x="17.4083"
+ y="15.194"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect136" />
+ <rect
+ width="325.86"
+ height="63.6537"
+ x="13.6713"
+ y="12.4966"
+ style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect126" />
+ <g
+ transform="matrix(1.14345,0,0,0.729078,-1.67818,105.325)"
+ style="font-size:12;"
+ id="g164">
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="16.6979"
+ y="222.966"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect138" />
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="14.7335"
+ y="221.002"
+ transform="translate(-1.30962,-1.30992)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect133" />
+ </g>
+ <text
+ x="170.824753"
+ y="58.402939"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text183">
+ <tspan
+ x="170.824997"
+ y="58.402901"
+ id="tspan360">
+Application</tspan>
+ </text>
+ <text
+ x="178.076340"
+ y="364.281433"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text197">
+ <tspan
+ x="178.076004"
+ y="364.281006"
+ id="tspan421">
+Database</tspan>
+ </text>
+ <text
+ x="68.605331"
+ y="138.524582"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text216">
+ <tspan
+ x="68.605301"
+ y="138.524994"
+ id="tspan384">
+SessionFactory</tspan>
+ </text>
+ <rect
+ width="67.0014"
+ height="101.35"
+ x="196.927"
+ y="89.2389"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect387" />
+ <rect
+ width="67.0014"
+ height="101.35"
+ x="194.633"
+ y="86.4389"
+ style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect388" />
+ <text
+ x="249.108841"
+ y="173.885559"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text389">
+ <tspan
+ x="249.108994"
+ y="173.886002"
+ id="tspan392">
+Session</tspan>
+ </text>
+ <rect
+ width="73.0355"
+ height="101.35"
+ x="270.995"
+ y="90.0018"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect395" />
+ <rect
+ width="73.0355"
+ height="101.35"
+ x="267.869"
+ y="87.2018"
+ style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect396" />
+ <text
+ x="328.593658"
+ y="174.715622"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text397">
+ <tspan
+ x="328.593994"
+ y="174.716003"
+ id="tspan563">
+Transaction</tspan>
+ </text>
+ <g
+ transform="matrix(0.29544,0,0,0.397877,9.70533,103.96)"
+ style="font-size:12;"
+ id="g565">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect566" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect567" />
+ </g>
+ <text
+ x="25.592752"
+ y="204.497803"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text568">
+ <tspan
+ x="25.592800"
+ y="204.498001"
+ id="tspan662">
+TransactionFactory</tspan>
+ </text>
+ <g
+ transform="matrix(0.298082,0,0,0.397877,99.6898,103.96)"
+ style="font-size:12;"
+ id="g573">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect574" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect575" />
+ </g>
+ <text
+ x="134.030670"
+ y="205.532791"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text576">
+ <tspan
+ x="134.031006"
+ y="205.533005"
+ id="tspan664">
+ConnectionProvider</tspan>
+ </text>
+ <g
+ transform="matrix(1.14345,0,0,0.729078,-1.67818,38.9539)"
+ style="font-size:12;"
+ id="g587">
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="16.6979"
+ y="222.966"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect588" />
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="14.7335"
+ y="221.002"
+ transform="translate(-1.30962,-1.30992)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect589" />
+ </g>
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="25.6196"
+ y="206.028"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect594" />
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="24.4229"
+ y="204.135"
+ style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect595" />
+ <text
+ x="85.575645"
+ y="282.300354"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+ id="text596">
+ <tspan
+ x="85.575600"
+ y="282.299988"
+ id="tspan607">
+JNDI</tspan>
+ </text>
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="236.937"
+ y="206.791"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect610" />
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="235.741"
+ y="204.898"
+ style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect611" />
+ <text
+ x="342.093201"
+ y="283.226410"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+ id="text612">
+ <tspan
+ x="342.092987"
+ y="283.226013"
+ id="tspan621">
+JTA</tspan>
+ </text>
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="130.134"
+ y="206.791"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect616" />
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="128.937"
+ y="204.898"
+ style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect617" />
+ <text
+ x="212.445343"
+ y="283.226410"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+ id="text618">
+ <tspan
+ x="212.445007"
+ y="283.226013"
+ id="tspan623">
+JDBC</tspan>
+ </text>
+ <g
+ transform="matrix(0.823795,0,0,0.823795,0.120302,6.19341)"
+ style="font-size:12;"
+ id="g637">
+ <g
+ transform="matrix(0.499515,0,0,0.415467,-0.237339,5.61339)"
+ id="g167">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect134" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect135" />
+ </g>
+ <text
+ x="33.749969"
+ y="50.589706"
+ style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text188">
+ <tspan
+ x="33.750000"
+ y="50.589699"
+ id="tspan635">
+Transient Objects</tspan>
+ </text>
+ </g>
+ <g
+ transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+ style="font-size:12;"
+ id="g644">
+ <g
+ transform="matrix(0.297486,0,0,0.516482,230.251,36.9178)"
+ id="g364">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect365" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect366" />
+ </g>
+ <text
+ x="277.123230"
+ y="85.155571"
+ style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+ id="text367">
+ <tspan
+ x="277.122986"
+ y="85.155602"
+ id="tspan631">
+Persistent</tspan>
+ <tspan
+ x="277.122986"
+ y="96.155602"
+ id="tspan633">
+Objects</tspan>
+ </text>
+ </g>
+</svg>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/hibernate_logo_a.png
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/hibernate_logo_a.png (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/hibernate_logo_a.png 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,212 @@
+PNG
+
+
+IHDR
+Ü:
+uu
+õ«£(ª©®n^wo¨
+
²tYÕtajëΧC¡ôôÅú觡®®¡nu'V¤6TyÏæ/æòùØKÿÀ¡ÏþWËç³c>óųãã£cñýò¾]Û¶lýæ¦_ÿ7ݺeS¤B+¥\¾00<:EÑ/æë¿6>Þc}ò[ÍÀðð\|ßóK侦u5ÕÕ
+õ«kª«gË3¿§ÁÕüd!7:ÅKV¼gmèå$æÿµõb;+å&Ç.::
+_Sï\)NAüzö,N+ïi\²tyèeé>ú(tkimkk?¼úî;ÿàáÐYïÿwÏù7÷ÿêó¸ýû?ðÔþ8O¬H³ßc;nÛÍß|ác;.ßûÁßt÷öÅv)±¢¦ºyݺÙ'×Íëîm¨¯«°N4¾sßýþC§H¿ýO:Âòk#úÇά¹éÞæu÷67Ó×
³ç;C§o÷ÿÆ[óÄÇúnlg¥ÙÔû#§þk°ïÿKUíùÿ÷P§Ç£ëø'²ý¡SU
+·ï~6æCý§Çfn,í²ãf½^ºüavª¦ae.t"æè?ÛþÐ*êa+
+RÓ¥]Ëk¯_ÿãïýÑï®þèÃéyçòdÆoÈ
+³%ýõo;÷5ÛºeÓÖ-ÊhU&i"Ûïm )<6ÀD¶ß× @eÓ¥ZOß¹·Ît]ÿÓékÑ;#nü͸þ³í
+Ûìä½Jíø˯¼¯iݮ۷nÙdï"P:ï
+¿;4<»äó;¶77Ûµc»½ÀÛ@Ò,é|SÑh¦{óÌS¾*n,ÕZ^k÷W:ßlÞWWt5Hnhfº0t¾sÃO
+ÚlIÖÒúú®Û·nÞ´kÇöÐXÁó
+ÛVÞ³6tÕµ«a/».éÖT°;C \¾p¨ãð
+ÿÖ
L¾ðÁÊóðz»ZCG
+
+¹Ð)nl4Ó¨<º±´¾øæÑÛ5Uøhh|yÑó°HÞ@Å»Ë÷û?<rìDè @Z¼u¦ë{?ø¡¡ÕÄÊ»:Df0¯Kx<
+Ï|PĤ(ú϶_¹:
+æ+ä&.íëj~r"[Í*7
+>:
+~XvüRv|¼§÷\vl|`øbÙµe&Vh"ÛÍô44n
+nUYßÚ5éöà ÜéÆ*Ê¡7b~[u¬;÷
mwÅy"É>
+
+u«¯·Éå=½}³Ý|¿áÌ2±LýgÛW5l´D²ÍôÌLB§X¸Bnbêý÷¬
+dáÖ4n»ûÆÐ)hf¦õÖ·ÆæKë'BªjV
Prw×6n|p_èÁ¬,Û¯åàtc#/ê8ó¡2ù]¿½¶ê®©ÏåæìÓ
+
+Ù÷¿ýÒWyzM}]è87p%?rìDè@üã7?ûç}lÏîÐq>Õ\þd,]s[Ïw^ÍONáÚÌÕ²¾llVÔ{
+ÙcÇCGà¼$ù*£U.d3=¡S
+ñÊ«-O?úöØw.O*ä&.í
+æÈön&3ë6¼Ò© µtcàä®î ¾:w5`
+æ.ôm
+sôô(¡];¶'ê{NE'Ïtåò
Ð)ofº0t¾3t
+¸±
+¸iìã/ÝXÙkim"¢èÓÙÐ/3pjêýÐ)
+
+tceìPû¡#ÜÀß÷L~xgUèÌQÈM¸
+¹ ×û#ÝX¹:rìDw"ï¾9ù2§¬ÀRk^wïÞG_<ÖÓç!5¤ÈO|qÛÍa3hålð|§§ö$ÄÄX§Ü]Ûxwmc}\fÐZEò£+K¹|áPÇáÐ)>ÕÏ/䦣ß9f¦>0
+æ¸<<:
+ÝX99rìÄ»CáSܽ>?8ç;¯æ'C§
+·5Ü
+Ô¹¼<笯R¼;önìòdÆÃ2¢+¹|¡¥õõÐ)n[ïP®ðÁÊÐ)¯¿Ç ´¶nÙ:.5ÕUíÙäè+¹|._rt¹½Û
+
+ï´ceb¦Zº¬jå=k¯ÿéõýqçZ5
+¹©÷Gb>
ÑW^m aQÞ<=rÇËB§`Bn®y
+n¬±9£cJ£l;?Ù¬ûʱ(Þd
+æ³k
+ÁvVÕ¬Z^];ï/ÎÛ²ØþX$ÝX(÷¡±Y'z&?NÁ3Ó
¡ó¡S
+³SH³ºP7åõØqZ^]ѱÌà©«ùÉÐ)¨pÙLÏÌtLw Þp}âÊ{Ö.]VOëf¦ÙLOÌ°
+ïô
+*ÜÄXlg¼çÆëb¿r,÷Ó%Z._8Ôq8t¢¹ÉÿòW+B§`>»æ DBMoÔTÇýi 9´ãÉTÈMD ÍtO]umæjf ¾í¼llÖÝÒTfà,
+0:6ªH<ÝXrµ¼Ö:BI}{ì;
NÁÞ@Å°N
+¨©Ðçòµò¤¤sëXä
+jJãj~2Îrèæã«ê´ÑÙ~_Y
+"H!W¦5:Ù¬H ÄYUÕ¬Z^]{Ðh©Ñ1Ó%TKkeÍúù
ÜL´"t
+æ.ج
+ïzßt"Îh鲪µëºªÕ$n,²ãÚÚÓ846ëÒå³S5¡S0_ÿY£c
+%ÒåȨ́ý¤EÞ² ×f®ÆY-`GâÚõ-]àÕD¶ß½
+r.
+ ¢\¾ÿB×(×ÿд¼º6iõØåÉÌÐ;GC§ é¦Þ¹<í¸E[+ïY[U³ªXanÝÌt!éÿ\
+-ÎËƪjV¼gí"_$ÔÝ~SfäÐ
ÑÓw®;Ä%ÉeaúZôÃNÁ|>-
+Çî®Ûã?´Lr·òÃ8:8eÍ>frìÂ-þÚ.¢|-¯®½»¶qñ¯³
+C§cfºÐ×Õ:É2íó¸â{
úså@BèÆb50|ñÍ£ÇC§(S
ÆNÁ|FÇ
+¹g;B§
+_²tùÆ·Yq4Óí³)o¡bUͪ÷¬-Ñ76ªu»¹l¦ûÚ;D
+[=¶g÷ÖÍH¡Æ«6N1_oWkè3õþH!7Ûq%íZ^]{wmcé^ÿÓÌL²njIè
+-ÖTá£ó6þfèÌ5x¾³¡qÛ¥ËCb:y¦ëä®ë?N1Ì:rìDKkÈÖ(VÔTa
+bãûNe:Å
ÜÄ
³|"t¹Ô)õhWCã¶8ïN»n"Û¿výCñÀ,ÝXÉj#t
+ñ÷=Í¿YWdä<A
+¹¡óÞPrùÂÉ3]ÃÃ'Ït%gâ_1DQË^yõ`
+ûç¾rÀw¤ VÞ³vý&mýàùÎÆæË«kC!nq^6vwmc©5®ßä
+½ÑL÷Æü>_A
+À'
+_Ìåó=½çrùüÀÐÅ°wöÜÜc{v?÷¡ST¬gºzzÏ
Nºº½<:·m`øbËkm iîWÔT?÷oJ!-Yº¼éGL·ÜÄD¶?éihÜ:ñëó¸R^6vݪAº±¬navÍo豲ī(tc%t¨ãpròTïýÁÃ5¡S0Çh¦»qlgmýÐA
+ÝB×f®ÆyÙظ.8_»þ¡þ³íñÏe^ÌL½?²òµ1¦HÚÚáRÓ
n¬T²ãÚÚNQ.]þ0;UÓ°2:sômè:
+eÇ/<ÓuòLWw½Þ×´Î×ä¨ßÐؼ3ÈüpuzLdã[¨¸tYUë:×êÆF3ݪe tc%ÑÓw.iô«$Ó×¢þpËo
ÎÁ\ýgÛâZw
+¹ ö¡+×ÚBG¨p'z&øú»¢«¡ðOf¦6i
+æ°I
+]¢hëæME{Áá¹|~`è×ÿ;0<|%/ÖÚWyºÿ*(¢¦û÷d3Ý'3¡ÌÑ÷vëªVT°lCcU5«â¿
«±ygn,éÞøà>_;
+î
+33ż!¬¶~CcóÎÌ@¬;î>ÓàùÎÆmñû±56ǽPqVC㶠Ù~Ý@Ìî ¢dÇ/µµÏTá£_®ùz»ZCG
+u«Cgø+jª¿þü³[7o
+ÛÐtÿl¦;È
+¸è?ÛÞиÍûÁJ·¶iÔNÍZÕ°1HMÍt7Ý¿'þsRK£P4-m¡#¤ÔÏ/äf"·%ËÌtÁ&
+
+ at lÌA._8rìxè©6ré_þÊèXâë®äòoé:øÚë/|륿û:ÞÈ_
+
+ Ú¿ïñoÿé¿Qµî2ærs}o·@qLõÇvÖÒeU
+[c;îÓ¸r
+tcEÐÒúú\>t´ëxë½Ðo"ÛÍôN
+³ñÁ}¡#Ì73]°i¿ÜMdã«jªjV%ç¶Ææ0-]6ÓQnlQ;ÑÝÛ:¿6}-:s.w×Ï
ÂÁSWó¡S
+-¯®
+293]yV µPÞúúý/Y
+5üζÇU¯9þkÇù½§¾:
+,ÒúºOí7+K.ozàÑþd1¼<zçhÓý{JôúµõJôÊÄ9ÀtwmãòêÚØ»ëwùjÍtoÌïKÚ¿
+Êc§â¢ì}äám[6NÁ¯5Ôþâî]¡S0G._8ôw'"7óÀí{whø[ßùVÿ
+,ж-ÿô_ûþ·ÿL1M÷ï ²îæÎwºB©ì\ÍOÆ95Õ¸>YCcQ-Yº<ÔÇ'ö
+nOf Ö=I
+IºlìºU
+ëÊ1èÆkëæMíÙ:ÑÖÍv~þ¿
+9²ãì¹þ§>ö
+I»·)¢ÑL÷ä+ÛËI£Kk·-Yº<¶ãnÝÚõ-]Vÿ¹'3Wóñ*º±"xòÇWÔTNvÿóïï
+ù^þ?ÿÿéèظz
+qà©ý'ÏtF5ÕUÿbÿÿ:ó½rðÿùä_¼Ëê8üÜWÄ
+¹É±µõb> =ÌͧöRÿò÷ø\õÐ)ãàßþ$ûþþ7ïé;s
+uuþÿ*Ãúºººæ¦{£(ÚºeSMuµ2¬òÄ9sÝÆ÷e3ÝA¾Þ®Ö÷»6s5Îq¥P#Y·eyuíݵño(.^»þ¡ÏH ÝX15¯»÷±=»ß<z<t´ØºyÓö;¡S0ÇÀðÅ#oöÊÄÖ×wíØ^S]C$
+ÛÞkZ÷Ávfî´3u;³¹3nw¦³sÓÍv:½Ùnsí¢Ýfí"¶3øM¼öÚîØîØ2®ùãg2¸6G"À&÷½qDqôûüÎ9¯×#ÛÎ÷aÞ¿Ïç[Û÷ì *ÕÖMÖ¯NQö^zå5[P=ò¹ÜR¬ÛýÑÒèÇ_föíÙÙ÷;³§Þ,ÇÍØsÿòOþôÇ×C7ëáÛßЩù\.:×qæììW¾úõßûí
+ÔqϦéÃ!?ÖÿÓ'_îèÙ\S[«%94vgC[}®!±ãnE[ç}!óéýÇýNvgC[
+¯Ø$ýtc%ÏeGö<½7:HåûåÏ~¦å®Îè,ðâÏ9}æ?xjÿ-7øY^EZ¢qW#G¯? ÜBsS¡¹éGÿ{uâôG=rôø³³ÙnÜ
âÜî''ý<ýfuu¬òGisøè±Ég¦<=ÆRè^;òêÙbËæ_ÿoûKuR6ß8_<WªrçÎy=±ãÚ:Ëch,ÉÔÔÖ·¶
+$YþÐôÉ;îÙü¹PFjj³®±d> okmiNQáò¹ìÛ~>:çæ'ÿfßM}ʤ4éj_5:¼m×ç'¾üÄ¿ø?üÒÃ;¶ßÝÑêú=¶ïÙoE§
+Ôв:
ë¦O¼|þì?䥲ùƼ w?
r¸lìÝ!ç&¼å zèÆÄ®Ñ*ÜCß[¦þæé,ÞÔ§¼øÊkG
+ÍM£ÃÛxüwþíÿø×w>òlÏÓ{O~3:PÏøíÌè^;R[ºíN~÷ÛÑX ɦµm ¼V®ì¼7ä7Ñ»ç§/ÎOþ\§[ý½kúz£ST¬BsÓ¶[£S°ÀÌìÛ^zu8ùôTÉÃ
+ïb97óú['ÿ.:xï·¼®¼ÆÞyúÄË!çT6ÝØR1:¶t¾ðk¾¶©3õÍ_¼xiøÆ©ÓÖ@P
+ÍMãc_~"¥
+?R¡Tò¹l컹3gg¿òÕ¯ Rì¼7j)ÜG8ùÝo_¹|1:L²CcµuÙB[bÇJkP7rÏ@ÅÓ-BsÓØÈPt
+Ôß»¦«ÇL^º9vüÐkGýéû=àÁX
+^
+GÇæçNÙ¬I0å84ÉdZV\n7_<WªËù
+ÍM»>yñØ
âÜW¾úu»R)ÚúnV>ñ²q±¬^¢F¯J¢>×pgC[òç^¾4ÿÖÉ¿Kþ\
+¦[r;Æ¢#Tßxh¼.·<:L}s²ø½Ë%y©ÃG9v¼$/
+·¯»rùbÈÑ
+QõØôÉCΨHº±$¶lLËåhýºÁöOD§`ÃÿêKÇOüe=÷¼5P
+Óѳ¹¶.]ãVóÅs§¾ûíèU'ÉÆ2q K+j+i¿X
+ÔÔÖ'vÜÒ)´
+TËï¾8w>ùs*n,!ù\vt8øIÃ2µã?³¼¹5:L=ýÍ,.ÑüÎó ÜmÙø@ìÉÁïÅ{,úBÁ7NÞýäÀ
+GÇN~÷Û&cäMcµuÙB[bÇ-µÆ^9É_2ʦKÔèȶèeæ×Æ>S[¦&¿Q¼xiI8|ôçPîò¹ìc>àÄéÓ§CEZ¿n0üⱩý,M¥¯XÙÙ³9:ÅÕNKJCH34ö¾B[6ßü¹óÅsçÏþCòçTÝX¢ú{×lÝ´!:EÙèï]3¸þè,03ûö¾$pÐä3S6APîºÚW~ïçAX
+£ÃCww´ÇføÊW¿>3ûvl*IGÏæ>Âô%à½wÞ/K츶Îû;+AmÑ1Ð%mb|{ìú2ò{0:WûÚÿY29;»ïÙÉ
+¤À+Ç®\¾r4@ŨP¥Ö¯èë=|ôXt4*47mÛº5:çæ½ôjÈÑOO=ñøï
+
+'Ù[ó];
+2¦4:<¾¡>m~ëWÀÕ¦þz26À
âܾgÄf
+
+¡ã¸º±`£ÃÛZ[£S¤B>ÝöO¢S°@qn>=[Oï
+åsÙ4<õèâ1Jeeç½
îè2:V*n¨ª0¦
+;¶GGö
_ÉUö|ã//E§XàÌÙÙ}Ï~+:
+ë£S°@qn~rïßF§¸ÝONFG
+&£«}Õ}÷ÿ\t
+}{ßó¯F§¸!nP
+éÑÕ¾jld(:
Ç(ÍÙ|ct¹uìf¹ªâñKptc©ShnÚ²±òGǶl| ½çÑ)Xàðß¿zäÍè7áÐsÏçlK lÌÌÎ&h>W]A:M
+ôõF§pñ%PS[ß½v$:Åݬs3*V¸ùâ¹÷Þy+:@9Ñ¥ÑèðPønú%ÏeÙ«íÞó×ÑnÎ
âÜä3{£S
+9x_¡¹i×ç'¢SdÞ8uz÷SÑ)({}ãÑ>tfúðù³ÿ¢<(ƪÍ
+üFñâ¥ètøè1oòH¿#Gcͼ©ÊÅÄøö»;Ú£Sd&Ù5ÃJÅèèÙêÜÌë?«ÍÆIsçß=?èAnn,½ºÚW¥áéÂÒêï]Ó÷ÉOE§`§ßÜ÷Ry?X´ïÙŹùè
+éoÝCß[öüÕS3ï\NQ2/¾òÚcÇ£S
+*I>Ýõùø÷w.ãÖuôlÎæ£S|àäw¿5©b½^urÉÀÐþÞ5iؼq+
+ÍMÛ¶nNÁ3³ozéÕè%6ùôTt
+q«
+mýéÖ²<ðÇ«ZóÅsï½óVt
+´ÓBsS-\þÞ5]÷ø¹Lº9vüÐßWæúÁÉgöZ@zÌ̾}ð;1ÝX~ò\S>ݵs"
+}íÉ=.ãVô
+GGø©«\¹|ÑðP5Ó\n¬l¥á½Ó"<ö«¿«MýÇÿa©\(Îí{ö@t
+
+Úµóá4lyñ×ö=ûè«Úúîµ#Ñ)XàâÜùs3¯'ybkÛ@ÇÀ;ù|4ÝXØ1á&<ôàp]nyt
+úæäÌ?£S,¹ÃG9VªP.;nhøhù\6%[{Þëâ1ÐÖX
+Ëóß¿x,:åª>×ÐÙ³9:L&óÞ;o½{~:ÉM
+~´Àѱé/G
+~º±òShnJÉs
aýºÁ®Þè,päØñN¨}Ïðè+
+ë£S°@qn~rïßF§3ùôTt
+9 åtceltd[tkø_GksË£S°ÀÔä7ß»"Ìá£Ç^zåµè
+=£ST¯/sÓØüZ%üo@¹Ð±þÞ5[7¥ë2þÞ5÷ÝÿsÑ)X`föí}/NÌ{
+ÍMÛ¶n
+À+ÎÍïûÏ/D§H}û¿2vè¹¾øÿgJnûQ}½nÊ31¾=
+;B2Ìî§&í'gV¯lªÊŹóïNòD§ë¾¨£^¹ ~º±
+1±#òIáß|èOçöü»¯¿w9:Eê>zìÐs*C
+±ß
+K$Ë>öè#Ñ)2qlVLFòµG`ÇSÖ"¯yýâÜù¨ÓRH7V!ºÚWE-Üèï]Ó÷ÉO
ÍOrâôþ¿ïF§H©}Ï(ÎÍG§
+*ÎÍOþ;èe`òé½)¹¼L&sæìì¿þ7Ù,ËçºÚÛ3LWÇ{ûû>(Ìò¹Ü-.}{fv6É8õfqnîÄ©7gfgË«ûQïØn"T|.»ëóÿ:7~½ñØÿNtÊÌêµÃg¦'<ÛT=^g¡â-ªÏ5´¶
+D7>¬xn¬ÒìÚ9ñG_þÓdÎzèÁá;rË94õ7OÏüc1:Exñ׶;n¡@
+](ν¿:ìĦöøI<Ð×{Ý,Îͽqêt©â¥ÇýëG·E§
+ÊLwÿHm?¼JéÊå _6ÖÚ6PS[䩦¶>ðζäûTtÒU BsÓØÈÐÑß»¦«çú+HÒcǽv4:E|foqn>:
+ÝIWÁ¿Ó'^¾rùbÔé
+ Ìèð¶¹j1o:=ùÌÞèÕk³ùÆèãÜ
åªÐ68Fð¸!@:éÆ*S>_ªÇ ù³YÖTX¢gq<xäôLt²4µÿÀÌìÛÑ)
+ ^>}ìÑG¢S|ÀÅcܬÕ7-Ué/'|¢¡±Òjl [«xnæõsç£NH ÝX%Ø1Vò×üß?÷Ku¹å%YnÅÔ7'ß»¢>zìȱãÑ)
+mý¿èÆ*YïûKzEWûª°Æ']ffßÞ÷ü«Ñ)ÊÑ1
+7±£·ýæç,á«Q{¾ñÑ*Á³³ûýVt
+
+-«fÊÚ{ï¼5_<äv`.ÀßÓ'Uªn¬òåsÙ[pÇ/~fyskIòP*SOóÄÌùèåàw÷¬+
+GG('ÉúX¨¸ÔÚº"§'_Ñ º±*21¾}kèíÁ-K[ñµ?ÿ³èìÌÙÙ}ÏN@ùá¸=ÀxìÑG\<F9jhYm2é]¹|qú
¦>×pgC[Ôégtc@µÒU|.»eãÍýÂÏol»çKÅyñ
ç¼9¢ÂzîùÙ·£S
+~p>ý±_\Ò<,ÂäÞÿ¡ò](Î`©mÝ´áÇ×íb@ mÙøÀýë£S|`ÏÓ{;òPkhëÔÁ\ß¹¤*éKFì×ÙèPtcUçÆþòÐÃwä-inÖ¿zjæÑ)ªÂÁï<ï<
+ò_ú½ßþç®ZWûª±¡è8|ôØä3SÑ)(
+-«mðûÉ÷øåHRlit¨Bº±jtÝwJý½kú>ù©Äòp#N~óÐß[ñ´ÉgöZÀhmi²AHØÄøØìIÆÔþÖsºûGjë²Ñ)ÒèâÜùwÏO'ybkÛ
Iª©,#]9T!ÝXZÏý¤ÿõ7>÷`a¸{þÒ*
+FãÛ=~æl*¶PLí?ÐÕ¾ÊL-×Õвºë¾ä·¦ÖôI«E¡m êê¯Ëæg¦¯ì¼7ätäéƪZï¾ÞÃG½ÿ·
æ¦m[·ÆF"Éd¾ÿ?2»ýý¿}ûÐK¯ÆÆ!ÉL>=õÄã¿xww´÷÷)47÷÷1¤_>}ìÑG~ÿÿ8:Èv?5ÙÕÑî¿\W÷ÚéÃ/¹¦.Édf-Kjë²
+(
¶þÚºlÔ¿ùçf^÷KTÝXµÛµsâ·ÿKïÿõ~--Ëè«ÝÇnÿÁ¥ùÛê²Lfêÿ¾xñRt 2o:½ïÙoo@Òúz-M
ææ®U]ííæòÓÕ¾êáÛ÷¤cOøûyì목ïèÙüúýÑAâÍLI¸)qÓX¬BÛ@ÔÐäéÃÝs#õ¹Ó¦«v
榱¡©ýú{×tõôFÇáºü½L]öȱã^;
ì{öÀüH ÝÝÑÏåº:Ve2þ¾5ù\®«}Ut(Þväèñ®õÆ©ÓÏLME!í:îÙ43}øÝóÓÑA%<4Éd[,TÔØÒ¸PôÌôá{6E¤Û~ðDg Xqnþð¥ÿë÷ÿeM
è,|èóïþÁý«3ç£ð¡±!ïá~hföíÙºÀæÈÑã7òa'N½¹¨³×¼Gg ïÚýäsÙBKóûÝÕ¾*Ïe2J
+
+
+-«[Û¢S°@ÓûæèUg×Îè
+
+w^¹û.ó|Kktx(sß
+-«ÛºîNÁ˳·ïoNQ±&vEG
+ö÷®N
+4±c{t
+ÍMÑ)
+X½mmW>:EÙÙ
+
+
+º1J¬{íHmÍuéÒóñ¹\öèaî_7Øß»&:
+¸»p©°":E-7¢S
+¨«Éôµß¢Ä&v
+øT×÷W,NQ2c#C]í«¢S
+X½m}kt[²kçDt
+
+XÙtû`ïÇ£S\ÃèðP>ç:
+
+
+Ü5 µ¥ybÜMc
+
+
+
+~ðò9Ã
+-«[Û¢S°@Ó[ßßzÝÛµs"0
+w^¹û®«çùFò9÷Ã
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/lite.gif
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/lite.gif (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/lite.gif 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,71 @@
+GIF89aÆ'Õ$
+¨/Á*\(m~#JH¡Ã&+jÜȱ£¸L2zI²¤Éb <ɲ¥K)¬|I³¦Í1̼ɳ§Oÿu9ìüI´¨Ñ*]ÊYÐ#CJºô©¨T³j½iµÖ`ÃìJä«Ø³h'b6Û·×
+i·®ÝzrIн˷oº¼{ý
+¼
+0áÃÏ&`ãÇ;%Ülñ°ÀY1SÞlYæ©7'î,tÓ*hÍZi`¦2 `BëÛ¾^ÿ½tvmÜÀuéöÅ[©oÛÁïUüèñäÊü:îå¼n½5ö]Úrï.ú»®ðDǧl>úê×:mäòÙÓßmÿ·u$ÐLÜ 2à
+ðrÀ
+ ª#:
+§l(
+í'Á¼®q7BÙm¯Ebik
+
+¥9×ô»ã'üÙçÔ6Ö¸§·)¦L'ª«z]N1§æ&ëÂÿ¦"4
+ÏnE"ÛÓÖ´
+`p¬ÃøÖ®ù wO,ã<q¥
+KÓ*Ç (¹)s*Ñårñ±ÎÿQ^7r9:á°8¡xì×¾
+o%XJT 5BºH
+U M*oâtÈ®Y à
+¯t¯Û[¿þ»ÙÿævÅËÞöº÷½Ê%ï Þàj·³QÐJ
+»U¦ÓªÀ8
+aã8I N]Ûõqæ_#Í(5y
+ºL¶VdJÉ"£pX:Þmlcý°S'L`x^ºÙ(eòßBÖ§A×3ÓñwÀæ%
+¼gÙ°Ôûþ÷À¾ðO|Ôs È?Qì]ÐE+-_ÁB á$ÿûàÿ+9ö.rÅfx¥z&`ý¸ î Ö.'ZO
+BvIà`9Bx;8
+§r88h[¹ÕNø µ`Ð
+F&Z´áªG`OØ pSØ
F
+§h»ø
+½HÏßáØã8Rox^Å°ë°íï8ÓhóHTæfÁê ÞxÂøñÈ)bõHÀ`éx¨Ò¨|ñÊ@è`àøuÁÈ
+ê)ìYùIiBSÑ@ !NVÇÐ8öuÞÐSÿ
+Z'ý
+ÿù
+ÎÃñÒUX<ÅàiÁ dØ
+"Ú
+ZâÉ¡9b5
+:E7/c²®¾R"\â¡X7-mòò922¢x·@
+ÄSN"{lÄ¥®I2óa66FËäFËx¬½0gç|?B¤!Gò*jC¶fC¯ó¢:
+hB«b+#®»(ÍT7jq ½rO>b ì4" }B5KÒ27¶':)¢²
+oÒ,s"eò´ }7\òK.»8ÿYrV° ×7Á.ûÓ°÷úT*ºÚ¶WbutÂ$q+;ª< À°LM29¸Ð3ÖâÏZýF+L!ämU+?æ&L3'/% ¢DûIfÃ%$-ER)ë0 tVICï# òÓ3s²EhGÛ°!ëÒ1P»&T7bg(æà#ò§\²FM».RBtª Û$,²bt¤®KCHi×
+ºª+$Ó¶;h- ª¦¼À°Ë7ÃË$"+uAYª6Σ9¹nÞ¢/`pS<¹U~tB¾
+¬é"9f{³¼Ô§>myÁÐ¥<xë7«Ú3ÇÓEob²Þ»íW9#:lûdâkC&:&R,}'p.#Â(ICGZv' H*æBüË¿"á¿ÀåÒ#³¸¬
+·C'&!ÖTlYR"
+0ÄÛ$ìDÆrÄîÉÛxtRB}3e¶Ç9"ü Î:]
+ÇtC=$*¶'ÀjǸðºðÇHdÆ`Cº18åÍÒM¹Ûd°µ t1ʱü)kº^%ÁøË»ã-æ»O2©ÛÈy<w%ÍR
ó*%w£:TÄ ÿ°æ«{V]{C3¼ÄÆ,
+ )¬È##%ì9}D¸Ì$#,«êÌ4>Tnjd¸4\7¨:/ünÇB¶·'³7½X¬»Ð3
+Ð2Ì61b+>÷4±,-F â"ÃÌ%#d(«-JüI¾PÊ¿<
+Pò+
+
+O»ÐS ¢N+Û)¢{&U"ê´§"9º¤m&n)ö$24)¶m ;ÕÄC1ËÆA}:ÚÃí9ú*¶Úm¨{¹î!§ÐÀi¯ Ƚ ³¤¨öÓMÆ× 0 àñÍà|ÔªÜ&
:
+©= Káa¸,Ñní1z
+ºº
+Ì
+
¹¹BÈOÅ|QßÓpßn,¸6êFñ?þýßMßÿÉ{²{öêü~.
+
+ù]ÐiÀÝ
+Þæß^!Î#
+%¼û]+¾-þ/Á'îá.5®7î9nÌ;X)N?~AÞCÒE
+3NInKÎMÝO¢GþS^U¾Wþnä=]N_®aîcå[ÞSËâqÞm®åegþiknçY~
+Qþ{î}Îw.èo.uäs^¾y¾
Þ~NénéîýNåþ£~Þ¾nn~1þ
+îÎÿ¯^±êHá!·~¹N»¾®ÁnÃ>Å~ì¡~Ë^Í.ÏnÑ
+µÞÕN×>§nì³î
+ÝÎßþáN½ãíÇÎí>ínè¥ó~ïþ «n^ëþÙïåÞ
+çV÷ëõî?Û®ï¿þÏì ¡_ù^¤PÀg¸ñ·DòAEÀ
!¿ $¿"ïñJøò0ó2?ó4_ó6ó8ó:¿ó<ßó>ÿó@ôB?ôD_ôFôP|J¿ôLßôNÿôPõR?õT_õ¿w|É~vZ¿¿õ^?Óþõÿboñ>öf/ û~öj/T¿ön]ÿöroY?÷vöi÷zïë!±÷~?qÿ÷`e?øßÖ}ø/ã
¿øø÷ùs?ùÿöùkùößùcÿù ÿõ¢?ú[_ú¦v¨úö¶ú¬oj®ÿúû²d_ûû¸¿ùº¿ûßû¾úÀü¤?üÄúÆüªüÊßúÌßü°ÿüÐ?ûÒ?ý¶_÷Ø¥ î$¤Î¼û´¡»ØÂ0kÄáÔ£þvq0à
+Àjà
+Á 2
+E""(
+F (CùLOQSU¿Üæ\á
+8G ,±ê6/w/=!¨.mÁÃÅõZ_]sÇÓÕ×»pÛyEJGþ(|às²OÄ®XI
+@Á
+M
+ø±°X' ÝFÖ¨v-dÉ×ùqð÷0
+ÓZë"AQD +üiÄQL1²ç¸PÅÿa±?ÑÆqT
Æ8\ÌÑÇìÐCX,ÒÈ#ÛH$l2ÆtRÊ)A-*±Ì2B+IèQË/ÁK/Ã,ÓLÆ<SÍ5wJÍ7áTÇÍ8é¬S9íÌSÏ<ðÜÓÏ?ÍèÐA RI2MôMAm4OFNH%ôLJ-ÍôKL5ítJN=
+IPE-HRMMõFTUmõEV]uDXeuCZmÍD%¯ÔÕ×qýUØðÖXÌ=VÙ¶]ÖÙ ¸Ül½i©ÖÚk±ÍVÛm¹íÖÛoÁ
+WÜqÉ-×ÜsÑMWÝuÙýË^áWÞyé×Þ{ñÍWß}ùí×ßXà .ØàNXá
nØá!Xâ)®Øâ1ÎXã9îØãAYäI.ÙäQNYåYnÙåaYæi®ÙæqÎYçyîÙçZè¡.Úè£NZé¥nÚ駡Zê©©®Ú꫱ÎZë¹îÚë¯Á[ì±É.Ûl~
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/lite.svg
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/lite.svg (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/lite.svg 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,334 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+ xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="318.898"
+ height="248.031"
+ id="svg1">
+ <defs
+ id="defs3">
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop128" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop129" />
+ </linearGradient>
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient130"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ <radialGradient
+ cx="0.5"
+ cy="0.5"
+ fx="0.5"
+ fy="0.5"
+ r="0.5"
+ id="radialGradient131"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ </defs>
+ <rect
+ width="291.837"
+ height="57.0074"
+ x="17.3169"
+ y="18.646"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect136" />
+ <rect
+ width="291.837"
+ height="57.0074"
+ x="13.9703"
+ y="16.2302"
+ style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect126" />
+ <g
+ transform="matrix(0.326107,0,0,0.765831,9.59261,8.98517)"
+ style="font-size:12;"
+ id="g161">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect137" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect132" />
+ </g>
+ <g
+ transform="matrix(1.02406,0,0,0.652953,0.223384,39.9254)"
+ style="font-size:12;"
+ id="g164">
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="16.6979"
+ y="222.966"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect138" />
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="14.7335"
+ y="221.002"
+ transform="translate(-1.30962,-1.30992)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect133" />
+ </g>
+ <g
+ transform="matrix(0.449834,0,0,0.338463,-3.15909,9.73319)"
+ style="font-size:12;"
+ id="g167">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect134" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect135" />
+ </g>
+ <text
+ x="302.277679"
+ y="65.943230"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text183">
+ <tspan
+ x="302.277954"
+ y="65.943184"
+ id="tspan360">
+Application</tspan>
+ </text>
+ <text
+ x="36.235924"
+ y="63.796055"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text188">
+ <tspan
+ x="36.235950"
+ y="63.796051"
+ id="tspan427">
+Transient Objects</tspan>
+ </text>
+ <text
+ x="180.416245"
+ y="290.543701"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text197">
+ <tspan
+ x="180.415939"
+ y="290.543549"
+ id="tspan421">
+Database</tspan>
+ </text>
+ <text
+ x="25.037701"
+ y="179.154755"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text216">
+ <tspan
+ x="25.037655"
+ y="179.154648"
+ id="tspan384">
+SessionFactory</tspan>
+ </text>
+ <g
+ transform="matrix(0.252763,0,0,0.765831,109.104,8.98517)"
+ style="font-size:12;"
+ id="g386">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect387" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect388" />
+ </g>
+ <g
+ transform="matrix(0.297394,0,0,0.572692,101.502,21.6359)"
+ style="font-size:12;"
+ id="g364">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect365" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect366" />
+ </g>
+ <text
+ x="202.746506"
+ y="102.992203"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+ id="text367">
+ <tspan
+ x="202.746948"
+ y="102.992249"
+ id="tspan423">
+Persistent</tspan>
+ <tspan
+ x="202.746948"
+ y="116.992355"
+ id="tspan425">
+Objects</tspan>
+ </text>
+ <text
+ x="174.458496"
+ y="180.080795"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text389">
+ <tspan
+ x="174.458618"
+ y="180.080338"
+ id="tspan392">
+Session</tspan>
+ </text>
+ <g
+ transform="matrix(0.127369,0,0,0.765831,188.675,8.98517)"
+ style="font-size:12;"
+ id="g394">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect395" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect396" />
+ </g>
+ <text
+ x="260.413269"
+ y="179.154739"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text397">
+ <tspan
+ x="260.412964"
+ y="179.154343"
+ id="tspan400">
+JDBC</tspan>
+ </text>
+ <g
+ transform="matrix(0.127369,0,0,0.765831,229.156,8.98517)"
+ style="font-size:12;"
+ id="g405">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect406" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect407" />
+ </g>
+ <text
+ x="320.606903"
+ y="179.154739"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text408">
+ <tspan
+ x="320.606964"
+ y="179.154343"
+ id="tspan417">
+JNDI</tspan>
+ </text>
+ <g
+ transform="matrix(0.127369,0,0,0.765831,269.281,8.98517)"
+ style="font-size:12;"
+ id="g411">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect412" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect413" />
+ </g>
+ <text
+ x="377.096313"
+ y="179.154739"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text414">
+ <tspan
+ x="377.096008"
+ y="179.154999"
+ id="tspan145">
+JTA</tspan>
+ </text>
+</svg>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/overview.gif
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/overview.gif (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/overview.gif 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,81 @@
+GIF89aT|æR
+H° Á ¥¡Ã#JH±¢Å3jÜȱ£Ç C `áÈ(Sª\ɲ¥ËKb³¦Í8sêÔ)Í@
+JôfÏQ?*]Ê´©Ó£¢:JµªUPCI½Êµ«×¯YAmýJ¶¬Y¡a?=˶Ûiÿ=}K·®Ýq;ͽ˷ïÛ¼öúL¸+àM+^¼ô°¦Ä#KÎé8äÉ3¯¬é²æÏ =r¾ä9´éÓG[*ºukÕX»
+6%Ù´sO¶= ·îßyKò
+¼x_á_N9$åÌ£uþºôë^©;²½{Uí¸{Ï<#ñäÓ5¿½ú÷<MÂO½"÷ôó·´¿þÿXÉà Hàhà)Èà0ñVPhá¢ávXÈ >("!$¸à¤¨â,
+ââÆ(Å4þg#9æ·£t¼P
+0
+5Úu6ä¨
+à28Ä%AçK6BÉ:
+P
+ØÊyÀ
+wFA½Wkq@A¯1 ¯Hé
+æBÀ
+`îÆD@Å» ¥É¸@
+¥Oã
+/4pA(
+ìCÑ
7ÛÐØÄ{ô"þm¯p\ç¢
+Áßæ`¼¶ÕïmÀ¹
+-*àÂÂ._(Vdp0 _#Ðhà is:
+Ö¾L~ªÓWð!ºÚ$ L Z½x
+l¹¶Ø¬H !(ÂÕ¾«\qÀ~ÆFÕuP¿]nh à=
+ Ò>à¬
+ ÿxÃR. ¼©1PÀ°Kf«¢T6ŵòsö»Ø$²Ë$Òé%DéKÒ;Ä4VÄ)cvG¦4IÈLÑ
+©HGJÒô¤(5©fÕÂsÕȨâÒÀ4¦éTjêâÔ"púâħ?¥H
+®pgÛÒu¸ÈM®rgfoסt}G)
+;²%æE¨étJ"øóà?Wo"¯ÉâD]颰²C|å
+´à»'ùÝu¹çêûB@P@AÞLF;®r0$ÀÿRÒ^÷¾pF!W¦´È.'ýJ+ÈÀÞd íbðDfYKL
+ìm«
EáGAðP,ç_GäV0þÞ
+¼ÅÐo$Þ±'z .³ÄR®âT
+¾¥ÑøRÐs
+)fI+ Í-ÀЬ<s)²9AåoÜÀj¿ó"R°¾æ ÈaÒ/PÐC¤«AÁP
+(Á¿-SzÊ] PKdøH×ç´õ qKì@@¦CýNmu"0ª
|Q
+h¡ÿ
+à
+héØK22£ ½ôx& ð³>Xïj×z¨%×
+@2°ÉÖÈ¥;ÅI(ï"à@R&XëaðzP\v/=ÇÇ¥NMäx'ùDF|4Ä2®Àt?¼ÉçTmÁê[:#¥]æ{ªù»Ï¯ÜÏ{+E¨¼ø¶d~y1«!·GÀ
+Âï¼³î÷uwÛ
+ß:¿ÉQ ;48Ûòyô×,Éä9¯DCp
+¸'p=6Ù µ¥6ª¦4@'%Fte#'?£±CÆ6 8bo"B74p
+&÷1:·æà0
+2#À. at 6_2÷@Í":P°>( È&ÜEZèX}Uÿðå!
+±-)Ãz Ö.î¸$Úâ
+
+âCü$8a(aùF±}q5ZJõEBÁöä6¡'ó¤5Á#áðx%LH¦
r©x8Ya/!"Aí.¡!Áêäûá}i\ÅÚgA!çD, áäaa*!Q*p0ôYöyøú¹üÙþù
+;7 @ØjH¶*d(TwÐ
+)c³äy§ ªÒÚu/»©Rd2_¥#,ÂW·ßåÿ´ÆB·àjd`t˸QÀª¤,Ôjµ*ëkª]k«UK¸®_~®D¹+EØjÃ6% .0¹Z¹fÏÓºqµWѹ\³*@&|Ó4_W>íº/¤ºª:bÐDK¶L˼þ]𹡻VÁ»ª*¦K;4ç³y>Y³9¼Ã4»m»$#+P[`лy Á3êôÂØ[Ú©¾ëEà
+»òÅc`«2)§¡¨z¨§ZlK//g?3$g@5|æBBmHR
+Ó3Þº+[ggÜ·úÑ!2*±TEMË*ù+¨½ÉÁP¼O<Åp¹¹V¨XÅ*Å\ìUüŹÅb<ÐZÆÆh|^¼Æ|{ÆnÌ¥dÇNHÄt¦m|ÇÓ1ÇzÜvÜÇw¡Æ|ÚR|ÈÈQÑüÈÉl½Ú
+!ÐMÐÝÐþ¬ÐQÀл,
+
+
+ÝPÐ }ÞÉÊmÜ/ ÞHÝ`;PÓ ×`Þç;íË×Ý߬Ý
+ÚÌÝÉßÉáÐIPÜ$0Ù½ÝÉëÐí-Ü<$pÉ$Ú:ÉÐ}Ô×ü
+50û-ã«ÝÊBp
+2¹ïañH!ª,WC´øu¡Ü_,pº TXPÑJÿ×èB!a64( Þ`ñrê·bE gôึ©YåZÖ¬$´c³¿JÊ»*\Cd«Ð³(Ñè5U¯´Õ
+<Ár3l
+,p@lð69$Ìà3@3XÀPxp\eÊɶ6¶ÁÝHÂFµYØi§â)Þ)Òb*%HPÀS%<7U$U¥§ã¥¥Ão p Èl6B¡
+
+byÀ_¡ä=4¦áäi=³e!]j£_
,Ú
+ùÜ_wùâO®Ôÿynvçc¢¸éj^:ë]£º«Ãîµë¶GÞ6´³$/üðÄoüñÈ'¯üòÌ[ö$L0/ýôÔWo=õ*ìÎpïª?ïý÷à/þøäoþùè§osØ©®þûðÇ/ÿüô×?>û»oÿþü÷ïÿÿ
+ÁWB±p
0¡·7@]ï8Ì¡wÈÃúð@$À
+Û¤'GIJõRZ¢,¥*WÉBF²ò°ü¤+cIËZr¶Ì¥.[9ÄTîò<%ª| ÌbBR{"¦1CdòÐü¥3Ó£ÌhZÿÓDO5¯ÉÍ fÓaÝç*¿*qsä|Ú9×iÉtNðt¤;áÏz6ö̧çÙ7}ú3üÈ6ÿIÐûá³ ÅäAÊÐ
+h:6ZÔ¥ÜE7J¿nb ½¨G}ÒÞ²&M)úF ª4¡,íÞKgJÁ
Òô¦Ö)qÊÓOév=
+*iljM(à¨H|j#ª
+
+@ka«Ú(ÌÈ
+0
+
+È7³
+Gq·KÔhjxÞ
@$ÿ`YÔ¸®«]rSìÛx¼1Xh¬[ÖL
+d±l
+@2`W"£´´áxÅÀÆY
²Wb¤TÆ«$¼T@)Éjg[@¹NP¢Õ¶¹îæ%ZD+p@Jð^KÊ
+ ÐØpгºËT±
+8
+ÎKlÊ3ÓÜÜ´(Ø; &6õx6ÔKg
+)èv\nüNÓEæU'0#q8 -Èl
+l@Ú%@&ôýV ¸EQàÝ
+t}êQ}Á
+hè
+À³8 øBð Ǹ¢%àHZ
+¸ØøiöS&àXx¸Øø "8$X&x(è&
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/overview.svg
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/overview.svg (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/en-US/src/main/resources/shared/images/overview.svg 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,250 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+ xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="248.031"
+ height="248.031"
+ id="svg1">
+ <defs
+ id="defs3">
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop128" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop129" />
+ </linearGradient>
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient130"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ <radialGradient
+ cx="0.5"
+ cy="0.5"
+ fx="0.5"
+ fy="0.5"
+ r="0.5"
+ id="radialGradient131"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ </defs>
+ <g
+ transform="matrix(0.771934,0,0,0.771934,4.36019,-3.02123)"
+ style="font-size:12;"
+ id="g158">
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="16.6979"
+ y="17.3527"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect136" />
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="14.7335"
+ y="15.3883"
+ transform="translate(-1.30962,-1.30992)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect126" />
+ </g>
+ <g
+ transform="matrix(0.771934,0,0,0.771934,4.36019,3.04452)"
+ style="font-size:12;"
+ id="g161">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect137" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect132" />
+ </g>
+ <g
+ transform="matrix(0.771934,0,0,0.771934,4.36019,8.0993)"
+ style="font-size:12;"
+ id="g164">
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="16.6979"
+ y="222.966"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect138" />
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="14.7335"
+ y="221.002"
+ transform="translate(-1.30962,-1.30992)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect133" />
+ </g>
+ <g
+ transform="matrix(0.771934,0,0,0.543505,2.59104,21.1103)"
+ style="font-size:12;"
+ id="g167">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect134" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect135" />
+ </g>
+ <text
+ x="105.392174"
+ y="56.568123"
+ transform="scale(0.771934,0.771934)"
+ style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text183">
+ <tspan
+ x="105.392273"
+ y="56.568146"
+ id="tspan186">
+Application</tspan>
+ </text>
+ <text
+ x="81.820183"
+ y="103.149330"
+ transform="scale(0.771934,0.771934)"
+ style="font-size:20;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text188">
+ <tspan
+ x="81.820213"
+ y="103.149727"
+ id="tspan206">
+Persistent Objects</tspan>
+ </text>
+ <text
+ x="111.548180"
+ y="278.927887"
+ transform="scale(0.771934,0.771934)"
+ style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text197">
+ <tspan
+ x="111.547874"
+ y="278.927551"
+ id="tspan200">
+Database</tspan>
+ </text>
+ <text
+ x="94.436180"
+ y="153.805740"
+ transform="scale(0.771934,0.771934)"
+ style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text216">
+ <tspan
+ x="94.436180"
+ y="153.805740"
+ id="tspan221">
+HIBERNATE</tspan>
+ </text>
+ <g
+ transform="matrix(0.771934,0,0,0.771934,2.59083,1.02261)"
+ style="font-size:12;"
+ id="g254">
+ <g
+ transform="translate(4.58374,2.61928)"
+ id="g176">
+ <g
+ transform="matrix(0.571429,0,0,0.67347,-10.6174,117.093)"
+ id="g170">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect171" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect172" />
+ </g>
+ <g
+ transform="matrix(0.571429,0,0,0.67347,138.682,117.093)"
+ id="g173">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect174" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect175" />
+ </g>
+ </g>
+ <text
+ x="47.259438"
+ y="182.367538"
+ style="font-weight:bold;stroke-width:1pt;font-family:Courier;"
+ id="text191">
+ <tspan
+ x="47.259399"
+ y="182.367996"
+ id="tspan212">
+hibernate.</tspan>
+ <tspan
+ x="47.259399"
+ y="194.367996"
+ id="tspan214">
+properties</tspan>
+ </text>
+ <text
+ x="198.523010"
+ y="188.260941"
+ style="font-weight:normal;stroke-width:1pt;font-family:helvetica;"
+ id="text194">
+ <tspan
+ id="tspan195">
+XML Mapping</tspan>
+ </text>
+ </g>
+</svg>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/pom.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/pom.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/pom.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,21 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-manual</artifactId>
+ <version>3.3.0.beta1</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>hibernate-manual-${translation}</artifactId>
+ <packaging>pom</packaging>
+ <name>Hibernate Manual (${translation})</name>
+
+ <properties>
+ <translation>fr-FR</translation>
+ </properties>
+</project>
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/master.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/master.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/master.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,188 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
+ "../support/docbook-dtd/docbookx.dtd"
+[
+<!ENTITY tutorial SYSTEM "modules/tutorial.xml">
+<!ENTITY architecture SYSTEM "modules/architecture.xml">
+<!ENTITY configuration SYSTEM "modules/configuration.xml">
+<!ENTITY persistent-classes SYSTEM "modules/persistent_classes.xml">
+<!ENTITY basic-mapping SYSTEM "modules/basic_mapping.xml">
+<!ENTITY collection-mapping SYSTEM "modules/collection_mapping.xml">
+<!ENTITY association-mapping SYSTEM "modules/association_mapping.xml">
+<!ENTITY component-mapping SYSTEM "modules/component_mapping.xml">
+<!ENTITY inheritance-mapping SYSTEM "modules/inheritance_mapping.xml">
+<!ENTITY session-api SYSTEM "modules/session_api.xml">
+<!ENTITY transactions SYSTEM "modules/transactions.xml">
+<!ENTITY events SYSTEM "modules/events.xml">
+<!ENTITY batch SYSTEM "modules/batch.xml">
+<!ENTITY query-hql SYSTEM "modules/query_hql.xml">
+<!ENTITY query-criteria SYSTEM "modules/query_criteria.xml">
+<!ENTITY query-sql SYSTEM "modules/query_sql.xml">
+<!ENTITY filters SYSTEM "modules/filters.xml">
+<!ENTITY xml SYSTEM "modules/xml.xml">
+<!ENTITY performance SYSTEM "modules/performance.xml">
+<!ENTITY toolset-guide SYSTEM "modules/toolset_guide.xml">
+<!ENTITY example-parentchild SYSTEM "modules/example_parentchild.xml">
+<!ENTITY example-weblog SYSTEM "modules/example_weblog.xml">
+<!ENTITY example-mappings SYSTEM "modules/example_mappings.xml">
+<!ENTITY best-practices SYSTEM "modules/best_practices.xml">
+]>
+
+<book lang="fr">
+
+ <bookinfo>
+ <title>HIBERNATE - Persistance relationnelle en Java standard</title>
+ <subtitle>Documentation de référence d'Hibernate</subtitle>
+ <releaseinfo>3.3.0.beta1</releaseinfo>
+ </bookinfo>
+
+ <toc/>
+
+ <preface id="preface" revision="2">
+ <title>Préface</title>
+ <para>
+ Traducteur(s): Vincent Ricard, Sebastien Cesbron, Michael Courcy, Vincent Giguère, Baptiste Mathus, Emmanuel Bernard, Anthony Patricio
+ </para>
+ <para>
+ Travailler dans les deux univers que sont l'orienté objet et la base de données
+ relationnelle peut être lourd et consommateur en temps dans le monde de
+ l'entreprise d'aujourd'hui. Hibernate est un outil de mapping objet/relationnel
+ pour le monde Java. Le terme mapping objet/relationnel (ORM) décrit la technique
+ consistant à faire le lien entre la représentation objet des données
+ et sa représentation relationnelle basée sur un schéma SQL.
+ </para>
+
+ <para>
+ Non seulement, Hibernate s'occupe du transfert des classes Java dans les tables
+ de la base de données (et des types de données Java dans les types de données SQL),
+ mais il permet de requêter les données et propose des moyens de les récupérer.
+ Il peut donc réduire de manière significative le temps de développement qui
+ aurait été autrement perdu dans une manipulation manuelle des données via SQL
+ et JDBC.
+ </para>
+
+ <para>
+ Le but d'Hibernate est de libérer le développeur de 95 pourcent des tâches de
+ programmation liées à la persistance des données communes. Hibernate n'est
+ probablement pas la meilleure solution pour les applications centrées sur les
+ données qui n'utilisent que les procédures stockées pour implémenter la logique
+ métier dans la base de données, il est le plus utile dans les modèles métier orientés
+ objets dont la logique métier est implémentée dans la couche Java dite intermédiaire.
+ Cependant, Hibernate vous aidera à supprimer ou à encapsuler le code SQL
+ spécifique à votre base de données et vous aidera sur la tâche commune qu'est
+ la transformation des données d'une représentation tabulaire à une
+ représentation sous forme de graphe d'objets.
+ </para>
+
+ <para>
+ Si vous êtes nouveau dans Hibernate et le mapping Objet/Relationnel voire même en Java,
+ suivez ces quelques étapes :
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>
+ Lisez <xref linkend="tutorial"/> pour un didacticiel plus long avec plus d'instructions étape par étape.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Lisez <xref linkend="architecture"/> pour comprendre les environnements dans lesquels
+ Hibernate peut être utilisé.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Regardez le répertoire <literal>eg</literal> de la distribution Hibernate, il contient
+ une application simple et autonome. Copiez votre pilote JDBC dans le répertoire
+ <literal>lib/</literal> et éditez <literal>src/hibernate.properties</literal>, en
+ positionnant correctement les valeurs pour votre base de données. A partir d'une
+ invite de commande dans le répertoire de la distribution, tapez <literal>ant eg</literal>
+ (cela utilise Ant), ou sous Windows tapez <literal>build eg</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Faîtes de cette documentation de référence votre principale source d'information.
+ Pensez à lire <emphasis>Hibernate in Action</emphasis>
+ (http://www.manning.com/bauer) si vous avez besoin de plus d'aide avec le design
+ d'applications ou si vous préférez un tutoriel pas à pas. Visitez aussi
+ http://caveatemptor.hibernate.org et téléchargez l'application exemple
+ pour Hibernate in Action.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Les questions les plus fréquemment posées (FAQs) trouvent leur réponse sur le
+ site web Hibernate.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Des démos, exemples et tutoriaux de tierces personnes sont référencés sur
+ le site web Hibernate.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ La zone communautaire (Community Area) du site web Hibernate est une
+ bonne source d'information sur les design patterns et sur différentes
+ solutions d'intégration d'Hibernate (Tomcat, JBoss, Spring Framework, Struts,
+ EJB, etc).
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ Si vous avez des questions, utilisez le forum utilisateurs du site web Hibernate.
+ Nous utilisons également l'outil de gestion des incidents JIRA pour tout ce qui
+ est rapports de bogue et demandes d'évolution. Si vous êtes intéressé par le
+ développement d'Hibernate, joignez-vous à la liste de diffusion de développement.
+ </para>
+
+ <para>
+ Le développement commercial, le support de production et les formations à Hibernate
+ sont proposés par JBoss Inc (voir http://www.hibernate.org/SupportTraining/). Hibernate
+ est un projet Open Source professionnel et un composant critique de la suite de produits
+ JBoss Enterprise Middleware System (JEMS).
+ </para>
+
+ </preface>
+
+ &tutorial;
+
+ &architecture;
+
+ &configuration;
+
+ &persistent-classes;
+
+ &basic-mapping;
+ &collection-mapping;
+ &association-mapping;
+ &component-mapping;
+ &inheritance-mapping;
+
+ &session-api;
+ &transactions;
+ &events;
+ &batch;
+
+ &query-hql;
+ &query-criteria;
+ &query-sql;
+ &filters;
+ &xml;
+
+ &performance;
+
+ &toolset-guide;
+
+ &example-parentchild;
+ &example-weblog;
+ &example-mappings;
+
+ &best-practices;
+
+</book>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/architecture.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/architecture.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/architecture.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,351 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="architecture">
+
+ <title>Architecture</title>
+
+ <sect1 id="architecture-overview" revision="1">
+ <title>Généralités</title>
+
+ <para>
+ Voici une vue (très) haut niveau de l'architecture d'Hibernate :
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="images/overview.svg" format="SVG" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../shared/images/overview.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ Ce diagramme montre Hibernate utilisant une base de données et des données
+ de configuration pour fournir un service de persistance (et des objets
+ persistants) à l'application.
+ </para>
+
+ <para>
+ Nous aimerions décrire une vue plus détaillée de l'architecture. Malheureusement,
+ Hibernate est flexible et supporte différentes approches. Nous allons en
+ montrer les deux extrêmes. L'architecture légère laisse l'application fournir
+ ses propres connexions JDBC et gérer ses propres transactions. Cette approche
+ utilise le minimum des APIs Hibernate :
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="images/lite.svg" format="SVG" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../shared/images/lite.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ L'architecture la plus complète abstrait l'application des APIs JDBC/JTA
+ sous-jacentes et laisse Hibernate s'occuper des détails.
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="images/full_cream.svg" format="SVG" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../shared/images/full_cream.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ Voici quelques définitions des objets des diagrammes :
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term>
+ <listitem>
+ <para>
+ Un cache threadsafe (immuable) des mappings vers une (et une seule) base
+ de données. Une factory (fabrique) de <literal>Session</literal> et un client
+ de <literal>ConnectionProvider</literal>. Peut contenir un cache optionnel de
+ données (de second niveau) qui est réutilisable entre les différentes transactions
+ que cela soit au sein du même processus (JVLM) ou par plusieurs n½uds d'un cluster.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Session (<literal>org.hibernate.Session</literal>)</term>
+ <listitem>
+ <para>
+ Un objet mono-threadé, à durée de vie courte, qui représente une conversation
+ entre l'application et l'entrepôt de persistance. Encapsule une connexion JDBC.
+ Factory (fabrique) des objets <literal>Transaction</literal>. Contient un cache
+ (de premier niveau) des objets persistants, ce cache est obligatoire. Il est
+ utilisé lors de la navigation dans le graphe d'objets ou lors de la récupération
+ d'objets par leur identifiant.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Objets et Collections persistants</term>
+ <listitem>
+ <para>
+ Objets mono-threadés à vie courte contenant l'état de persistance
+ et la fonction métier. Ceux-ci sont en général les objets de type JavaBean
+ (ou POJOs) ; la seule particularité est qu'ils sont associés avec une (et
+ une seule) <literal>Session</literal>. Dès que la <literal>Session</literal>
+ est fermée, ils seront détachés et libres d'être utilisés par n'importe laquelle
+ des couches de l'application (ie. de et vers la présentation en tant que Data
+ Transfer Objects - DTO : objet de transfert de données).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Objets et collections transients</term>
+ <listitem>
+ <para>
+ Instances de classes persistantes qui ne sont actuellement pas associées à
+ une <literal>Session</literal>. Elles ont pu être instanciées par l'application
+ et ne pas avoir (encore) été persistées ou elle ont pu être instanciées par
+ une <literal>Session</literal> fermée.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Transaction (<literal>org.hibernate.Transaction</literal>)</term>
+ <listitem>
+ <para>
+ (Optionnel) Un objet mono-threadé à vie courte utilisé par l'application
+ pour définir une unité de travail atomique. Abstrait l'application des
+ transactions sous-jacentes qu'elles soient JDBC, JTA ou CORBA. Une
+ <literal>Session</literal> peut fournir plusieurs <literal>Transaction</literal>s
+ dans certains cas. Toutefois, la délimitation des transactions, via l'API d'Hibernate
+ ou par la <literal>Transaction</literal> sous-jacente, n'est jamais optionnelle!
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term>
+ <listitem>
+ <para>
+ (Optionnel) Une fabrique de (pool de) connexions JDBC. Abstrait l'application
+ de la <literal>Datasource</literal> ou du <literal>DriverManager</literal> sous-jacent.
+ Non exposé à l'application, mais peut être étendu/implémenté par le développeur.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term>
+ <listitem>
+ <para>
+ (Optionnel) Une fabrique d'instances de <literal>Transaction</literal>. Non
+ exposé à l'application, mais peut être étendu/implémenté par le développeur.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><emphasis>Interfaces d'extension</emphasis></term>
+ <listitem>
+ <para>
+ Hibernate fournit de nombreuses interfaces d'extensions optionnelles que
+ vous pouvez implémenter pour personnaliser le comportement de votre couche de persistance.
+ Reportez vous à la documentation de l'API pour plus de détails.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
+ <para>
+ Dans une architecture légère, l'application n'aura pas à utiliser les APIs
+ <literal>Transaction</literal>/<literal>TransactionFactory</literal>
+ et/ou n'utilisera pas les APIs <literal>ConnectionProvider</literal>
+ pour utiliser JTA ou JDBC.
+ </para>
+ </sect1>
+
+ <sect1 id="architecture-states" revision="1">
+ <title>Etats des instances</title>
+ <para>
+ Une instance d'une classe persistante peut être dans l'un des trois états suivants,
+ définis par rapport à un <emphasis>contexte de persistance</emphasis>.
+ L'objet <literal>Session</literal> d'hibernate correspond à ce concept de
+ contexte de persistance :
+ </para>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>passager (transient)</term>
+ <listitem>
+ <para>
+ L'instance n'est pas et n'a jamais été associée à un contexte
+ de persistance. Elle ne possède pas d'identité persistante (valeur de clé primaire)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>persistant</term>
+ <listitem>
+ <para>
+ L'instance est associée au contexte de persistance.
+ Elle possède une identité persistante (valeur de clé primaire)
+ et, peut-être, un enregistrement correspondant dans la base.
+ Pour un contexte de persistance particulier, Hibernate
+ <emphasis>garantit</emphasis> que l'identité persistante
+ est équivalente à l'identité Java (emplacement mémoire de l'objet)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>détaché</term>
+ <listitem>
+ <para>
+ L'instance a été associée au contexte de persistance mais ce
+ contexte a été fermé, ou l'instance a été sérialisée vers un
+ autre processus. Elle possède une identité persistante et
+ peut-être un enregistrement correspondant dans la base.
+ Pour des instances détachées, Hibernate ne donne aucune
+ garantie sur la relation entre l'identité persistante et
+ l'identité Java.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="architecture-jmx" revision="1">
+ <title>Intégration JMX</title>
+ <para>
+ JMX est le standard J2EE de gestion des composants Java.
+ Hibernate peut être géré via un service JMX standard. Nous fournissons une implémentation
+ d'un MBean dans la distribution : <literal>org.hibernate.jmx.HibernateService</literal>.
+ </para>
+
+ <para>
+ Pour avoir un exemple sur la manière de déployer Hibernate en tant que service JMX dans le
+ serveur d'application JBoss Application Server, référez vous au guide utilisateur JBoss (JBoss User Guide).
+ Si vous déployez Hibernate via JMX sur JBoss AS, vous aurez également les bénéfices suivants :
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Gestion de la session :</emphasis> Le cycle de vie de la <literal>Session</literal>
+ Hibernate peut être automatiquement limitée à la portée d'une transaction JTA.
+ Cela signifie que vous n'avez plus besoin d'ouvrir et de fermer la <literal>Session</literal>
+ manuellement, cela devient le travail de l'intercepteur EJB de JBoss. Vous n'avez
+ pas non plus à vous occuper des démarcations des transactions dans votre code (sauf
+ si vous voulez écrire une couche de persistance qui soit portable, dans ce cas vous
+ pouvez utiliser l'API optionnelle <literal>Transaction</literal> d'Hibernate).
+ Vous appelez l'<literal>HibernateContext</literal> pour accéder à la <literal>Session</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Déploiement HAR :</emphasis> Habituellement vous déployez le service JMX
+ Hibernate en utilisant le descripteur de déploiement de JBoss (dans un fichier EAR et/ou un SAR),
+ il supporte toutes les options de configuration usuelles d'une <literal>SessionFactory</literal>
+ Hibernate. Cependant, vous devez toujours nommer tous vos fichiers de mapping dans le
+ descripteur de déploiement. Si vous décidez d'utiliser le déploiement optionnel sous forme
+ de HAR, JBoss détectera automatiquement tous vos fichiers de mapping dans votre fichier HAR.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Consultez le guide d'utilisation de JBoss AS pour plus d'informations sur ces options.
+ </para>
+
+ <para>
+ Les statistiques pendant l'exécution d'Hibernate (au runtime) sont une
+ autre fonctionnalité disponible en tant que service JMX. Voyez pour cela
+ <xref linkend="configuration-optional-statistics"/>.
+ </para>
+ </sect1>
+
+ <sect1 id="architecture-jca" revision="1">
+ <title>Support JCA</title>
+ <para>
+ Hibernate peut aussi être configuré en tant que connecteur JCA. Référez-vous au site
+ web pour de plus amples détails. Il est important de noter que le support JCA d'Hibernate
+ est encore considéré comme expérimental.
+ </para>
+ </sect1>
+
+ <sect1 id="architecture-current-session" revision="1">
+ <title>Sessions Contextuelles</title>
+ <para>
+ Certaines applications utilisant Hibernate ont besoin d'une sorte de session "contextuelle", où
+ une session est liée à la portée d'un contexte particulier. Cependant, les applications ne définissent
+ pas toutes la notion de contexte de la même manière, et différents contextes définissent différentes
+ portées à la notion de "courant". Les applications à base d'Hibernate, versions précédentes à la 3.0
+ utilisaient généralement un principe maison de sessions contextuelles basées sur le <literal>ThreadLocal</literal>,
+ ainsi que sur des classes utilitaires comme <literal>HibernateUtil</literal>, ou utilisaient des
+ framework tiers (comme Spring ou Pico) qui fournissaient des sessions contextuelles basées sur
+ l'utilisation de proxy/interception.
+ </para>
+ <para>
+ A partir de la version 3.0.1, Hibernate a ajouté la méthode <literal>SessionFactory.getCurrentSession()</literal>.
+ Initialement, cela demandait l'usage de transactions <literal>JTA</literal>, où la
+ transaction <literal>JTA</literal> définissait la portée et le contexte de la session courante.
+ L'équipe Hibernate pense que, étant donnée la maturité des implémentations de <literal>JTA TransactionManager</literal> ,
+ la plupart (sinon toutes) des applications devraient utiliser la gestion des transactions par <literal>JTA</literal>
+ qu'elles soient ou non déployées dans un conteneur <literal>J2EE</literal>. Par conséquent,
+ vous devriez toujours contextualiser vos sessions, si vous en avez besoin, via la méthode basée sur JTA.
+ </para>
+ <para>
+ Cependant, depuis la version 3.1, la logique derrière
+ <literal>SessionFactory.getCurrentSession()</literal> est désormais branchable.
+ A cette fin, une nouvelle interface d'extension (<literal>org.hibernate.context.CurrentSessionContext</literal>)
+ et un nouveau paramètre de configuration (<literal>hibernate.current_session_context_class</literal>)
+ ont été ajoutés pour permettre de configurer d'autres moyens de définir la portée et le contexte des
+ sessions courantes.
+ </para>
+ <para>
+ Allez voir les Javadocs de l'interface <literal>org.hibernate.context.CurrentSessionContext</literal>
+ pour une description détaillée de son contrat. Elle définit une seule méthode,
+ <literal>currentSession()</literal>, depuis laquelle l'implémentation est responsable
+ de traquer la session courante du contexte. Hibernate fournit deux implémentation
+ de cette interface.
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>org.hibernate.context.JTASessionContext</literal> - les sessions courantes sont
+ associées à une transaction <literal>JTA</literal>. La logique est la même que
+ l'ancienne approche basée sur JTA. Voir les javadocs pour les détails.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>org.hibernate.context.ThreadLocalSessionContext</literal> - les sessions
+ courantes sont associées au thread d'exécution. Voir les javadocs pour les détails.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Les deux implémentations fournissent un modèle de programmation de type "une session - une transaction
+ à la base de données", aussi connu sous le nom de <emphasis>session-per-request</emphasis>.
+ Le début et la fin d'une session Hibernate sont définis par la durée d'une transaction de base de données.
+ Si vous utilisez une démarcation programmatique de la transaction (par exemple sous J2SE ou JTA/UserTransaction/BMT),
+ nous vous conseillons d'utiliser l'API Hibernate <literal>Transaction</literal> pour masquer le système
+ de transaction utilisé. Si vous exécutez sous un conteneur EJB qui supporte CMT, vous n'avez besoin d'aucune
+ opérations de démarcations de session ou transaction dans votre code puisque tout
+ est géré de manière déclarative. Référez vous à <xref linkend="transactions"/> pour plus d'informations
+ et des exemples de code.
+ </para>
+
+ <para>
+ Le paramètre de configuration <literal>hibernate.current_session_context_class</literal>
+ définit quelle implémentation de <literal>org.hibernate.context.CurrentSessionContext</literal>
+ doit être utilisée. Notez que pour assurer la compatibilité avec les versions précédentes, si
+ ce paramètre n'est pas défini mais qu'un <literal>org.hibernate.transaction.TransactionManagerLookup</literal>
+ est configuré, Hibernate utilisera le <literal>org.hibernate.context.JTASessionContext</literal>.
+ La valeur de ce paramètre devrait juste nommer la classe d'implémentation à utiliser,
+ pour les deux implémentations fournies, il y a cependant deux alias correspondant: "jta" et "thread".
+ </para>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/association_mapping.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/association_mapping.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/association_mapping.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,623 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="associations">
+
+ <title>Mapper les associations</title>
+
+ <sect1 id="assoc-intro" revision="1">
+ <title>Introduction</title>
+
+ <para>
+ Correctement mapper les associations est souvent la tâche la plus difficile.
+ Dans cette section nous traiterons les cas classiques les uns après les autres.
+ Nous commencerons d'abbord par les mappings unidirectionnels, puis nous aborderons
+ la question des mappings bidirectionnels. Nous illustrerons tous nos exemples
+ avec les classes <literal>Person</literal> et <literal>Address</literal>.
+ </para>
+
+ <para>
+ Nous utiliserons deux critères pour classer les associations : le premier
+ sera de savoir si l'association est bâti sur une table supplémentaire d'association
+ et le deuxieme sera basé sur la multiplicité de cette association.
+ </para>
+
+ <para>
+ Autoriser une clé étrangère nulle est considéré comme un mauvais choix dans
+ la construction d'un modèle de données. Nous supposerons donc que dans tous
+ les exemples qui vont suivre on aura interdit la valeur nulle pour les clés
+ étrangères. Attention, ceci ne veut pas dire que Hibernate ne supporte pas
+ les clés étrangères pouvant prendre des valeurs nulles, les exemples qui suivent
+ continueront de fonctionner si vous décidiez ne plus imposer la contrainte
+ de non-nullité sur les clés étrangères.
+ </para>
+
+ </sect1>
+
+ <sect1 id="assoc-unidirectional" revision="1">
+ <title>Association unidirectionnelle</title>
+
+ <sect2 id="assoc-unidirectional-m21" >
+ <title>plusieurs à un</title>
+
+ <para>
+ Une <emphasis>association plusieurs-à-un (many-to-one) unidirectionnelle </emphasis>
+ est le type que l'on rencontre le plus souvent dans les associations unidirectionnelles.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"/>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+
+ </sect2>
+
+ <sect2 id="assoc-unidirectional-121">
+ <title>un à un</title>
+
+ <para>
+ une <emphasis>association un-à-un (one-to-one) sur une clé étrangère</emphasis>
+ est presque identique. La seule différence est sur la contrainte d'unicité que
+ l'on impose à cette colonne.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <many-to-one name="address"
+ column="addressId"
+ unique="true"
+ not-null="true"/>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ <para>
+ Une <emphasis>association un-à-un (one-to-one) unidirectionnelle sur une clé primaire</emphasis>
+ utilise un générateur d'identifiant particulier. (Remarquez que nous avons inversé le sens de cette
+ association dans cet exemple.)
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+</class>
+
+<class name="Address">
+ <id name="id" column="personId">
+ <generator class="foreign">
+ <param name="property">person</param>
+ </generator>
+ </id>
+ <one-to-one name="person" constrained="true"/>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-unidirectional-12m">
+ <title>un à plusieurs</title>
+
+ <para>
+ Une <emphasis>association un-à-plusieurs (one-to-many) unidirectionnelle sur une
+ clé étrangère</emphasis> est vraiment inhabituelle, et n'est pas vraiment recommandée.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <set name="addresses">
+ <key column="personId"
+ not-null="true"/>
+ <one-to-many class="Address"/>
+ </set>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( addressId bigint not null primary key, personId bigint not null )
+ ]]></programlisting>
+
+ <para>
+ Nous pensons qu'il est préférable d'utiliser une table de jointure pour ce type d'association.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="assoc-unidirectional-join" revision="1">
+ <title>Associations unidirectionnelles avec tables de jointure</title>
+
+ <sect2 id="assoc-unidirectional-join-12m">
+ <title>un à plusieurs</title>
+
+ <para>
+ Une <emphasis>association unidirectionnelle un-à-plusieurs (one-to-many) avec
+ une table de jointure</emphasis> est un bien meilleur choix.
+ Remarquez qu'en spécifiant <literal>unique="true"</literal>,
+ on a changé la multiplicité plusieurs-à-plusieurs (many-to-many) pour
+ un-à-plusieurs (one-to-many).
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <set name="addresses" table="PersonAddress">
+ <key column="personId"/>
+ <many-to-many column="addressId"
+ unique="true"
+ class="Address"/>
+ </set>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-unidirectional-join-m21">
+ <title>plusieurs à un</title>
+
+ <para>
+ Une <emphasis>assiociation plusieurs-à-un (many-to-one) unidirectionnelle sur
+ une table de jointure</emphasis> est très fréquente quand l'association est optionnelle.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <join table="PersonAddress"
+ optional="true">
+ <key column="personId" unique="true"/>
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"/>
+ </join>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-unidirectional-join-121">
+ <title>un à un</title>
+
+ <para>
+ Une <emphasis>association unidirectionnelle un-à-un (one-to-one) sur une table
+ de jointure</emphasis> est extrèmement rare mais envisageable.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <join table="PersonAddress"
+ optional="true">
+ <key column="personId"
+ unique="true"/>
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"
+ unique="true"/>
+ </join>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-unidirectional-join-m2m">
+ <title>plusieurs à plusieurs</title>
+
+ <para>
+ Finallement, nous avons <emphasis>l'association unidirectionnelle plusieurs-à-plusieurs (many-to-many)</emphasis>.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <set name="addresses" table="PersonAddress">
+ <key column="personId"/>
+ <many-to-many column="addressId"
+ class="Address"/>
+ </set>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="assoc-bidirectional" revision="1">
+ <title>Associations bidirectionnelles</title>
+
+ <sect2 id="assoc-bidirectional-m21" revision="2">
+ <title>un à plusieurs / plusieurs à un</title>
+
+ <para>
+ Une <emphasis>association bidirectionnelle plusieurs à un (many-to-one)</emphasis>
+ est le type d'association que l'on rencontre le plus souvent. (c'est la façon standard de créer
+ des relations parents/enfants.)
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"/>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+ <set name="people" inverse="true">
+ <key column="addressId"/>
+ <one-to-many class="Person"/>
+ </set>
+</class>]]></programlisting>
+
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ <para>
+ Si vous utilisez une <literal>List</literal> (ou toute autre collection indexée) vous devez
+ paramétrer la colonne <literal>key</literal> de la clé étrangère à <literal>not null</literal>,
+ et laisser Hibernate gérer l'association depuis l'extrémité collection pour maintenir l'index
+ de chaque élément (rendant l'autre extrémité virtuellement inverse en paramétrant
+ <literal>update="false"</literal> et <literal>insert="false"</literal>):
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id"/>
+ ...
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"
+ insert="false"
+ update="false"/>
+</class>
+
+<class name="Address">
+ <id name="id"/>
+ ...
+ <list name="people">
+ <key column="addressId" not-null="true"/>
+ <list-index column="peopleIdx"/>
+ <one-to-many class="Person"/>
+ </list>
+</class>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-bidirectional-121">
+ <title>Un à un</title>
+
+ <para>
+ Une <emphasis>association bidirectionnelle un à un (one-to-one) sur une clé étrangère</emphasis>
+ est aussi très fréquente.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <many-to-one name="address"
+ column="addressId"
+ unique="true"
+ not-null="true"/>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+ <one-to-one name="person"
+ property-ref="address"/>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ <para>
+ Une <emphasis>association bidirectionnelle un-à-un (one-to-one) sur une clé primaire</emphasis>
+ utilise un générateur particulier d'id.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <one-to-one name="address"/>
+</class>
+
+<class name="Address">
+ <id name="id" column="personId">
+ <generator class="foreign">
+ <param name="property">person</param>
+ </generator>
+ </id>
+ <one-to-one name="person"
+ constrained="true"/>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="assoc-bidirectional-join" revision="1">
+ <title>Associations bidirectionnelles avec table de jointure</title>
+
+ <sect2 id="assoc-bidirectional-join-12m">
+ <title>un à plusieurs / plusieurs à un</title>
+
+ <para>
+ Une <emphasis>association bidirectionnelle un-à-plusieurs (one-to-many) sur une table de jointure </emphasis>.
+ Remarquez que <literal>inverse="true"</literal> peut s'appliquer sur les deux extrémités de l'
+ association, sur la collection, ou sur la jointure.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <set name="addresses"
+ table="PersonAddress">
+ <key column="personId"/>
+ <many-to-many column="addressId"
+ unique="true"
+ class="Address"/>
+ </set>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+ <join table="PersonAddress"
+ inverse="true"
+ optional="true">
+ <key column="addressId"/>
+ <many-to-one name="person"
+ column="personId"
+ not-null="true"/>
+ </join>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-bidirectional-join-121">
+ <title>Un à un</title>
+
+ <para>
+ Une <emphasis>association bidirectionnelle un-à-un (one-to-one) sur une table de jointure</emphasis>
+ est extrèmement rare mais envisageable.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <join table="PersonAddress"
+ optional="true">
+ <key column="personId"
+ unique="true"/>
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"
+ unique="true"/>
+ </join>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+ <join table="PersonAddress"
+ optional="true"
+ inverse="true">
+ <key column="addressId"
+ unique="true"/>
+ <many-to-one name="person"
+ column="personId"
+ not-null="true"
+ unique="true"/>
+ </join>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-bidirectional-join-m2m" revision="1">
+ <title>plusieurs à plusieurs</title>
+
+ <para>
+ Finallement nous avons <emphasis>l'association bidirectionnelle plusieurs à plusieurs</emphasis>.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <set name="addresses" table="PersonAddress">
+ <key column="personId"/>
+ <many-to-many column="addressId"
+ class="Address"/>
+ </set>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+ <set name="people" inverse="true" table="PersonAddress">
+ <key column="addressId"/>
+ <many-to-many column="personId"
+ class="Person"/>
+ </set>
+</class>]]></programlisting>
+
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="assoc-complex">
+ <title>Des mappings plus complexes</title>
+
+ <para>
+ Des associations encore plus complexes sont <emphasis>extrêmement</emphasis> rares.
+ Hibernate permet de gérer des situations plus complexes en utilisant des
+ parties SQL dans les fichiers de mapping. Par exemple, si une table
+ avec l'historiques des informations d'un compte définit les colonnes
+ <literal>accountNumber</literal>, <literal>effectiveEndDate</literal>
+ et <literal>effectiveStartDate</literal>, mappées de telle sorte:
+ </para>
+
+ <programlisting><![CDATA[<properties name="currentAccountKey">
+ <property name="accountNumber" type="string" not-null="true"/>
+ <property name="currentAccount" type="boolean">
+ <formula>case when effectiveEndDate is null then 1 else 0 end</formula>
+ </property>
+</properties>
+<property name="effectiveEndDate" type="date"/>
+<property name="effectiveStateDate" type="date" not-null="true"/>]]></programlisting>
+
+ <para>
+ alors nous pouvons mapper une association à l'instance <emphasis>courante</emphasis>
+ (celle avec une <literal>effectiveEndDate</literal>) nulle en utilisant:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="currentAccountInfo"
+ property-ref="currentAccountKey"
+ class="AccountInfo">
+ <column name="accountNumber"/>
+ <formula>'1'</formula>
+</many-to-one>]]></programlisting>
+
+ <para>
+ Dans un exemple plus complexe, imaginez qu'une association entre
+ <literal>Employee</literal> et <literal>Organization</literal> est gérée
+ dans une table <literal>Employment</literal> pleines de données historiques.
+ Dans ce cas, une association vers l'employeur <emphasis>le plus récent</emphasis>
+ (celui avec la <literal>startDate</literal> la plus récente) pourrait être mappée comme cela:
+ </para>
+
+ <programlisting><![CDATA[<join>
+ <key column="employeeId"/>
+ <subselect>
+ select employeeId, orgId
+ from Employments
+ group by orgId
+ having startDate = max(startDate)
+ </subselect>
+ <many-to-one name="mostRecentEmployer"
+ class="Organization"
+ column="orgId"/>
+</join>]]></programlisting>
+
+ <para>
+ Vous pouvez être créatif grace à ces possibilités, mais il est généralement plus pratique
+ d'utiliser des requêtes HQL ou criteria dans ce genre de situation.
+ </para>
+
+ </sect1>
+
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/basic_mapping.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/basic_mapping.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/basic_mapping.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,3117 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+<chapter id="mapping">
+ <title>Mapping O/R basique</title>
+ <sect1 id="mapping-declaration" revision="1">
+ <title>Déclaration de Mapping</title>
+ <para>
+ Les mappings Objet/relationnel sont généralement définis dans un document XML.
+ Le document de mapping est conçu pour être lisible et éditable à la main.
+ Le langage de mapping est Java-centrique, c'est à dire que les mappings sont construits
+ à partir des déclarations des classes persistantes et non des déclarations des tables.
+ </para>
+ <para>
+ Remarquez que même si beaucoup d'utilisateurs de Hibernate préfèrent écrire les
+ fichiers de mappings à la main, plusieurs outils existent pour générer ce document,
+ notamment XDoclet, Middlegen et AndroMDA.
+ </para>
+ <para>Démarrons avec un exemple de mapping :</para>
+ <programlisting id="mapping-declaration-ex1" revision="1"><![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">
+
+<hibernate-mapping package="eg">
+
+ <class name="Cat"
+ table="cats"
+ discriminator-value="C">
+
+ <id name="id">
+ <generator class="native"/>
+ </id>
+
+ <discriminator column="subclass"
+ type="character"/>
+
+ <property name="weight"/>
+
+ <property name="birthdate"
+ type="date"
+ not-null="true"
+ update="false"/>
+
+ <property name="color"
+ type="eg.types.ColorUserType"
+ not-null="true"
+ update="false"/>
+
+ <property name="sex"
+ not-null="true"
+ update="false"/>
+
+ <property name="litterId"
+ column="litterId"
+ update="false"/>
+
+ <many-to-one name="mother"
+ column="mother_id"
+ update="false"/>
+
+ <set name="kittens"
+ inverse="true"
+ order-by="litter_id">
+ <key column="mother_id"/>
+ <one-to-many class="Cat"/>
+ </set>
+
+ <subclass name="DomesticCat"
+ discriminator-value="D">
+
+ <property name="name"
+ type="string"/>
+
+ </subclass>
+
+ </class>
+
+ <class name="Dog">
+ <!-- mapping for Dog could go here -->
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+ <para>
+ Etudions le contenu du document de mapping. Nous décrirons uniquement
+ les éléments et attributs du document utilisés par Hibernate à l'exécution.
+ Le document de mapping contient aussi des attributs et éléments optionnels
+ qui agissent sur le schéma de base de données exporté par l'outil de
+ génération de schéma. (Par exemple l'attribut <literal>not-null</literal>.)
+ </para>
+ <sect2 id="mapping-declaration-doctype" revision="2">
+ <title>Doctype</title>
+ <para>
+ Tous les mappings XML devraient utiliser le doctype indiqué.
+ Ce fichier est présent à l'URL ci-dessus, dans le répertoire
+ <literal>hibernate-x.x.x/src/org/hibernate</literal> ou dans <literal>hibernate3.jar</literal>.
+ Hibernate va toujours chercher la DTD dans son classpath en premier lieu. Si vous constatez
+ 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">
+ <title>hibernate-mapping</title>
+ <para>
+ Cet élément a plusieurs attributs optionnels. Les attributs <literal>schema</literal> et <literal>catalog</literal>
+ indiquent que les tables référencées par ce mapping appartiennent au schéma nommé et/ou au catalogue.
+ S'ils sont spécifiés, les noms de tables seront qualifiés par les noms de schéma et catalogue.
+ L'attribut <literal>default-cascade</literal> indique quel type de cascade sera utlisé par défaut
+ pour les propriétés et collections qui ne précisent pas l'attribut <literal>cascade</literal>.
+ L'attribut <literal>auto-import</literal> nous permet d'utiliser par défaut des noms de classes
+ non qualifiés dans le langage de requête.
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="hm1" coords="2 55"/>
+ <area id="hm2" coords="3 55"/>
+ <area id="hm3" coords="4 55"/>
+ <area id="hm4" coords="5 55"/>
+ <area id="hm5" coords="6 55"/>
+ <area id="hm6" coords="7 55"/>
+ <area id="hm7" coords="8 55"/>
+ </areaspec>
+ <programlisting><![CDATA[<hibernate-mapping
+ schema="schemaName"
+ catalog="catalogName"
+ default-cascade="cascade_style"
+ default-access="field|property|ClassName"
+ default-lazy="true|false"
+ auto-import="true|false"
+ package="package.name"
+ />]]></programlisting>
+ <calloutlist>
+ <callout arearefs="hm1">
+ <para>
+ <literal>schema</literal> (optionnel) : Le nom d'un schéma de base de données.
+ </para>
+ </callout>
+ <callout arearefs="hm2">
+ <para>
+ <literal>catalog</literal> (optionnel) : Le nom d'un catalogue de base de données.
+ </para>
+ </callout>
+ <callout arearefs="hm3">
+ <para>
+ <literal>default-cascade</literal> (optionnel - par défaut vaut : <literal>none</literal>) :
+ Un type de cascade par défaut.
+ </para>
+ </callout>
+ <callout arearefs="hm4">
+ <para>
+ <literal>default-access</literal> (optionnel - par défaut vaut : <literal>property</literal>) :
+ Comment hibernate accèdera aux propriétés. On peut aussi
+ redéfinir sa propre implémentation de <literal>PropertyAccessor</literal>.
+ </para>
+ </callout>
+ <callout arearefs="hm5">
+ <para>
+ <literal>default-lazy</literal> (optionnel - par défaut vaut : <literal>true</literal>) :
+ Valeur par défaut pour un attribut <literal>lazy</literal>
+ non spécifié : celui des mappings de classes et de collection.
+ </para>
+ </callout>
+ <callout arearefs="hm6">
+ <para>
+ <literal>auto-import</literal> (optionnel - par défaut vaut : <literal>true</literal>) :
+ Spécifie si l'on peut utiliser des noms de classes
+ non qualifiés (des classes de ce mapping) dans le langage de requête.
+ </para>
+ </callout>
+ <callout arearefs="hm7">
+ <para>
+ <literal>package</literal> (optionnel) : Préfixe de package par défaut pour
+ les noms de classe non qualifiés du document de mapping.
+
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Si deux classes possèdent le même nom de classe (non qualifié), vous devez indiquer
+ <literal>auto-import="false"</literal>. Hibernate lancera une exception
+ si vous essayez d'assigner à deux classes le même nom importé.
+ </para>
+ <para>
+ Notez que l'élément <literal>hibernate-mapping</literal> vous permet d'imbriquer plusieurs mappings de
+ <literal><class></literal> persistantes, comme dans l'exemple ci-dessus.
+ Cependant la bonne pratique (ce qui est attendu par certains outils) est
+ de mapper une seule classe (ou une seule hiérarchie de classes)
+ par fichier de mapping et de nommer ce fichier d'après le nom de la superclasse, par exemple
+ <literal>Cat.hbm.xml</literal>, <literal>Dog.hbm.xml</literal>, ou en cas d'héritage,
+ <literal>Animal.hbm.xml</literal>.
+ </para>
+ </sect2>
+ <sect2 id="mapping-declaration-class" revision="3">
+ <title>class</title>
+ <para>
+ Déclarez une classe persistante avec l'élément <literal>class</literal> :
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="class1" coords="2 55"/>
+ <area id="class2" coords="3 55"/>
+ <area id="class3" coords="4 55"/>
+ <area id="class4" coords="5 55"/>
+ <area id="class5" coords="6 55"/>
+ <area id="class6" coords="7 55"/>
+ <area id="class7" coords="8 55"/>
+ <area id="class8" coords="9 55"/>
+ <area id="class9" coords="10 55"/>
+ <area id="class10" coords="11 55"/>
+ <area id="class11" coords="12 55"/>
+ <area id="class12" coords="13 55"/>
+ <area id="class13" coords="14 55"/>
+ <area id="class14" coords="15 55"/>
+ <area id="class15" coords="16 55"/>
+ <area id="class16" coords="17 55"/>
+ <area id="class17" coords="18 55"/>
+ <area id="class18" coords="19 55"/>
+ <area id="class19" coords="20 55"/>
+ <area id="class20" coords="21 55"/>
+ <area id="class21" coords="22 55"/>
+ </areaspec>
+ <programlisting><![CDATA[<class
+ name="ClassName"
+ table="tableName"
+ discriminator-value="discriminator_value"
+ mutable="true|false"
+ schema="owner"
+ catalog="catalog"
+ proxy="ProxyInterface"
+ dynamic-update="true|false"
+ dynamic-insert="true|false"
+ select-before-update="true|false"
+ polymorphism="implicit|explicit"
+ where="arbitrary sql where condition"
+ persister="PersisterClass"
+ batch-size="N"
+ optimistic-lock="none|version|dirty|all"
+ lazy="true|false"
+ entity-name="EntityName"
+ catalog="catalog"
+ check="arbitrary sql check condition"
+ rowid="rowid"
+ subselect="SQL expression"
+ abstract="true|false"
+ entity-name="EntityName"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="class1">
+ <para>
+ <literal>name</literal> (optionnel) : Le nom Java complet de la classe (ou interface) persistante.
+ Si cet attribut est absent, il est supposé que ce mapping ne se rapporte pas à une entité POJO.
+ </para>
+ </callout>
+ <callout arearefs="class2">
+ <para>
+ <literal>table</literal> (optionnel - par défaut le nom (non-qualifié) de la classe) : Le
+ nom de sa table en base de données.
+ </para>
+ </callout>
+ <callout arearefs="class3">
+ <para>
+ <literal>discriminator-value</literal> (optionnel - par défaut le nom de la classe) :
+ Une valeur permettant de distinguer les sous-classes dans le cas de l'utilisation du polymorphisme.
+ Les valeurs <literal>null</literal> et <literal>not null</literal> sont autorisées.
+ </para>
+ </callout>
+ <callout arearefs="class4">
+ <para>
+ <literal>mutable</literal> (optionnel, vaut <literal>true</literal> par défaut) : Spécifie
+ que des instances de la classe sont (ou non) immuables.
+ </para>
+ </callout>
+ <callout arearefs="class5">
+ <para>
+ <literal>schema</literal> (optionnel) : Surcharge le nom de schéma spécifié par
+ l'élément racine <literal><hibernate-mapping></literal>.
+ </para>
+ </callout>
+ <callout arearefs="class6">
+ <para>
+ <literal>catalog</literal> (optionnel) : Surcharge le nom du catalogue spécifié par
+ l'élément racine <literal><hibernate-mapping></literal>.
+ </para>
+ </callout>
+ <callout arearefs="class7">
+ <para>
+ <literal>proxy</literal> (optionnel) : Spécifie une interface à utiliser pour l'initialisation différée (lazy loading)
+ des proxies. Vous pouvez indiquer le nom de la classe elle-même.
+ </para>
+ </callout>
+ <callout arearefs="class8">
+ <para>
+ <literal>dynamic-update</literal> (optionnel, par défaut à <literal>false</literal>) :
+ Spécifie que les <literal>UPDATE</literal> SQL doivent être générés à l'exécution et contenir
+ uniquement les colonnes dont les valeurs ont été modifiées.
+ </para>
+ </callout>
+ <callout arearefs="class9">
+ <para>
+ <literal>dynamic-insert</literal> (optionnel, par défaut à <literal>false</literal>):
+ Spécifie que les <literal>INSERT</literal> SQL doivent être générés à l'exécution et ne contenir
+ que les colonnes dont les valeurs sont non nulles.
+ </para>
+ </callout>
+ <callout arearefs="class10">
+ <para>
+ <literal>select-before-update</literal> (optionnel, par défaut à <literal>false</literal>):
+ Spécifie que Hibernate ne doit <emphasis>jamais</emphasis> exécuter un <literal>UPDATE</literal> SQL
+ sans être certain qu'un objet a été réellement modifié. Dans certains cas, (en réalité, seulement
+ quand un objet transient a été associé à une nouvelle session par <literal>update()</literal>),
+ cela signifie que Hibernate exécutera un <literal>SELECT</literal> SQL pour s'assurer qu'un
+ <literal>UPDATE</literal> SQL est véritablement nécessaire.
+ </para>
+ </callout>
+ <callout arearefs="class11">
+ <para>
+ <literal>polymorphism</literal> (optionnel, vaut <literal>implicit</literal> par défaut) :
+ Détermine si, pour cette classe, une requête polymorphique implicite ou explicite est utilisée.
+ </para>
+ </callout>
+ <callout arearefs="class12">
+ <para>
+ <literal>where</literal> (optionnel) spécifie une clause SQL <literal>WHERE</literal>
+ à utiliser lorsque l'on récupère des objets de cette classe.
+ </para>
+ </callout>
+ <callout arearefs="class13">
+ <para>
+ <literal>persister</literal> (optionnel) : Spécifie un <literal>ClassPersister</literal> particulier.
+ </para>
+ </callout>
+ <callout arearefs="class14">
+ <para>
+ <literal>batch-size</literal> (optionnel, par défaut = <literal>1</literal>) : spécifie une taille de batch
+ pour remplir les instances de cette classe par identifiant en une seule requête.
+ </para>
+ </callout>
+ <callout arearefs="class15">
+ <para>
+ <literal>optimistic-lock</literal> (optionnel, par défaut = <literal>version</literal>) :
+ Détermine la stratégie de verrou optimiste.
+ </para>
+ </callout>
+ <callout arearefs="class16">
+ <para>
+ <literal>lazy</literal> (optionnel) : Déclarer <literal>lazy="true"</literal> est un raccourci
+ pour spécifier le nom de la classe comme étant l'interface <literal>proxy</literal>.
+ </para>
+ </callout>
+ <callout arearefs="class17">
+ <para>
+ <literal>entity-name</literal> (optionnel) : Hibernate3 permet à une classe d'être
+ mappée plusieurs fois (potentiellement à plusieurs tables), et permet aux mappings d'entité d'être
+ représentés par des Maps ou du XML au niveau Java. Dans ces cas, vous devez indiquer un nom explicite arbitraire pour
+ les entités. Voir <xref linkend="persistent-classes-dynamicmodels"/> et <xref linkend="xml"/>
+ 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">
+ <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
+ <literal>rowid</literal> pour des mises à jour rapides si cette option vaut <literal>rowid</literal>. Un ROWID représente
+ la localisation physique d'un tuple enregistré.
+ </para>
+ </callout>
+ <callout arearefs="class21">
+ <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">
+ <para>
+ <literal>abstract</literal> (optionnel) : Utilisé pour marquer des superclasses abstraites dans
+ des hiérarchies de <literal><union-subclass></literal>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Il est tout à fait possible d'utiliser une interface comme nom
+ de classe persistante. Vous devez alors déclarer les classes implémentant
+ cette interface en utilisant l'élément <literal><subclass></literal>.
+ Vous pouvez faire persister toute classe interne <emphasis>static</emphasis>.
+ Vous devez alors spécifier le nom de la classe par la notation habituelle
+ des classes internes c'est à dire <literal>eg.Foo$Bar</literal>.
+ </para>
+ <para>
+ Les classes immuables, <literal>mutable="false"</literal>, ne peuvent
+ pas être modifiées ou supprimées par l'application. Cela permet
+ à Hibernate de faire quelques optimisations mineures sur les performances.
+ </para>
+ <para>
+ L'attribut optionnnel <literal>proxy</literal> permet les intialisations
+ différées des instances persistantes de la classe. Hibernate retournera
+ initialement des proxies CGLIB qui implémentent l'interface nommée.
+ Le véritable objet persistant ne sera chargé que lorsque une méthode du proxy
+ sera appelée. Voir plus bas le paragraphe abordant les proxies et le chargement différé (lazy initialization).
+ </para>
+ <para>
+ Le polymorphisme <emphasis>implicite</emphasis>
+ signifie que les instances de la classe seront retournées par une
+ requête qui utilise les noms de la classe ou de chacune de ses
+ superclasses ou encore des interfaces implémentées par cette classe
+ ou ses superclasses. Les instances des classes filles seront retournées
+ par une requête qui utilise le nom de la classe elle même. Le polymorphisme
+ <emphasis>explicite</emphasis> signifie que les instances de la classe
+ ne seront retournées que par une requête qui utilise explicitement
+ son nom et que seules les instances des classes filles déclarées dans les éléments
+ <literal><subclass></literal> ou <literal><joined-subclass></literal>
+ seront retournées. Dans la majorités des cas la valeur par défaut,
+ <literal>polymorphism="implicit"</literal>,
+ est appropriée. Le polymorphisme explicite est utile lorsque deux
+ classes différentes sont mappées à la même table (ceci permet d'écrire
+ une classe "légère" qui ne contient qu'une partie des colonnes de
+ la table - voir la partie design pattern du site communautaire).
+ </para>
+ <para>
+ L'attribut <literal>persister</literal> vous permet de customiser
+ la stratégie utilisée pour la classe. Vous pouvez, par exemple, spécifier
+ votre propre sous-classe de <literal>org.hibernate.persister.EntityPersister</literal> ou
+ vous pourriez aussi créer une nouvelle implémentation de l'interface <literal>org.hibernate.persister.ClassPersister</literal>
+ qui proposerait une persistance via, par exemple, des appels de procédures
+ stockées, de la sérialisation vers des fichiers plats ou un annuaire LDAP.
+ Voir <literal>org.hibernate.test.CustomPersister</literal> pour un exemple simple (d'une "persistance"
+ vers une <literal>Hashtable</literal>).
+ </para>
+ <para>
+ Notez que les paramètres <literal>dynamic-update</literal> et <literal>dynamic-insert</literal>
+ ne sont pas hérités par les sous-classes et peuvent donc être spécifiés
+ pour les éléments <literal><subclass></literal> ou <literal><joined-subclass></literal>
+ Ces paramètres peuvent améliorer les performances dans certains cas,
+ mais peuvent aussi les amoindrir. A utiliser en connaissance de causes.
+ </para>
+ <para>
+ L'utilisation de <literal>select-before-update</literal> va généralement
+ faire baisser les performances. Ce paramètre est pratique
+ pour prévenir l'appel inutile d'un trigger sur modification quand on
+ réattache un graphe d'instances à une <literal>Session</literal>.
+ </para>
+ <para>
+ Si vous utilisez le <literal>dynamic-update</literal>, les différentes
+ stratégies de verrouillage optimiste (optimistic locking) sont les suivantes:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>version</literal> vérifie les colonnes version/timestamp
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>all</literal> vérifie toutes les colonnes
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>dirty</literal> vérifie les colonnes modifiées, permettant des updates concurrents
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>none</literal> pas de verrouillage optimiste
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Nous encourageons <emphasis>très</emphasis> fortement l'utilisation
+ de colonnes de version/timestamp pour le verrouillage optimiste
+ avec Hibernate. C'est la meilleure stratégie en regard des performances
+ et la seule qui gère correctement les modifications sur les objets détachés
+ (c'est à dire lorsqu'on utilise <literal>Session.merge()</literal>).
+ </para>
+ <para>
+ Il n'y a pas de différence entre table et vue pour le mapping Hibernate,
+ tant que c'est transparent au niveau base de données (remarquez
+ que certaines BDD ne supportent pas les vues correctement, notamment
+ pour les updates). Vous rencontrerez peut-être des cas où vous
+ souhaitez utiliser une vue mais ne pouvez pas en créer sur votre BDD
+ (par exemple à cause de schémas anciens et figés). Dans ces cas,
+ vous pouvez mapper une entité immuable en lecture seule sur un sous-select SQL donné:
+ </para>
+ <programlisting><![CDATA[<class name="Summary">
+ <subselect>
+ select item.name, max(bid.amount), count(*)
+ from item
+ join bid on bid.item_id = item.id
+ group by item.name
+ </subselect>
+ <synchronize table="item"/>
+ <synchronize table="bid"/>
+ <id name="name"/>
+ ...
+</class>]]></programlisting>
+ <para>
+ Déclarez les tables à synchroniser avec cette entité pour assurer
+ que le flush automatique se produise correctement,
+ et pour que les requêtes sur l'entité dérivée ne renvoient pas des données périmées.
+ Le litéral <literal><subselect></literal> est disponible
+ comme attribut ou comme élément de mapping.
+ </para>
+ </sect2>
+ <sect2 id="mapping-declaration-id" revision="4">
+ <title>id</title>
+ <para>
+ Les classes mappées <emphasis>doivent</emphasis> déclarer la
+ clef primaire de la table en base de données.
+ La plupart des classes auront aussi une propriété de type
+ javabean présentant l'identifiant unique d'une instance.
+ L'élément <literal><id></literal> sert à définir le
+ mapping entre cette propriété et la clef primaire en base.
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="id1" coords="2 65"/>
+ <area id="id2" coords="3 65"/>
+ <area id="id3" coords="4 65"/>
+ <area id="id4" coords="5 65"/>
+ <area id="id5" coords="6 65"/>
+ </areaspec>
+ <programlisting><![CDATA[<id
+ name="propertyName"
+ type="typename"
+ column="column_name"
+ unsaved-value="null|any|none|undefined|id_value"
+ access="field|property|ClassName">
+
+ <generator class="generatorClass"/>
+</id>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="id1">
+ <para>
+ <literal>name</literal> (optionnel) : Nom de la propriété qui sert d'identifiant.
+ </para>
+ </callout>
+ <callout arearefs="id2">
+ <para>
+ <literal>type</literal> (optionnel) : Nom indiquant le type Hibernate.
+ </para>
+ </callout>
+ <callout arearefs="id3">
+ <para>
+ <literal>column</literal> (optionnel - le nom de la propriété est pris par défaut) : Nom de la clef primaire.
+ </para>
+ </callout>
+ <callout arearefs="id4">
+ <para>
+ <literal>unsaved-value</literal> (optionnel - par défaut une valeur "bien choisie") :
+ Une valeur de la propriété d'identifiant qui indique que l'instance est nouvellement
+ instanciée (non sauvegardée), et qui la distingue des instances <literal>transient</literal>s qui ont
+ été sauvegardées ou chargées dans une session précédente.
+ </para>
+ </callout>
+ <callout arearefs="id5">
+ <para>
+ <literal>access</literal> (optionnel - par défaut <literal>property</literal>) : La stratégie que doit utiliser Hibernate
+ pour accéder aux valeurs des propriétés.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Si l'attribut <literal>name</literal> est absent, Hibernate considère que la classe ne possède pas de propriété identifiant.
+ </para>
+ <para>
+ L'attribut <literal>unsaved-value</literal> est important ! Si
+ l'identifiant de votre classe n'a pas une valeur par défaut compatible avec
+ le comportement standard de Java (zéro ou null), vous devez alors préciser la valeur par défaut.
+ </para>
+ <para>
+ La déclaration alternative <literal><composite-id></literal>
+ permet l'acccès aux données d'anciens systèmes qui utilisent des
+ clefs composées. Son utilisation est fortement déconseillée pour d'autres cas.
+ </para>
+ <sect3 id="mapping-declaration-id-generator" revision="2">
+ <title>Generator</title>
+ <para>
+ L'élément fils <literal><generator></literal> nomme une classe Java utilisée pour générer
+ les identifiants uniques pour les instances des classes persistantes. Si des paramètres sont requis
+ pour configurer ou initialiser l'instance du générateur, ils sont passés en utilisant l'élément <literal><param></literal>.
+ </para>
+ <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+ <generator class="org.hibernate.id.TableHiLoGenerator">
+ <param name="table">uid_table</param>
+ <param name="column">next_hi_value_column</param>
+ </generator>
+</id>]]></programlisting>
+ <para>
+ Tous les générateurs doivent implémenter l'interface <literal>org.hibernate.id.IdentifierGenerator</literal>.
+ C'est une interface très simple ; certaines applications peuvent proposer leur propre implémentations spécialisées.
+ Cependant, Hibernate propose une série d'implémentations intégrées. Il existe des noms raccourcis pour les générateurs intégrés :
+ <variablelist>
+ <varlistentry>
+ <term>
+ <literal>increment</literal>
+ </term>
+ <listitem>
+ <para>
+ Génère des identifiants de type <literal>long</literal>, <literal>short</literal> ou
+ <literal>int</literal> qui ne sont uniques que si aucun autre processus n'insère de données dans la même table.
+ <emphasis>Ne pas utiliser en environnement clusterisé.</emphasis>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>identity</literal>
+ </term>
+ <listitem>
+ <para>
+ Utilisation de la colonne identity de DB2, MySQL, MS SQL Server, Sybase et
+ HypersonicSQL. L'identifiant renvoyé est de type <literal>long</literal>,
+ <literal>short</literal> ou <literal>int</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>sequence</literal>
+ </term>
+ <listitem>
+ <para>
+ Utilisation des séquences dans DB2, PostgreSQL, Oracle, SAP DB, McKoi ou d'un générateur dans Interbase.
+ L'identifiant renvoyé est de type <literal>long</literal>,
+ <literal>short</literal> ou <literal>int</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>hilo</literal>
+ </term>
+ <listitem>
+ <para id="mapping-declaration-id-hilodescription" revision="1">
+ Utilise un algorithme hi/lo pour générer de façon efficace des identifiants de type
+ <literal>long</literal>, <literal>short</literal> ou <literal>int</literal>,
+ en prenant comme source de valeur "hi" une table et une colonne (par défaut
+ <literal>hibernate_unique_key</literal> et
+ <literal>next_hi</literal> respectivement). L'algorithme hi/lo génère des identifiants uniques
+ pour une base de données particulière seulement.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>seqhilo</literal>
+ </term>
+ <listitem>
+ <para>
+ Utilise un algorithme hi/lo pour générer efficacement des identifiants de type <literal>long</literal>, <literal>short</literal> ou <literal>int</literal>,
+ étant donné un nom de séquence en base.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>uuid</literal>
+ </term>
+ <listitem>
+ <para>
+ Utilise un algorithme de type UUID 128 bits pour générer des identifiants de
+ type string, unique au sein d'un réseau (l'adresse IP est utilisée).
+ Le UUID en codé en une chaîne de nombre héxadécimaux de longueur 32.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>guid</literal>
+ </term>
+ <listitem>
+ <para>
+ Utilise une chaîne GUID générée par la base pour MS SQL Server et MySQL.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>native</literal>
+ </term>
+ <listitem>
+ <para>
+ Choisit <literal>identity</literal>, <literal>sequence</literal> ou
+ <literal>hilo</literal> selon les possibilités offertes par la base de données sous-jacente.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>assigned</literal>
+ </term>
+ <listitem>
+ <para>
+ Laisse l'application affecter un identifiant à l'objet avant que la métode
+ <literal>save()</literal> soit appelée. Il s'agit de la stratégie par défaut
+ si aucun <literal><generator></literal> n'est spécifié.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>select</literal>
+ </term>
+ <listitem>
+ <para>
+ Récupère une clef primaire assignée par un trigger en sélectionnant
+ la ligne par une clef unique quelconque.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>foreign</literal>
+ </term>
+ <listitem>
+ <para>
+ Utilise l'identifiant d'un objet associé. Habituellement utilisé en conjonction
+ avec une association <literal><one-to-one></literal> sur la clef primaire.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect3>
+ <sect3 id="mapping-declaration-id-hilo" revision="1">
+ <title>algorithme Hi/lo</title>
+ <para>
+ Les générateurs <literal>hilo</literal> et <literal>seqhilo</literal> proposent deux implémentations
+ alternatives de l'algorithme hi/lo, une approche largement utilisée pour générer des identifiants. La
+ première implémentation nécessite une table "spéciale" en base pour héberger la prochaine valeur "hi" disponible.
+ La seconde utilise une séquence de type Oracle (quand la base sous-jacente le propose).
+ </para>
+ <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+ <generator class="hilo">
+ <param name="table">hi_value</param>
+ <param name="column">next_value</param>
+ <param name="max_lo">100</param>
+ </generator>
+</id>]]></programlisting>
+ <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+ <generator class="seqhilo">
+ <param name="sequence">hi_value</param>
+ <param name="max_lo">100</param>
+ </generator>
+</id>]]></programlisting>
+ <para>
+ Malheureusement, vous ne pouvez pas utilisez <literal>hilo</literal> quand vous apportez
+ votre propre <literal>Connection</literal> à Hibernate. Quand Hibernate utilise une datasource du serveur
+ d'application pour obtenir des connexions inscrites avec JTA, vous devez correctement configurer
+ <literal>hibernate.transaction.manager_lookup_class</literal>.
+ </para>
+ </sect3>
+ <sect3 id="mapping-declaration-id-uuid">
+ <title>UUID algorithm</title>
+ <para>
+ Le contenu du UUID est : adresse IP, date de démarrage de la JVM (précis au quart de seconde),
+ l'heure système et un compteur (unique au sein de la JVM). Il n'est pas possible d'obtenir l'adresse
+ MAC ou une adresse mémoire à partir de Java, c'est donc le mieux que l'on puisse faire sans utiliser JNI.
+ </para>
+ </sect3>
+ <sect3 id="mapping-declaration-id-sequences">
+ <title>Colonnes identifiantes et séquences</title>
+ <para>
+ Pour les bases qui implémentent les colonnes "identité" (DB2, MySQL, Sybase, MS SQL),
+ vous pouvez utiliser la génération de clef par <literal>identity</literal>.
+ Pour les bases qui implémentent les séquences (DB2, Oracle, PostgreSQL, Interbase, McKoi, SAP DB)
+ vous pouvez utiliser la génération de clef par <literal>sequence</literal>. Ces deux méthodes nécessitent
+ deux requêtes SQL pour insérer un objet.
+ </para>
+ <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+ <generator class="sequence">
+ <param name="sequence">person_id_sequence</param>
+ </generator>
+</id>]]></programlisting>
+ <programlisting><![CDATA[<id name="id" type="long" column="person_id" unsaved-value="0">
+ <generator class="identity"/>
+</id>]]></programlisting>
+ <para>Pour le développement multi-plateformes, la stratégie <literal>native</literal> choisira
+ entre les méthodes <literal>identity</literal>, <literal>sequence</literal> et
+ <literal>hilo</literal>, selon les possibilités offertes par la base sous-jacente.
+ </para>
+ </sect3>
+ <sect3 id="mapping-declaration-id-assigned">
+ <title>Identifiants assignés</title>
+ <para>
+ Si vous souhaitez que l'application assigne des identifiants (par opposition
+ à la génération par Hibernate), vous pouvez utiliser le générateur <literal>assigned</literal>.
+ Ce générateur spécial utilisera une valeur d'identifiant déjà utilisé par la propriété identifiant l'objet.
+ Ce générateur est utilisé quand la clef primaire est une clef naturelle plutôt qu'une clef secondaire.
+ C'est le comportement par défaut si vous ne précisez pas d'élément <literal><generator></literal>.
+ </para>
+ <para>
+ Choisir le générateur <literal>assigned</literal> fait utiliser
+ <literal>unsaved-value="undefined"</literal> par Hibernate, le forçant à interroger
+ la base pour déterminer si l'instance est transiente ou détachée, à moins d'utiliser
+ une propriété version ou timestamp, ou alors de définir
+ <literal>Interceptor.isUnsaved()</literal>.
+ </para>
+ </sect3>
+ <sect3 id="mapping-declaration-id-select">
+ <title>Clefs primaires assignées par trigger</title>
+ <para>
+ Pour les schémas de base hérités d'anciens systèmes uniquement (Hibernate ne génère pas de DDL avec des triggers)
+ </para>
+ <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+ <generator class="select">
+ <param name="key">socialSecurityNumber</param>
+ </generator>
+</id>]]></programlisting>
+ <para>
+ Dans l'exemple ci-dessus, <literal>socialSecurityNumber</literal> a une
+ valeur unique définie par la classe en tant que clef naturelle et <literal>person_id</literal>
+ est une clef secondaire dont la valeur est générée par trigger.
+ </para>
+ </sect3>
+ </sect2>
+ <sect2 id="mapping-declaration-compositeid" revision="3">
+ <title>composite-id</title>
+ <programlisting><![CDATA[<composite-id
+ name="propertyName"
+ class="ClassName"
+ mapped="true|false"
+ access="field|property|ClassName">
+ node="element-name|."
+
+ <key-property name="propertyName" type="typename" column="column_name"/>
+ <key-many-to-one name="propertyName class="ClassName" column="column_name"/>
+ ......
+</composite-id>]]></programlisting>
+ <para>
+ Pour une table avec clef composée, vous pouvez mapper plusieurs attributs de la classe
+ comme propriétés identifiantes. L'élement <literal><composite-id></literal> accepte
+ les mappings de propriétés <literal><key-property></literal> et les mappings
+ <literal><key-many-to-one></literal> comme fils.
+ </para>
+ <programlisting><![CDATA[<composite-id>
+ <key-property name="medicareNumber"/>
+ <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+ <para>
+ Vos classes persistantes <emphasis>doivent</emphasis> surcharger les méthodes <literal>equals()</literal>
+ et <literal>hashCode()</literal> pour implémenter l'égalité d'identifiant composé. Elles doivent aussi
+ implenter l'interface <literal>Serializable</literal>.
+ </para>
+ <para>
+ Malheureusement cette approche sur les identifiants composés signifie qu'un objet persistant
+ est son propre identifiant. Il n'y a pas d'autre moyen pratique de manipuler l'objet que par l'objet lui-même.
+ Vous devez instancier une instance de la classe persistante elle-même et peupler ses attributs identifiants
+ avant de pouvoir appeler la méthode <literal>load()</literal> pour charger son état persistant associé
+ à une clef composée. Nous appelons cette approche "identifiant composé <emphasis>embarqué</emphasis>"
+ et ne la recommandons pas pour des applications complexes.
+ </para>
+
+ <para>
+ Une seconde approche, appelée identifiant composé <emphasis>mappé</emphasis>,
+ consiste à encapsuler les propriétés identifiantes (celles contenues dans <literal><composite-id></literal>)
+ dans une classe particulière.
+ </para>
+
+ <programlisting><![CDATA[<composite-id class="MedicareId" mapped="true">
+ <key-property name="medicareNumber"/>
+ <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+ <para>
+ Dans cet exemple, la classe d'identifiant composée,<literal>MedicareId</literal> et la classe mappée elle-même,
+ possèdent les propriétés <literal>medicareNumber</literal>
+ et <literal>dependent</literal>. La classe identifiante doit redéfinir
+ <literal>equals()</literal> et <literal>hashCode()</literal> et implémenter
+ <literal>Serializable</literal>. Le désavantage de cette approche est la
+ duplication du code.
+ </para>
+
+ <para>
+ Les attributs suivants servent à configurer un identifiant composé mappé :
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>mapped</literal> (optionnel, défaut à <literal>false</literal>) :
+ indique qu'un identifiant composé mappé est utilisé, et que les propriétés
+ contenues font référence aux deux classes (celle mappée et la classe identifiante).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>class</literal> (optionnel, mais requis pour un identifiant composé mappé) :
+ La classe composant utilisée comme identifiant composé.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Nous décrirons une troisième approche beaucoup plus efficace ou l'identifiant composé
+ est implémenté comme une classe composant dans <xref linkend="components-compositeid"/>.
+ Les attributs décrits ci dessous, ne s'appliquent que pour cette dernière approche :
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>name</literal> (optionnel, requis pour cette approche) : une propriété de type
+ composant qui contient l'identifiant composé (voir chapitre 9).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>access</literal> (optionnel - défaut à <literal>property</literal>) :
+ La stratégie qu'Hibernate utilisera pour accéder à la valeur de la propriété.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>class</literal> (optionnel - défaut au type de la propriété déterminé par réflexion) :
+ La classe composant utilisée comme identifiant (voir prochaine section).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Cette dernière approche est celle que nous recommandons pour toutes vos applications.
+ </para>
+ </sect2>
+ <sect2 id="mapping-declaration-discriminator" revision="3">
+ <title>discriminator</title>
+ <para>
+ L'élément <literal><discriminator></literal> est nécessaire pour la persistance polymorphique
+ qui utilise la stratégie de mapping de table par hiérarchie de classe. La colonne discriminante contient
+ une valeur marqueur qui permet à la couche de persistance de savoir quelle
+ sous-classe instancier pour une ligne particulière de table en base. Un nombre restreint de types
+ peuvent être utilisés :
+ <literal>string</literal>, <literal>character</literal>, <literal>integer</literal>,
+ <literal>byte</literal>, <literal>short</literal>, <literal>boolean</literal>,
+ <literal>yes_no</literal>, <literal>true_false</literal>.
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="discriminator1" coords="2 60"/>
+ <area id="discriminator2" coords="3 60"/>
+ <area id="discriminator3" coords="4 60"/>
+ <area id="discriminator4" coords="5 60"/>
+ <area id="discriminator5" coords="6 60"/>
+ </areaspec>
+ <programlisting><![CDATA[<discriminator
+ column="discriminator_column"
+ type="discriminator_type"
+ force="true|false"
+ insert="true|false"
+ formula="arbitrary sql expression"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="discriminator1">
+ <para>
+ <literal>column</literal> (optionnel - par défaut à <literal>class</literal>) le
+ nom de la colonne discriminante.
+ </para>
+ </callout>
+ <callout arearefs="discriminator2">
+ <para>
+ <literal>type</literal> (optionnel - par défaut à <literal>string</literal>) un nom
+ indiquant le type Hibernate.
+ </para>
+ </callout>
+ <callout arearefs="discriminator3">
+ <para>
+ <literal>force</literal> (optionnel - par défaut à <literal>false</literal>)
+ "oblige" Hibernate à spécifier une valeur discriminante autorisée même quand on récupère
+ toutes les instances de la classe de base.
+ </para>
+ </callout>
+ <callout arearefs="discriminator4">
+ <para>
+ <literal>insert</literal> (optionnel - par défaut à <literal>true</literal>)
+ à passer à <literal>false</literal> si la colonne discriminante fait aussi partie
+ d'un identifiant composé mappé (Indique à Hibernate de ne pas inclure la colonne
+ dans les <literal>INSERT</literal> SQL).
+ </para>
+ </callout>
+ <callout arearefs="discriminator5">
+ <para>
+ <literal>formula</literal> (optionnel) une expression SQL arbitraire qui est exécutée
+ quand un type doit être évalué. Permet la discrimination basée sur le contenu.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Les véritables valeurs de la colonne discriminante sont spécifiées par l'attribut
+ <literal>discriminator-value</literal> des éléments <literal><class></literal> et
+ <literal><subclass></literal>.
+ </para>
+ <para>
+ L'attribut <literal>force</literal> n'est utile que si la table contient des lignes avec des
+ valeurs "extra" discriminantes qui ne sont pas mappées à une classe persistante. Ce ne sera généralement pas le cas.
+ </para>
+ <para>
+ En utilisant l'attribut <literal>formula</literal> vous pouvez déclarer une expression SQL arbitraire
+ qui sera utilisée pour évaluer le type d'une ligne :
+ </para>
+ <programlisting><![CDATA[<discriminator
+ formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
+ type="integer"/>]]></programlisting>
+ </sect2>
+ <sect2 id="mapping-declaration-version" revision="4">
+ <title>version (optionnel)</title>
+ <para>
+ L'élément <literal><version></literal> est optionnel et indique que la table contient
+ des données versionnées. C'est particulièrement utile si vous avez l'intention d'utiliser
+ des <emphasis>transactions longues</emphasis> (voir plus-bas).
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="version1" coords="2 60"/>
+ <area id="version2" coords="3 60"/>
+ <area id="version3" coords="4 60"/>
+ <area id="version4" coords="5 60"/>
+ <area id="version5" coords="6 60"/>
+ <area id="version6" coords="7 70"/>
+ <area id="version7" coords="8 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<version
+ column="version_column"
+ name="propertyName"
+ type="typename"
+ access="field|property|ClassName"
+ unsaved-value="null|negative|undefined"
+ generated="never|always"
+ insert="true|false"
+ node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="version1">
+ <para>
+ <literal>column</literal> (optionnel - par défaut égal au nom de la propriété) : Le nom de la colonne
+ contenant le numéro de version.
+ </para>
+ </callout>
+ <callout arearefs="version2">
+ <para>
+ <literal>name</literal> : Le nom d'un attribut de la classe persistante.
+ </para>
+ </callout>
+ <callout arearefs="version3">
+ <para>
+ <literal>type</literal> (optionnel - par défaut à <literal>integer</literal>) :
+ Le type du numéro de version.
+ </para>
+ </callout>
+ <callout arearefs="version4">
+ <para>
+ <literal>access</literal> (optionnel - par défaut à <literal>property</literal>) : La stratégie
+ à utiliser par Hibernate pour accéder à la valeur de la propriété.
+ </para>
+ </callout>
+ <callout arearefs="version5">
+ <para>
+ <literal>unsaved-value</literal> (optionnel - par défaut à <literal>undefined</literal>) :
+ Une valeur de la propriété d'identifiant qui indique que l'instance est nouvellement
+ instanciée (non sauvegardée), et qui la distingue des instances détachées qui ont
+ été sauvegardées ou chargées dans une session précédente (<literal>undefined</literal> indique
+ que la valeur de l'atribut identifiant devrait être utilisé).
+ </para>
+ </callout>
+ <callout arearefs="version6">
+ <para>
+ <literal>generated</literal> (optional - défaut à <literal>never</literal>) :
+ Indique que la valeur de la propriété version est générée par la base de données
+ cf. <xref linkend="mapping-generated">generated properties</xref>.
+ </para>
+ </callout>
+ <callout arearefs="version7">
+ <para>
+ <literal>insert</literal> (optionnel - défaut à <literal>true</literal>) :
+ Indique si la colonne de version doit être incluse dans les ordres insert.
+ Peut être à <literal>false</literal> si et seulement si la colonne de la
+ base de données est définie avec une valeur par défaut à <literal>0</literal>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Les numéros de version doivent avoir les types Hibernate <literal>long</literal>, <literal>integer</literal>,
+ <literal>short</literal>, <literal>timestamp</literal> ou <literal>calendar</literal>.
+ </para>
+ <para>
+ Une propriété de version ou un timestamp ne doit jamais être null pour une instance
+ détachée, ainsi Hibernate pourra détecter toute instance ayant une version ou un timestamp null
+ comme transient, quelles que soient les stratégies <literal>unsaved-value</literal> spécifiées.
+ <emphasis>Déclarer un numéro de version ou un timestamp "nullable" est un moyen pratique d'éviter
+ tout problème avec les réattachements transitifs dans Hibernate, particulièrement utile pour ceux qui
+ utilisent des identifiants assignés ou des clefs composées !</emphasis>
+ </para>
+ </sect2>
+ <sect2 id="mapping-declaration-timestamp" revision="3" >
+ <title>timestamp (optionnel)</title>
+ <para>
+ L'élément optionnel <literal><timestamp></literal> indique que la table contient des données
+ horodatées (timestamp). Cela sert d'alternative à l'utilisation de numéros de version. Les timestamps (ou horodatage)
+ sont par nature une implémentation moins fiable pour l'optimistic locking. Cependant, l'application
+ peut parfois utiliser l'horodatage à d'autres fins.
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="timestamp1" coords="2 45"/>
+ <area id="timestamp2" coords="3 45"/>
+ <area id="timestamp3" coords="4 45"/>
+ <area id="timestamp4" coords="5 45"/>
+ <area id="timestamp5" coords="6 70" />
+ <area id="timestamp6" coords="7 70" />
+ </areaspec>
+ <programlisting><![CDATA[<timestamp
+ column="timestamp_column"
+ name="propertyName"
+ access="field|property|ClassName"
+ unsaved-value="null|undefined"
+ source="vm|db"
+ generated="never|always"
+ node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="timestamp1">
+ <para>
+ <literal>column</literal> (optionnel - par défaut à le nom de la propriété) : Le nom d'une colonne
+ contenant le timestamp.
+ </para>
+ </callout>
+ <callout arearefs="timestamp2">
+ <para>
+ <literal>name</literal> : Le nom d'une propriété au sens JavaBean de type
+ <literal>Date</literal> ou <literal>Timestamp</literal> de la classe persistante.
+ </para>
+ </callout>
+ <callout arearefs="timestamp3">
+ <para>
+ <literal>access</literal> (optionnel - par défaut à <literal>property</literal>) : La stratégie
+ à utiliser par Hibernate pour accéder à la valeur de la propriété.
+ </para>
+ </callout>
+ <callout arearefs="timestamp4">
+ <para>
+ <literal>unsaved-value</literal> (optionnel - par défaut à <literal>null</literal>) :
+ Propriété dont la valeur est un numéro de version qui indique que l'instance est nouvellement
+ instanciée (non sauvegardée), et qui la distingue des instances détachées qui ont
+ été sauvegardées ou chargées dans une session précédente (<literal>undefined</literal> indique
+ que la valeur de l'attribut identifiant devrait être utilisée).
+ </para>
+ </callout>
+ <callout arearefs="timestamp5">
+ <para>
+ <literal>source</literal> (optionnel - par défaut à <literal>vm</literal>) :
+ D'où Hibernate doit-il récupérer la valeur du timestamp? Depuis la base de données
+ ou depuis la JVM d'exécution? Les valeurs de timestamp de la base de données provoquent
+ une surcharge puisque Hibernate doit interroger la base pour déterminer la prochaine valeur
+ mais cela est plus sûr lorsque vous fonctionnez dans un cluster. Remarquez aussi que
+ certains des dialectes ne supportent pas cette fonction, et que d'autres l'implémentent
+ mal, provoquant des erreurs de précision (Oracle 8 par exemple).
+ </para>
+ </callout>
+ <callout arearefs="timestamp6">
+ <para>
+ <literal>generated</literal> (optional - défaut à <literal>never</literal>) :
+ Indique que la valeur de ce timestamp est générée par la base de données
+ cf. <xref linkend="mapping-generated">generated properties</xref>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Notez que <literal><timestamp></literal> est équivalent à
+ <literal><version type="timestamp"></literal>.
+ </para>
+ </sect2>
+ <sect2 id="mapping-declaration-property" revision="4">
+ <title>property</title>
+ <para>
+ L'élément <literal><property></literal> déclare une propriété de la classe au sens JavaBean.
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="property1" coords="2 45"/>
+ <area id="property2" coords="3 45"/>
+ <area id="property3" coords="4 45"/>
+ <areaset id="property4-5" coords="">
+ <area id="property4" coords="5 45"/>
+ <area id="property5" coords="6 45"/>
+ </areaset>
+ <area id="property6" coords="7 45"/>
+ <area id="property7" coords="8 45"/>
+ <area id="property8" coords="9 45"/>
+ <area id="property9" coords="10 45"/>
+ <area id="property10" coords="11 45"/>
+ <area id="property11" coords="12 45"/>
+ <area id="property12" coords="13 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<property
+ name="propertyName"
+ column="column_name"
+ type="typename"
+ update="true|false"
+ insert="true|false"
+ formula="arbitrary SQL expression"
+ access="field|property|ClassName"
+ lazy="true|false"
+ unique="true|false"
+ not-null="true|false"
+ optimistic-lock="true|false"
+ generated="never|insert|always"
+ node="element-name|@attribute-name|element/@attribute|."
+ index="index_name"
+ unique_key="unique_key_id"
+ length="L"
+ precision="P"
+ scale="S"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="property1">
+ <para>
+ <literal>name</literal> : nom de la propriété, avec une lettre initiale en minuscule.
+ </para>
+ </callout>
+ <callout arearefs="property2">
+ <para>
+ <literal>column</literal> (optionnel - par défaut au nom de la propriété) : le nom
+ de la colonne mappée. Cela peut aussi être indiqué dans le(s) sous-élément(s)
+ <literal><column></literal>.
+ </para>
+ </callout>
+ <callout arearefs="property3">
+ <para>
+ <literal>type</literal> (optionnel) : nom indiquant le type Hibernate.
+ </para>
+ </callout>
+ <callout arearefs="property4-5">
+ <para>
+ <literal>update, insert</literal> (optionnel - par défaut à <literal>true</literal>) :
+ indique que les colonnes mappées devraient être incluses dans des <literal>UPDATE</literal> SQL
+ et/ou des <literal>INSERT</literal>. Mettre les deux à <literal>false</literal>
+ empêche la propagation en base de données (utile si vous savez qu'un trigger affectera la valeur à la colonne).
+ </para>
+ </callout>
+ <callout arearefs="property6">
+ <para>
+ <literal>formula</literal> (optionnel) : une expression SQL qui définit la valeur pour une propriété
+ <emphasis>calculée</emphasis>. Les propriétés calculées ne possède pas leur propre mapping.
+ </para>
+ </callout>
+ <callout arearefs="property7">
+ <para>
+ <literal>access</literal> (optionnel - par défaut à <literal>property</literal>): Stratégie que Hibernate
+ doit utiliser pour accéder à cette valeur.
+ </para>
+ </callout>
+ <callout arearefs="property8">
+ <para>
+ <literal>lazy</literal> (optionnel - par défaut à <literal>false</literal>): Indique
+ que cette propriété devrait être chargée en différé (lazy loading) quand on accède à la variable
+ d'instance pour la première fois.
+ </para>
+ </callout>
+ <callout arearefs="property9">
+ <para>
+ <literal>unique</literal> (optionnel): Génère le DDL d'une contrainte d'unicité pour les colonnes.
+ Permet aussi d'en faire la cible d'un <literal>property-ref</literal>.
+ </para>
+ </callout>
+ <callout arearefs="property10">
+ <para>
+ <literal>not-null</literal> (optionnel): Génère le DDL d'une contrainte de non nullité pour les colonnes.
+ </para>
+ </callout>
+ <callout arearefs="property11">
+ <para>
+ <literal>optimistic-lock</literal> (optionnel - par défaut à <literal>true</literal>):
+ Indique que les mises à jour de cette propriété peuvent ou non nécessiter l'acquisition
+ d'un verrou optimiste. En d'autres termes, cela détermine s'il est nécessaire d'incrémenter
+ un numéro de version quand cette propriété est marquée obsolète (dirty).
+ </para>
+ </callout>
+ <callout arearefs="property12">
+ <para>
+ <literal>generated</literal> (optional - défaut à<literal>never</literal>):
+ Indique que la valeur de ce timestamp est générée par la base de données
+ cf. <xref linkend="mapping-generated">generated properties</xref>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ <emphasis>typename</emphasis> peut être:
+ </para>
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ Nom d'un type basique Hibernate (ex: <literal>integer, string, character,
+ date, timestamp, float, binary, serializable, object, blob</literal>).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Nom d'une classe Java avec un type basique par défaut (ex: <literal>int, float,
+ char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob</literal>).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Nom d'une classe Java sérialisable.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Nom d'une classe ayant un type spécifique (ex: <literal>com.illflow.type.MyCustomType</literal>).
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ Si vous n'indiquez pas un type, Hibernate utlisera la réflexion sur le nom de la propriété
+ pour tenter de trouver le type Hibernate correct. Hibernate essayera d'interprêter
+ le nom de la classe retournée par le getter de la propriété en utilisant les régles 2, 3,
+ 4 dans cet ordre. Cependant, ce n'est pas toujours suffisant. Dans certains cas vous aurez
+ encore besoin de l'attribut <literal>type</literal> (Par exemple, pour distinguer
+ <literal>Hibernate.DATE</literal> et <literal>Hibernate.TIMESTAMP</literal>, ou pour préciser
+ un type spécifique).
+ </para>
+ <para>
+ L'attribut <literal>access</literal> permet de contrôler comment Hibernate accèdera
+ à la propriété à l'exécution. Par défaut, Hibernate utilisera les méthodes set/get.
+ Si vous indiquez <literal>access="field"</literal>, Hibernate ignorera les getter/setter
+ et accèdera à la propriété directement en utilisant la réflexion. Vous pouvez spécifier
+ votre propre stratégie d'accès aux propriété en donnant une classe qui implémente l'interface
+ <literal>org.hibernate.property.PropertyAccessor</literal>.
+ </para>
+ <para>
+ Une fonctionnalité particulièrement intéressante est les propriétés dérivées.
+ Ces propriétés sont par définition en lecture seule, la valeur de la propriété est calculée au chargement.
+ Le calcul est déclaré comme une expression SQL, qui se traduit par une sous-requête <literal>SELECT</literal>
+ dans la requête SQL qui charge une instance :
+ </para>
+ <programlisting><![CDATA[
+<property name="totalPrice"
+ formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p
+ WHERE li.productId = p.productId
+ AND li.customerId = customerId
+ AND li.orderNumber = orderNumber )"/>]]></programlisting>
+ <para>
+ Remarquez que vous pouvez référencer la propre table des entités en ne déclarant pas un
+ alias sur une colonne particulière (<literal>customerId</literal> dans l'exemple donné).
+ Notez aussi que vous pouvez utiliser le sous-élément de mapping <literal><formula></literal>
+ plutôt que d'utiliser l'attribut si vous le souhaitez.
+ </para>
+ </sect2>
+ <sect2 id="mapping-declaration-manytoone" revision="5">
+ <title>many-to-one</title>
+ <para> Une association ordinaire vers une autre classe persistante est déclarée en utilisant
+ un élément <literal>many-to-one</literal>. Le modèle relationnel est une association
+ de type many-to-one : une clef étrangère dans une table référence la ou les clef(s) primaire(s) dans la table cible.
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="manytoone1" coords="2 60"/>
+ <area id="manytoone2" coords="3 60"/>
+ <area id="manytoone3" coords="4 60"/>
+ <area id="manytoone4" coords="5 60"/>
+ <area id="manytoone5" coords="6 60"/>
+ <areaset id="manytoone6-7" coords="">
+ <area id="manytoone6" coords="7 60"/>
+ <area id="manytoone7" coords="8 60"/>
+ </areaset>
+ <area id="manytoone8" coords="9 60"/>
+ <area id="manytoone9" coords="10 60"/>
+ <area id="manytoone10" coords="11 60"/>
+ <area id="manytoone11" coords="12 60"/>
+ <area id="manytoone12" coords="13 60"/>
+ <area id="manytoone13" coords="14 60"/>
+ <area id="manytoone14" coords="15 60"/>
+ <area id="manytoone14" coords="15 70"/>
+ <area id="manytoone15" coords="16 70"/>
+ <area id="manytoone16" coords="17 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<many-to-one
+ name="propertyName"
+ column="column_name"
+ class="ClassName"
+ cascade="cascade_style"
+ fetch="join|select"
+ update="true|false"
+ insert="true|false"
+ property-ref="propertyNameFromAssociatedClass"
+ access="field|property|ClassName"
+ unique="true|false"
+ not-null="true|false"
+ optimistic-lock="true|false"
+ lazy="proxy|no-proxy|false"
+ not-found="ignore|exception"
+ entity-name="EntityName"
+ formula="arbitrary SQL expression"
+ node="element-name|@attribute-name|element/@attribute|."
+ embed-xml="true|false"
+ index="index_name"
+ unique_key="unique_key_id"
+ foreign-key="foreign_key_name"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="manytoone1">
+ <para>
+ <literal>name</literal> : Nom de la propriété.
+ </para>
+ </callout>
+ <callout arearefs="manytoone2">
+ <para>
+ <literal>column</literal> (optionnel) : Le nom de la clef étrangère. Cela peut être
+ aussi indiqué avec le sous-élément <literal><column></literal>.
+ </para>
+ </callout>
+ <callout arearefs="manytoone3">
+ <para>
+ <literal>class</literal> (optionnel - par défaut le type de la propriété déterminé
+ par réflexion) : Le nom de la classe associée.
+ </para>
+ </callout>
+ <callout arearefs="manytoone4">
+ <para>
+ <literal>cascade</literal> (optionnel) : Indique quelles opérations doivent
+ être propagées de l'objet père vers les objets associés.
+ </para>
+ </callout>
+ <callout arearefs="manytoone5">
+ <para>
+ <literal>fetch</literal> (optionnel - par défaut à <literal>select</literal>) :
+ Choisit entre le chargement de type outer-join ou le chargement par select successifs.
+ </para>
+ </callout>
+ <callout arearefs="manytoone6-7">
+ <para>
+ <literal>update, insert</literal> (optionnel - par défaut à <literal>true</literal>) :
+ indique que les colonnes mappées devraient être incluses dans des <literal>UPDATE</literal> SQL
+ et/ou des <literal>INSERT</literal>. Mettre les deux à <literal>false</literal>
+ empêche la propagation en base de données (utile si vous savez qu'un trigger affectera la valeur à la colonne).
+ </para>
+ </callout>
+ <callout arearefs="manytoone8">
+ <para>
+ <literal>property-ref</literal> : (optionnel) Le nom d'une propriété de la classe
+ associée qui est liée à cette clef étrangère. Si ce n'est pas spécifié, la clef primaire de la
+ classe associée est utilisée.
+ </para>
+ </callout>
+ <callout arearefs="manytoone9">
+ <para>
+ <literal>access</literal> (optionnel - par défaut à <literal>property</literal>) : La
+ stratégie à utiliser par Hibernate pour accéder à la valeur de cette propriété.
+ </para>
+ </callout>
+ <callout arearefs="manytoone10">
+ <para>
+ <literal>unique</literal> (optionnel) : Génère le DDL d'une contrainte d'unicité pour la clef étrangère.
+ Permet aussi d'en faire la cible d'un <literal>property-ref</literal>. Cela permet de créer une véritable
+ association one-to-one.
+ </para>
+ </callout>
+ <callout arearefs="manytoone11">
+ <para>
+ <literal>not-null</literal> (optionnel) : Génère le DDL pour une contrainte de non nullité pour la clef étrangère.
+ </para>
+ </callout>
+ <callout arearefs="manytoone12">
+ <para>
+ <literal>optimistic-lock</literal> (optionnel - par défaut à <literal>true</literal>) :
+ Indique que les mises à jour de cette propriété requièrent ou non l'acquisition
+ d'un verrou optimiste. En d'autres termes, détermine si un incrément de version doit
+ avoir lieu quand la propriété est marquée obsolète (dirty).
+ </para>
+ </callout>
+ <callout arearefs="manytoone13">
+ <para>
+ <literal>lazy</literal> (optionnel - par défaut à <literal>false</literal>) : Indique
+ que cette propriété doit être chargée en différé (lazy loading) au premier accès
+ à la variable d'instance (nécessite une instrumentation du bytecode lors de la phase
+ de construction). Remarquez que cela n'influence pas le comportement du proxy
+ Hibernate - comme l'attribut <literal>lazy</literal> sur des classes ou des mappings
+ de collections, mais utilise l'interception pour le chargement différé.
+ <literal>lazy="false"</literal> indique que l'association sera toujours chargée.
+ </para>
+ </callout>
+ <callout arearefs="manytoone14">
+ <para>
+ <literal>not-found</literal> (optionnel - par défaut à <literal>exception</literal>) :
+ Indique comment les clefs étrangères qui référencent des lignes manquantes doivent être manipulées :
+ <literal>ignore</literal> traitera une ligne manquante comme une association nulle.
+ </para>
+ </callout>
+ <callout arearefs="manytoone15">
+ <para>
+ <literal>entity-name</literal> (optionnel) : Le nom de l'entité de la classe associée.
+ </para>
+ </callout>
+ <callout arearefs="manytoone16">
+ <para>
+ <literal>formula</literal> (optionnel) : une expression SQL qui définit la valeur
+ pour une clé étrangère calculée.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Donner une valeur significative à l'attribut <literal>cascade</literal> autre que
+ <literal>none</literal> propagera certaines opérations à l'objet associé. Les valeurs
+ significatives sont les noms des opérations Hibernate basiques,
+ <literal>persist, merge, delete, save-update, evict, replicate, lock,
+ refresh</literal>, ainsi que les valeurs spéciales <literal>delete-orphan</literal>
+ et <literal>all</literal> et des combinaisons de noms d'opérations séparées par des virgules,
+ comme par exemple <literal>cascade="persist,merge,evict"</literal> ou
+ <literal>cascade="all,delete-orphan"</literal>. Voir <xref linkend="objectstate-transitive"/>
+ pour une explication complète.
+ Notez que les assocations many-to-one et one-to-one ne supportent pas orphan delete.
+ </para>
+
+ <para>
+ Une déclaration <literal>many-to-one</literal> typique est aussi simple que :
+ </para>
+ <programlisting><![CDATA[<many-to-one name="product" class="Product" column="PRODUCT_ID"/>]]></programlisting>
+ <para>
+ L'attribut <literal>property-ref</literal> devrait être utilisé pour mapper seulement des données
+ provenant d'un ancien système où les clefs étrangères font référence à une clef unique de la table associée
+ et qui n'est pas la clef primaire. C'est un cas de mauvaise conception relationnelle.
+ Par exemple, supposez que la classe <literal>Product</literal> a un numéro de série unique qui n'est pas
+ la clef primaire. (L'attribut <literal>unique</literal> contrôle la génération DDL par Hibernate avec
+ l'outil SchemaExport.)
+ </para>
+ <programlisting><![CDATA[<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>]]></programlisting>
+ <para>
+ Ainsi le mapping pour <literal>OrderItem</literal> peut utiliser :
+ </para>
+ <programlisting><![CDATA[<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>]]></programlisting>
+ <para>
+ bien que ce ne soit certainement pas encouragé.
+ </para>
+ <para>
+ Si la clef unique référencée comprend des propriétés multiples de l'entité associée, vous devez mapper
+ ces propriétés à l'intérieur d'un élément <literal><properties></literal>.
+ </para>
+ </sect2>
+ <sect2 id="mapping-declaration-onetoone" revision="3">
+ <title>one-to-one</title>
+ <para>
+ Une association one-to-one vers une autre classe persistante est déclarée avec l'élément
+ <literal>one-to-one</literal>.
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="onetoone1" coords="2 60"/>
+ <area id="onetoone2" coords="3 60"/>
+ <area id="onetoone3" coords="4 60"/>
+ <area id="onetoone4" coords="5 60"/>
+ <area id="onetoone5" coords="6 60"/>
+ <area id="onetoone6" coords="7 60"/>
+ <area id="onetoone7" coords="8 60"/>
+ <area id="onetoone8" coords="9 60"/>
+ <area id="onetoone9" coords="10 70"/>
+ <area id="onetoone10" coords="11 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<one-to-one
+ name="propertyName"
+ class="ClassName"
+ cascade="cascade_style"
+ constrained="true|false"
+ fetch="join|select"
+ property-ref="propertyNameFromAssociatedClass"
+ access="field|property|ClassName"
+ formula="any SQL expression"
+ entity-name="EntityName"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="onetoone1">
+ <para>
+ <literal>name</literal> : Le nom de la propriété.
+ </para>
+ </callout>
+ <callout arearefs="onetoone2">
+ <para>
+ <literal>class</literal> (optionnel - par défaut du type de la propriété
+ déterminé par réflexion) : Le nom de la classe associée.
+ </para>
+ </callout>
+ <callout arearefs="onetoone3">
+ <para>
+ <literal>cascade</literal> (optionnel) : Indique quelles opérations doivent
+ être cascadées de l'objet père vers l'objet associé.
+ </para>
+ </callout>
+ <callout arearefs="onetoone4">
+ <para>
+ <literal>constrained</literal> (optionnel) : Indique qu'une contrainte de clef étrangère
+ sur la clef primaire de la table mappée référence la table de la classe associée.
+ Cette option affecte l'ordre dans lequel chaque <literal>save()</literal> et chaque
+ <literal>delete()</literal> sont cascadés et détermine si l'association peut utiliser un proxy
+ (aussi utilisé par l'outil d'export de schéma).
+ </para>
+ </callout>
+ <callout arearefs="onetoone5">
+ <para>
+ <literal>fetch</literal> (optionnel - par défaut à <literal>select</literal>) :
+ Choisit entre récupération par jointure externe ou select séquentiel.
+ </para>
+ </callout>
+ <callout arearefs="onetoone6">
+ <para>
+ <literal>property-ref</literal> (optionnel) : Le nom de la propriété de la classe associée qui est jointe à la clef
+ primaire de cette classe. Si ce n'est pas spécifié, la clef primaire de la classe associée est utilisée.
+ </para>
+ </callout>
+ <callout arearefs="onetoone7">
+ <para>
+ <literal>access</literal> (optionnel - par défaut à <literal>property</literal>) :
+ La stratégie à utiliser par Hibernate pour accéder à la valeur de la propriété.
+ </para>
+ </callout>
+ <callout arearefs="onetoone8">
+ <para>
+ <literal>formula</literal> (optionnel) : Presque toutes les associations one-to-one pointent sur la clef primaire
+ de l'entité propriétaire. Dans les rares cas différents, vous devez donner une ou plusieurs
+ autres colonnes ou expression à joindre par une formule SQL (voir <literal>org.hibernate.test.onetooneformula</literal> pour un exemple).
+ </para>
+ </callout>
+ <callout arearefs="onetoone9">
+ <para>
+ <literal>lazy</literal> (optionnel - par défaut <literal>proxy</literal>) :
+ Par défaut, les associations simples sont soumise à proxy. <literal>lazy="no-proxy"</literal>
+ spécifie que la propriété doit être chargée à la demande au premier accès à l'instance.
+ (nécessite l'intrumentation du bytecode à la construction).
+ <literal>lazy="false"</literal> indique que l'association sera toujours chargée
+ agressivement. <emphasis>Notez que si <literal>constrained="false"</literal>,
+ l'utilisation de proxy est impossible et Hibernate chargera automatiquement l'association !</emphasis>
+ </para>
+ </callout>
+ <callout arearefs="onetoone10">
+ <para>
+ <literal>entity-name</literal> (optional) : The entity name of the associated class.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Il existe deux types d'associations one-to-one :
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ associations par clef primaire
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ association par clef étrangère unique
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Les associations par clef primaire ne nécessitent pas une colonne supplémentaire en table ; si deux lignes sont
+ liés par l'association alors les deux lignes de la table partagent la même valeur de clef primaire. Donc si vous
+ voulez que deux objets soient liés par une association par clef primaire, vous devez faire en sorte qu'on leur
+ assigne la même valeur d'identifiant !
+ </para>
+ <para>
+ Pour une association par clef primaire, ajoutez les mappings suivants à <literal>Employee</literal> et
+ <literal>Person</literal>, respectivement.
+ </para>
+ <programlisting><![CDATA[<one-to-one name="person" class="Person"/>]]></programlisting>
+ <programlisting><![CDATA[<one-to-one name="employee" class="Employee" constrained="true"/>]]></programlisting>
+ <para>
+ Maintenant, vous devez faire en sorte que les clefs primaires des lignes liées dans les tables PERSON et EMPLOYEE
+ sont égales. On utilise une stratégie Hibernate spéciale de génération d'identifiants appelée
+ <literal>foreign</literal> :
+ </para>
+ <programlisting><![CDATA[<class name="person" table="PERSON">
+ <id name="id" column="PERSON_ID">
+ <generator class="foreign">
+ <param name="property">employee</param>
+ </generator>
+ </id>
+ ...
+ <one-to-one name="employee"
+ class="Employee"
+ constrained="true"/>
+</class>]]></programlisting>
+ <para>
+ Une instance fraîchement enregistrée de <literal>Person</literal> se voit alors assignée la même valeur
+ de clef primaire que l'instance de <literal>Employee</literal> référencée par la propriété <literal>employee</literal>
+ de cette <literal>Person</literal>.
+ </para>
+ <para>
+ Alternativement, une clef étrangère avec contrainte d'unicité de <literal>Employee</literal> vers
+ <literal>Person</literal> peut être indiquée ainsi :
+ </para>
+ <programlisting><![CDATA[<many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/>]]></programlisting>
+ <para>
+ Et cette association peut être rendue bidirectionnelle en ajoutant ceci au mapping de <literal>Person</literal> :
+ </para>
+ <programlisting><![CDATA[<one-to-one name"employee" class="Employee" property-ref="person"/>]]></programlisting>
+ </sect2>
+
+ <sect2 id="mapping-declaration-naturalid">
+ <title>natural-id</title>
+
+ <programlisting><![CDATA[<natural-id mutable="true|false"/>
+ <property ... />
+ <many-to-one ... />
+ ......
+</natural-id>]]></programlisting>
+
+ <para>
+ Bien que nous recommandions l'utilisation de clé primaire générée, vous devriez toujours
+ essayer d'identifier des clé métier (naturelles) pour toutes vos entités. Une clé naturelle
+ est une propriété ou une combinaison de propriétés uniques et non nulles. Si elle est aussi
+ immuable, c'est encore mieux. Mappez les propriétés de la clé naturelle dans l'élément
+ <literal><natural-id></literal>. Hibernate générera la clé unique nécessaire et les contraintes
+ de non-nullité, et votre mapping s'auto-documentera.
+ </para>
+
+ <para>
+ Nous vous recommandons fortement d'implémenter <literal>equals()</literal> et
+ <literal>hashCode()</literal> pour comparer les clés naturelles de l'entité.
+ </para>
+
+ <para>
+ Ce mapping n'est pas destiné à être utilisé avec des entités qui ont des clés naturelles.
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>mutable</literal> (optionel, par défaut à <literal>false</literal>) :
+ Par défaut, les identifiants naturels sont supposés être immuable (constants).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect2>
+ <sect2 id="mapping-declaration-component" revision="2">
+ <title>component, dynamic-component</title>
+ <para>
+ L'élément <literal><component></literal> mappe les propriétés d'un objet fils
+ aux colonnes d'une classe parente. Les composants peuvent en retour déclarer leurs propres
+ propriétés, composants ou collections. Voir "Components" plus bas.
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="component1" coords="2 45"/>
+ <area id="component2" coords="3 45"/>
+ <area id="component3" coords="4 45"/>
+ <area id="component4" coords="5 45"/>
+ <area id="component5" coords="6 45"/>
+ <area id="component6" coords="7 45"/>
+ <area id="component7" coords="8 45"/>
+ <area id="component8" coords="9 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<component
+ name="propertyName"
+ class="className"
+ insert="true|false"
+ update="true|false"
+ access="field|property|ClassName"
+ lazy="true|false"
+ optimistic-lock="true|false"
+ unique="true|false"
+>
+
+ <property ...../>
+ <many-to-one .... />
+ ........
+</component>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="component1">
+ <para>
+ <literal>name</literal> : Nom de la propriété
+ </para>
+ </callout>
+ <callout arearefs="component2">
+ <para>
+ <literal>class</literal> (optionnel - par défaut au type de la propriété déterminé par réflexion) :
+ le nom de la classe (fille) du composant.
+ </para>
+ </callout>
+ <callout arearefs="component3">
+ <para>
+ <literal>insert</literal> : Est ce que les colonnes mappées apparaissent dans les
+ <literal>INSERT</literal>s ?
+ </para>
+ </callout>
+ <callout arearefs="component4">
+ <para>
+ <literal>update</literal>: Est ce que les colonnes mappées apparaissent dans les
+ <literal>UPDATE</literal>s ?
+ </para>
+ </callout>
+ <callout arearefs="component5">
+ <para>
+ <literal>access</literal> (optionnel - par défaut à <literal>property</literal>) :
+ La stratégie que Hibernate doit utiliser pour accéder à la valeur de cette propriété.
+ </para>
+ </callout>
+ <callout arearefs="component6">
+ <para>
+ <literal>lazy</literal> (optionnel - par défaut à <literal>false</literal>) :
+ Indique que ce composant doit être chargé au premier accès
+ à la variable d'instance (nécessite une instrumentation du bytecode au moment du build).
+ </para>
+ </callout>
+ <callout arearefs="component7">
+ <para>
+ <literal>optimistic-lock</literal> (optionnel - par défaut à <literal>true</literal>) :
+ Indique que les mises à jour sur ce composant nécessitent ou non l'acquisition d'un
+ verrou optimiste. En d'autres termes, cela détermine si une incrémentation de version
+ doit avoir lieu quand la propriété est marquée obsolète (dirty).
+ </para>
+ </callout>
+ <callout arearefs="component8">
+ <para>
+ <literal>unique</literal> (optionnel - par défaut à <literal>false</literal>) :
+ Indique qu'une contrainte d'unicité existe sur toutes les colonnes mappées de ce composant.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Les tags fils <literal><property></literal> mappent les propriétés
+ de la classe fille sur les colonnes de la table.
+ </para>
+ <para>
+ L'élément <literal><component></literal> permet de déclarer sous-élément <literal><parent></literal> qui associe une propriété
+ de la classe composant comme une référence arrière vers l'entité contenante.
+ </para>
+ <para>
+ L'élément <literal><dynamic-component></literal> permet à une <literal>Map</literal> d'être mappée
+ comme un composant, quand les noms de la propriété font référence aux clefs de cette Map, voir
+ <xref linkend="components-dynamic"/>.
+ </para>
+ </sect2>
+ <sect2 id="mapping-declaration-properties" revision="2">
+ <title>properties</title>
+ <para>
+ L'élément <literal><properties></literal> permet la définition d'un groupement logique nommé
+ des propriétés d'une classe. L'utilisation la plus importante de cette construction est la possibilité
+ pour une combinaison de propriétés d'être la cible d'un <literal>property-ref</literal>. C'est aussi
+ un moyen pratique de définir une contrainte d'unicité multi-colonnes.
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="properties1" coords="2 45"/>
+ <area id="properties2" coords="3 45"/>
+ <area id="properties3" coords="4 45"/>
+ <area id="properties4" coords="5 45"/>
+ <area id="properties5" coords="6 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<properties
+ name="logicalName"
+ insert="true|false"
+ update="true|false"
+ optimistic-lock="true|false"
+ unique="true|false"
+>
+
+ <property ...../>
+ <many-to-one .... />
+ ........
+</properties>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="properties1">
+ <para>
+ <literal>name</literal> : Le nom logique d'un regroupement et
+ <emphasis>non</emphasis> le véritable nom d'une propriété.
+ </para>
+ </callout>
+ <callout arearefs="properties2">
+ <para>
+ <literal>insert</literal> : Est-ce que les colonnes mappées apparaissent dans les
+ <literal>INSERT</literal>s ?
+ </para>
+ </callout>
+ <callout arearefs="properties3">
+ <para>
+ <literal>update</literal> : Est-ce que les colonnes mappées apparaissent dans les
+ <literal>UPDATE</literal>s ?
+ </para>
+ </callout>
+ <callout arearefs="properties4">
+ <para>
+ <literal>optimistic-lock</literal> (optionnel - par défaut à <literal>true</literal>) :
+ Indique que les mises à jour sur ce composant nécessitent ou non l'acquisition d'un
+ verrou optimiste. En d'autres termes, cela détermine si une incrémentation
+ de version doit avoir lieu quand la propriété est marquée obsolète (dirty).
+ </para>
+ </callout>
+ <callout arearefs="properties5">
+ <para>
+ <literal>unique</literal> (optionnel - par défaut à <literal>false</literal>) :
+ Indique qu'une contrainte d'unicité existe sur toutes les colonnes mappées de ce composant.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Par exemple, si nous avons le mapping de <literal><properties></literal> suivant :
+ </para>
+ <programlisting><![CDATA[<class name="Person">
+ <id name="personNumber"/>
+ ...
+ <properties name="name"
+ unique="true" update="false">
+ <property name="firstName"/>
+ <property name="initial"/>
+ <property name="lastName"/>
+ </properties>
+</class>]]></programlisting>
+ <para>
+ Alors nous pourrions avoir une association sur des données d'un ancien système (legacy) qui font référence
+ à cette clef unique de la table <literal>Person</literal> au lieu de la clef primaire :
+ </para>
+ <programlisting><![CDATA[<many-to-one name="person"
+ class="Person" property-ref="name">
+ <column name="firstName"/>
+ <column name="initial"/>
+ <column name="lastName"/>
+</many-to-one>]]></programlisting>
+ <para>
+ Nous ne recommandons pas l'utilisation de ce genre de chose en dehors du contexte de mapping de données héritées
+ d'anciens systèmes.
+ </para>
+ </sect2>
+ <sect2 id="mapping-declaration-subclass" revision="4">
+ <title>subclass</title>
+ <para>
+ Pour finir, la persistance polymorphique nécessite la déclaration de chaque sous-classe de la classe persistante de base.
+ pour la stratégie de mapping de type table-per-class-hierarchy, on utilise la déclaration
+ <literal><subclass></literal>.
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="subclass1" coords="2 55"/>
+ <area id="subclass2" coords="3 55"/>
+ <area id="subclass3" coords="4 55"/>
+ <area id="subclass4" coords="5 55"/>
+ </areaspec>
+ <programlisting><![CDATA[<subclass
+ name="ClassName"
+ discriminator-value="discriminator_value"
+ proxy="ProxyInterface"
+ lazy="true|false"
+ dynamic-update="true|false"
+ dynamic-insert="true|false"
+ entity-name="EntityName"
+ node="element-name"
+ extends="SuperclassName">
+
+ <property .... />
+ .....
+</subclass>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="subclass1">
+ <para>
+ <literal>name</literal> : Le nom complet de la sous-classe.
+ </para>
+ </callout>
+ <callout arearefs="subclass2">
+ <para>
+ <literal>discriminator-value</literal> (optionnel - par défaut le nom de la classe) :
+ une valeur qui distingue les différentes sous-classes.
+ </para>
+ </callout>
+ <callout arearefs="subclass3">
+ <para>
+ <literal>proxy</literal> (optionnel) : Indique une classe ou interface à utiliser pour les chargements
+ à la demande des proxies (lazy).
+ </para>
+ </callout>
+ <callout arearefs="subclass4">
+ <para>
+ <literal>lazy</literal> (optionnel, par défaut à <literal>true</literal>) : Spécifier
+ <literal>lazy="false"</literal> désactive l'utilisation du chargement à la demande (lazy).
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Chaque sous-classe devrait déclarer ses propres propriétés persistantes et sous-classes.
+ Les propriétés <literal><version></literal> et <literal><id></literal>
+ sont implicitement hérités de la classe de base. Chaque sous-classe dans une hiérarchie doit
+ définir une unique <literal>discriminator-value</literal>. Si aucune n'est spécifiée,
+ le nom complet de la classe Java est utilisé.
+ </para>
+ <para>
+ Pour plus d'infos sur le mapping d'héritage, voir <xref linkend="inheritance"/>.
+ </para>
+ <programlisting><![CDATA[
+<hibernate-mapping>
+ <subclass name="DomesticCat" extends="Cat" discriminator-value="D">
+ <property name="name" type="string"/>
+ </subclass>
+</hibernate-mapping>]]></programlisting>
+ <para>
+ Pour des informations sur les mappings d'héritage, voir <xref linkend="inheritance"/>.
+ </para>
+ </sect2>
+ <sect2 id="mapping-declaration-joinedsubclass" revision="3">
+ <title>joined-subclass</title>
+ <para>
+ Une autre façon possible de faire est la suivante, chaque sous-classe peut être mappée vers sa propre table (stratégie
+ de mapping de type table-per-subclass). L'état hérité est récupéré en joignant la table de la super-classe.
+ L'élément <literal><joined-subclass></literal> est utilisé.
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="joinedsubclass1" coords="2 45"/>
+ <area id="joinedsubclass2" coords="3 45"/>
+ <area id="joinedsubclass3" coords="4 45"/>
+ <area id="joinedsubclass4" coords="5 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<joined-subclass
+ name="ClassName"
+ table="tablename"
+ proxy="ProxyInterface"
+ lazy="true|false"
+ dynamic-update="true|false"
+ dynamic-insert="true|false"
+ schema="schema"
+ catalog="catalog"
+ extends="SuperclassName"
+ persister="ClassName"
+ subselect="SQL expression"
+ entity-name="EntityName">
+
+ <key .... >
+
+ <property .... />
+ .....
+</joined-subclass>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="joinedsubclass1">
+ <para>
+ <literal>name</literal> : Le nom Java complet de la sous-classe.
+ </para>
+ </callout>
+ <callout arearefs="joinedsubclass2">
+ <para>
+ <literal>table</literal> : Le nom de la table de la sous-classe.
+ </para>
+ </callout>
+ <callout arearefs="joinedsubclass3">
+ <para>
+ <literal>proxy</literal> (optionnel) : Indique une classe ou interface pour le chargement différé des proxies.
+ </para>
+ </callout>
+ <callout arearefs="joinedsubclass4">
+ <para>
+ <literal>lazy</literal> (optionnel, par défaut à <literal>true</literal>) : Indiquer
+ <literal>lazy="false"</literal> désactive l'utilisation du chargement à la demande.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Aucune colonne discriminante n'est nécessaire pour cette stratégie de mapping. Cependant,
+ chaque sous-classe doit déclarer une colonne de table contenant l'objet identifiant qui utilise l'élément
+ <literal><key></literal>. Le mapping au début de ce chapitre serait ré-écrit ainsi :
+ </para>
+ <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+ <class name="Cat" table="CATS">
+ <id name="id" column="uid" type="long">
+ <generator class="hilo"/>
+ </id>
+ <property name="birthdate" type="date"/>
+ <property name="color" not-null="true"/>
+ <property name="sex" not-null="true"/>
+ <property name="weight"/>
+ <many-to-one name="mate"/>
+ <set name="kittens">
+ <key column="MOTHER"/>
+ <one-to-many class="Cat"/>
+ </set>
+ <joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
+ <key column="CAT"/>
+ <property name="name" type="string"/>
+ </joined-subclass>
+ </class>
+
+ <class name="eg.Dog">
+ <!-- mapping for Dog could go here -->
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+ <para>
+ Pour des informations sur les mappings d'héritage, voir <xref linkend="inheritance"/>.
+ </para>
+ </sect2>
+ <sect2 id="mapping-declaration-unionsubclass" revision="2">
+ <title>union-subclass</title>
+ <para>
+ Une troisième option est de seulement mapper vers des tables les classes concrètes
+ d'une hiérarchie d'héritage, (stratégie de type table-per-concrete-class) où
+ chaque table définit tous les états persistants de la classe, y compris les états hérités.
+ Dans Hibernate il n'est absolument pas nécessaire de mapper explicitement de telles hiérarchies
+ d'héritage. Vous pouvez simplement mapper chaque classe avec une déclaration <literal><class></literal>
+ différente. Cependant, si vous souhaitez utiliser des associations polymorphiques (càd une association
+ vers la superclasse de la hiérarchie), vous devez utiliser le mapping <literal><union-subclass></literal>.
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="unionsubclass1" coords="2 45"/>
+ <area id="unionsubclass2" coords="3 45"/>
+ <area id="unionsubclass3" coords="4 45"/>
+ <area id="unionsubclass4" coords="5 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<union-subclass
+ name="ClassName"
+ table="tablename"
+ proxy="ProxyInterface"
+ lazy="true|false"
+ dynamic-update="true|false"
+ dynamic-insert="true|false"
+ schema="schema"
+ catalog="catalog"
+ extends="SuperclassName"
+ abstract="true|false"
+ persister="ClassName"
+ subselect="SQL expression"
+ entity-name="EntityName">
+
+ <property .... />
+ .....
+</union-subclass>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="unionsubclass1">
+ <para>
+ <literal>name</literal> : Le nom Java complet de la sous-classe.
+ </para>
+ </callout>
+ <callout arearefs="unionsubclass2">
+ <para>
+ <literal>table</literal> : nom de la table de la sous-classe.
+ </para>
+ </callout>
+ <callout arearefs="unionsubclass3">
+ <para>
+ <literal>proxy</literal> (optionnel) : Indique une classe ou interface pour le chargement différé des proxies.
+ </para>
+ </callout>
+ <callout arearefs="unionsubclass4">
+ <para>
+ <literal>lazy</literal> (optionnel, par défaut à <literal>true</literal>) : Indiquer
+ <literal>lazy="false"</literal> désactive l'utilisation du chargement à la demande.
+ </para>
+
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Aucune colonne discriminante ou colonne clef n'est requise pour cette stratégie de mapping.
+ </para>
+ <para>
+ Pour des informations sur les mappings d'héritage, voir <xref linkend="inheritance"/>.
+ </para>
+ </sect2>
+ <sect2 id="mapping-declaration-join" revision="3">
+ <title>join</title>
+ <para>
+ En utilisant l'élément <literal><join></literal>, il est possible de mapper
+ des propriétés d'une classe sur plusieurs tables.
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="join1" coords="2 50"/>
+ <area id="join2" coords="3 50"/>
+ <area id="join3" coords="4 50"/>
+ <area id="join4" coords="5 50"/>
+ <area id="join5" coords="6 50"/>
+ <area id="join6" coords="7 50"/>
+ </areaspec>
+ <programlisting><![CDATA[<join
+ table="tablename"
+ schema="owner"
+ catalog="catalog"
+ fetch="join|select"
+ inverse="true|false"
+ optionnel="true|false">
+
+ <key ... />
+
+ <property ... />
+ ...
+</join>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="join1">
+ <para>
+ <literal>table</literal> : Le nom de la table jointe.
+ </para>
+ </callout>
+ <callout arearefs="join2">
+ <para>
+ <literal>schema</literal> (optionnel) : court-circuite le nom de schéma spécifié par l'élément de base
+ <literal><hibernate-mapping></literal>.
+ </para>
+ </callout>
+ <callout arearefs="join3">
+ <para>
+ <literal>catalog</literal> (optionnel) : court-circuite le nom de catalogue spécifié par l'élément de base
+ <literal><hibernate-mapping></literal>.
+ </para>
+ </callout>
+ <callout arearefs="join4">
+ <para>
+ <literal>fetch</literal> (optionnel - par défaut à <literal>join</literal>) :
+ Si positionné à <literal>join</literal>, Hibernate utilisera une jointure interne pour charger
+ une <literal>jointure</literal> définie par une classe ou ses super-classes et une jointure externe
+ pour une <literal><jointure></literal> définie par une sous-classe.
+ Si positionné à <literal>select</literal> alors Hibernate utilisera un select séquentiel
+ pour une <literal><jointure></literal> définie sur une sous-classe, qui ne sera délivrée que
+ si une ligne se représente une instance de la sous-classe. Les jointures internes seront quand même
+ utilisées pour charger une <literal><jointure></literal> définie par une classe et ses super-classes.
+ </para>
+ </callout>
+ <callout arearefs="join5">
+ <para>
+ <literal>inverse</literal> (optionnel - par défaut à <literal>false</literal>) :
+ Si positionné à true, Hibernate n'essaiera pas d'insérer ou de mettre à jour les
+ propriétés définies par cette jointure.
+ </para>
+ </callout>
+ <callout arearefs="join6">
+ <para>
+ <literal>optionnel</literal> (optionnel - par défaut à <literal>false</literal>) :
+ Si positionné à true, Hibernate insèrera une ligne seulement si les propriétés définies
+ par cette jointure sont non-nulles et utilisera toujours une jointure externe pour charger les propriétés.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Par exemple, les informations d'adresse pour une personne peuvent être mappées vers une table
+ séparée (tout en préservant des sémantiques de type valeur pour toutes ses propriétés) :
+ </para>
+ <programlisting><![CDATA[<class name="Person"
+ table="PERSON">
+
+ <id name="id" column="PERSON_ID">...</id>
+
+ <join table="ADDRESS">
+ <key column="ADDRESS_ID"/>
+ <property name="address"/>
+ <property name="zip"/>
+ <property name="country"/>
+ </join>
+ ...]]></programlisting>
+ <para>
+ Cette fonctionnalité est souvent seulement utile pour les modèles de données
+ hérités d'anciens systèmes (legacy), nous recommandons d'utiliser moins de tables que de classes
+ et un modèle de domaine à granularité fine. Cependant, c'est utile
+ pour passer d'une stratégie de mapping d'héritage à une autre dans une hiérarchie simple ainsi qu'il est
+ expliqué plus tard.
+ </para>
+ </sect2>
+ <sect2 id="mapping-declaration-key">
+ <title>key</title>
+ <para>
+ Nous avons rencontré l'élément <literal><key></literal> à plusieurs reprises maintenant.
+ Il apparaît partout que l'élément de mapping parent définit une jointure sur une nouvele table, et
+ définit la clef étrangère dans la table jointe, ce qui référence la clef primaire de la table d'origine.
+ </para>
+ <programlistingco>
+ <areaspec>
+ <area id="key1" coords="2 50"/>
+ <area id="key2" coords="3 50"/>
+ <area id="key3" coords="4 50"/>
+ <area id="key4" coords="5 50"/>
+ <area id="key5" coords="6 50"/>
+ <area id="key6" coords="7 50"/>
+ </areaspec>
+ <programlisting><![CDATA[<key
+ column="columnname"
+ on-delete="noaction|cascade"
+ property-ref="propertyName"
+ not-null="true|false"
+ update="true|false"
+ unique="true|false"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="key1">
+ <para>
+ <literal>column</literal> (optionnel) : Le nom de la colonne de la clef étrangère
+ Cela peut aussi être spécifié par l'élément(s) intégré(s) <literal><column></literal>.
+ </para>
+ </callout>
+ <callout arearefs="key2">
+ <para>
+ <literal>on-delete</literal> (optionnel, par défaut à <literal>noaction</literal>) :
+ Indique si la contrainte de clef étrangère possède la possibilité au niveau base de données
+ de suppression en cascade.
+ </para>
+ </callout>
+ <callout arearefs="key3">
+ <para>
+ <literal>property-ref</literal> (optionnel) : Indique que la clef étrangère fait
+ référence à des colonnes qui ne sont pas la clef primaire de la table d'origine
+ (Pour les données de systèmes legacy).
+ </para>
+ </callout>
+ <callout arearefs="key4">
+ <para>
+ <literal>not-null</literal> (optionnel) : Indique que les colonnes des clefs étrangères ne
+ peuvent pas être nulles (c'est implicite si la clef étrangère fait partie de la clef primaire).
+ </para>
+ </callout>
+ <callout arearefs="key5">
+ <para>
+ <literal>update</literal> (optionnel) : Indique que la clef étrangère ne devrait jamais être mise à jour
+ (implicite si celle-ci fait partie de la clef primaire).
+ </para>
+ </callout>
+ <callout arearefs="key6">
+ <para>
+ <literal>unique</literal> (optionnel) : Indique que la clef étrangère doit posséder une contrainte
+ d'unicité (implicite si la clef étrangère est aussi la clef primaire).
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Nous recommandons pour les systèmes où les suppressions doivent être performantes de définir toutes
+ les clefs <literal>on-delete="cascade"</literal>, ainsi Hibernate utilisera une contrainte
+ <literal>ON CASCADE DELETE</literal> au niveau base de données, plutôt que de nombreux
+ <literal>DELETE</literal> individuels. Attention, cette fonctionnalité court-circuite la stratégie
+ habituelle de verrou optimiste pour les données versionnées.
+ </para>
+ <para>
+ Les attributs <literal>not-null</literal> et <literal>update</literal> sont utiles pour
+ mapper une association one-to-many unidirectionnelle. Si vous mappez un one-to-many unidirectionnel
+ vers une clef étrangère non nulle, vous <emphasis>devez</emphasis> déclarer la colonne de la clef
+ en utilisant <literal><key not-null="true"></literal>.
+ </para>
+ </sect2>
+ <sect2 id="mapping-column" revision="4">
+ <title>éléments column et formula</title>
+ <para>
+ Tout élément de mapping qui accepte un attribut <literal>column</literal> acceptera alternativement
+ un sous-élément <literal><column></literal>. De façon identique, <literal><formula></literal>
+ est une alternative à l'attribut <literal>formula</literal>.
+ </para>
+ <programlisting><![CDATA[<column
+ name="column_name"
+ length="N"
+ precision="N"
+ scale="N"
+ not-null="true|false"
+ unique="true|false"
+ unique-key="multicolumn_unique_key_name"
+ index="index_name"
+ sql-type="sql_type_name"
+ check="SQL expression"/>]]></programlisting>
+ <programlisting><![CDATA[<formula>SQL expression</formula>]]></programlisting>
+ <para>
+ Les attributs <literal>column</literal> et <literal>formula</literal> peuvent même être combinés
+ au sein d'une même propriété ou mapping d'association pour exprimer, par exemple, des conditions
+ de jointure exotiques.
+ </para>
+ <programlisting><![CDATA[<many-to-one name="homeAddress" class="Address"
+ insert="false" update="false">
+ <column name="person_id" not-null="true" length="10"/>
+ <formula>'MAILING'</formula>
+</many-to-one>]]></programlisting>
+ </sect2>
+ <sect2 id="mapping-declaration-import">
+ <title>import</title>
+ <para>
+ Supposez que votre application possède deux classes persistantes du même nom, et vous ne voulez pas préciser
+ le nom Java complet (packages inclus) dans les queries Hibernate. Les classes peuvent alors être "importées"
+ explicitement plutôt que de compter sur <literal>auto-import="true"</literal>.Vous pouvez même importer
+ des classes et interfaces qui ne sont pas mappées explicitement.
+ </para>
+ <programlisting><![CDATA[<import class="java.lang.Object" rename="Universe"/>]]></programlisting>
+ <programlistingco>
+ <areaspec>
+ <area id="import1" coords="2 40"/>
+ <area id="import2" coords="3 40"/>
+ </areaspec>
+ <programlisting><![CDATA[<import
+ class="ClassName"
+ rename="ShortName"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="import1">
+ <para>
+ <literal>class</literal> : Nom Java complet de la classe.
+ </para>
+ </callout>
+ <callout arearefs="import2">
+ <para>
+ <literal>rename</literal> (optionnel - par défaut vaut le nom de la classe Java (sans package)) :
+ Nom pouvant être utilisé dans le langage de requête.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ </sect2>
+ <sect2 id="mapping-types-anymapping" revision="2">
+ <title>any</title>
+ <para>
+ Il existe encore un type de mapping de propriété. L'élément de mapping <literal><any></literal>
+ définit une association polymorphique vers des classes de tables multiples. Ce type de mapping requiert
+ toujours plus d'une colonne. La première colonne contient le type de l'entité associée. Les colonnes
+ restantes contiennent l'identifiant. il est impossible de spécifier une contrainte de clef étrangère
+ pour ce type d'association, donc ce n'est certainement pas considéré comme le moyen habituel de mapper
+ des associations (polymorphiques). Vous devriez utiliser cela uniquement dans des cas particuliers
+ (par exemple des logs d'audit, des données de session utilisateur, etc...).
+ </para>
+ <para>
+ L'attribut <literal>meta-type</literal> permet à l'application de spécifier un type personnalisé qui mappe
+ des valeurs de colonnes de le base de données sur des classes persistantes qui ont un attribut identifiant
+ du type spécifié par <literal>id-type</literal>. Vous devez spécifier le mapping à partir de valeurs du
+ méta-type sur les noms des classes.
+ </para>
+ <programlisting><![CDATA[<any name="being" id-type="long" meta-type="string">
+ <meta-value value="TBL_ANIMAL" class="Animal"/>
+ <meta-value value="TBL_HUMAN" class="Human"/>
+ <meta-value value="TBL_ALIEN" class="Alien"/>
+ <column name="table_name"/>
+ <column name="id"/>
+</any>]]></programlisting>
+ <programlistingco>
+ <areaspec>
+ <area id="any1" coords="2 50"/>
+ <area id="any2" coords="3 50"/>
+ <area id="any3" coords="4 50"/>
+ <area id="any4" coords="5 50"/>
+ <area id="any5" coords="6 50"/>
+ <area id="any6" coords="7 50"/>
+ </areaspec>
+ <programlisting><![CDATA[<any
+ name="propertyName"
+ id-type="idtypename"
+ meta-type="metatypename"
+ cascade="cascade_style"
+ access="field|property|ClassName"
+ optimistic-lock="true|false"
+>
+ <meta-value ... />
+ <meta-value ... />
+ .....
+ <column .... />
+ <column .... />
+ .....
+</any>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="any1">
+ <para>
+ <literal>name</literal> : le nom de la propriété.
+ </para>
+ </callout>
+ <callout arearefs="any2">
+ <para>
+ <literal>id-type</literal> : le type identifiant.
+ </para>
+ </callout>
+ <callout arearefs="any3">
+ <para>
+ <literal>meta-type</literal> (optionnel - par défaut à <literal>string</literal>) :
+ Tout type permis pour un mapping par discriminateur.
+ </para>
+ </callout>
+ <callout arearefs="any4">
+ <para>
+ <literal>cascade</literal> (optionnel - par défaut à <literal>none</literal>) :
+ le style de cascade.
+ </para>
+ </callout>
+ <callout arearefs="any5">
+ <para>
+ <literal>access</literal> (optionnel - par défaut à <literal>property</literal>) : La stratégie
+ à utiliser par Hibernate pour accéder à cette propriété.
+ </para>
+ </callout>
+ <callout arearefs="any6">
+ <para>
+ <literal>optimistic-lock</literal> (optionnel - par défaut à <literal>true</literal>) :
+ Indique que les mises à jour sur cette propriété nécessitent ou non l'acquisition d'un
+ verrou optimiste. En d'autres termes, définit si un incrément de version doit avoir lieu
+ quand cette propriété est marquée dirty.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ </sect2>
+ </sect1>
+ <sect1 id="mapping-types">
+ <title>Hibernate Types</title>
+ <sect2 id="mapping-types-entitiesvalues" revision="1">
+ <title>Entités et valeurs</title>
+ <para>
+ Pour comprendre le comportement des différents objets Java par rapport au service
+ de persistance, nous avons besoin de les classer en deux groupes :
+ </para>
+ <para>
+ Une <emphasis>entité</emphasis> existe indépendamment de tout autre objet possédant
+ une référence vers l'entité. Comparez cela avec le modèle Java habituel où un objet
+ est supprimé par le garbage collector dès qu'il n'est plus référencé. Les entités
+ doivent être explicitement enregistrées et supprimées (sauf dans les cas où
+ sauvegardes et suppressions sont <emphasis>cascadées</emphasis> d'une entité mère
+ vers ses enfants). C'est différent du modèle ODMG de persistance par
+ atteignabilité - et correspond mieux à la façon dont les objets sont
+ habituellement utilisés dans des grands systèmes. Les entités permettent les références
+ circulaires et partagées. Elles peuvent aussi être versionnées.
+ </para>
+ <para>
+ L'état persistant d'une entité consiste en des références vers d'autres entités et
+ instances de types <emphasis>valeurs</emphasis>. Ces valeurs sont des types primitifs,
+ des collections (et non le contenu d'une collection), des composants de certains objets
+ immuables. Contrairement aux entités, les valeurs (et en particulier les collections et
+ composants) <emphasis>sont</emphasis> persistés par atteignabiliité. Comme les
+ valeurs (et types primitifs) sont persistés et supprimés avec l'entité qui les contient,
+ ils ne peuvent pas posséder leurs propres versions. Les valeurs n'ont pas d'identité
+ indépendantes, ainsi elles ne peuvent pas être partagées par deux entités ou collections.
+ </para>
+ <para>
+ Jusqu'à présent nous avons utilisé le terme "classe persistante" pour parler d'entités.
+ Nous allons continuer à faire ainsi. Cependant, au sens strict, toutes
+ les classes définies par un utilisateur possédant un état persistant ne sont pas des
+ entités. Un <emphasis>composant</emphasis> est une classe définie par un utilisateur
+ avec les caractéristiques d'une valeur. Une propriété Java de type <literal>java.lang.String</literal>
+ a aussi les caractéristiques d'une valeur.
+
+ <!-- FIXME Baptiste MATHUS : J'ai remis le texte anglais pour que si la version est publiée
+ comme ça, au moins le lecteur puisse essayer lui aussi de comprendre la version anglaise... -->
+
+ Given this definition, we can say that all types (classes) provided
+ by the JDK have value type semantics in Java, while user-defined types may
+ be mapped with entity or value type semantics. This decision is up to the
+ application developer. A good hint for an entity class in a domain model are
+ shared references to a single instance of that class, while composition or
+ aggregation usually translates to a value type.
+ </para>
+ <para>
+ Nous nous pencherons sur ces deux concepts tout au long de la documentation.
+ </para>
+ <para>
+ Le défi est de mapper les type Javas (et la définition des développeurs des
+ entités et valeurs types) sur les types du SQL ou des bases de données. Le pont
+ entre les deux systèmes est proposé par Hibernate : pour les entités nous utilisons
+ <literal><class></literal>, <literal><subclass></literal> et ainsi de suite.
+ Pour les types valeurs nous utilisons <literal><property></literal>,
+ <literal><component></literal>, etc., habituellement avec un attribut <literal>type</literal>.
+ La valeur de cet attribut est le nom d'un <emphasis>type de mapping</emphasis> Hibernate.
+ Hibernate propose de base de nombreux mappings (pour les types de valeurs standards du JDK).
+ Vous pouvez écrire vos propres types de mappings et implémenter aussi vos propres stratégies
+ de conversion, nous le verrons plus tard.
+ </para>
+ <para>
+ Tous les types proposés de base par Hibernate à part les collections autorisent la valeur null.
+ </para>
+ </sect2>
+ <sect2 id="mapping-types-basictypes" revision="3">
+ <title>Basic value types</title>
+ <para>
+ Les <emphasis>types basiques de mapping</emphasis> proposés de base peuvent grossièrement être
+ rangés dans les catégories suivantes :
+ <variablelist>
+ <varlistentry>
+ <term>
+ <literal>integer, long, short, float, double, character, byte,
+ boolean, yes_no, true_false</literal>
+ </term>
+ <listitem>
+ <para>
+ Les mappings de type des primitives Java ou leurs classes wrappers (ex: Integer
+ pour int) vers les types SQL (propriétaires) appropriés. <literal>boolean,
+ yes_no</literal>et <literal>true_false</literal> sont tous des alternatives
+ pour les types Java <literal>boolean</literal> ou <literal>java.lang.Boolean</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>string</literal>
+ </term>
+ <listitem>
+ <para>
+ Mapping de type de <literal>java.lang.String</literal> vers
+ <literal>VARCHAR</literal> (ou le <literal>VARCHAR2</literal> Oracle).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>date, time, timestamp</literal>
+ </term>
+ <listitem>
+ <para>
+ Mappings de type pour <literal>java.util.Date</literal> et ses sous-classes
+ vers les types SQL <literal>DATE</literal>, <literal>TIME</literal> et
+ <literal>TIMESTAMP</literal> (ou équivalent).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>calendar, calendar_date</literal>
+ </term>
+ <listitem>
+ <para>
+ Mappings de type pour <literal>java.util.Calendar</literal> vers les types SQL
+ <literal>TIMESTAMP</literal> et <literal>DATE</literal>
+ (ou équivalent).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>big_decimal, big_integer</literal>
+ </term>
+ <listitem>
+ <para>
+ Mappings de type pour <literal>java.math.BigDecimal</literal> et
+ <literal>java.math.BigInteger</literal> vers <literal>NUMERIC</literal>
+ (ou le <literal>NUMBER</literal> Oracle).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>locale, timezone, currency</literal>
+ </term>
+ <listitem>
+ <para>
+ Mappings de type pour <literal>java.util.Locale</literal>,
+ <literal>java.util.TimeZone</literal> et
+ <literal>java.util.Currency</literal>
+ vers <literal>VARCHAR</literal> (ou le <literal>VARCHAR2</literal> Oracle).
+ Les instances de <literal>Locale</literal> et <literal>Currency</literal> sont
+ mappées sur leurs codes ISO. Les instances de <literal>TimeZone</literal> sont
+ mappées sur leur <literal>ID</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>class</literal>
+ </term>
+ <listitem>
+ <para>
+ Un type de mapping pour <literal>java.lang.Class</literal> vers
+ <literal>VARCHAR</literal> (ou le <literal>VARCHAR2</literal> Oracle).
+ Un objet <literal>Class</literal> est mappé sur son nom Java complet.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>binary</literal>
+ </term>
+ <listitem>
+ <para>
+ Mappe les tableaux de bytes vers le type binaire SQL approprié.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>text</literal>
+ </term>
+ <listitem>
+ <para>
+ Mappe les longues chaînes de caractères Java vers les types SQL
+ <literal>CLOB</literal> ou <literal>TEXT</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>serializable</literal>
+ </term>
+ <listitem>
+ <para>
+ Mappe les types Java sérialisables vers le type SQL binaire approprié. Vous pouvez
+ aussi indiquer le type Hibernate <literal>serializable</literal> avec le nom
+ d'une classe Java sérialisable ou une interface qui ne soit pas par défaut un type de base.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>clob, blob</literal>
+ </term>
+ <listitem>
+ <para>
+ Mappings de type pour les classes JDBC <literal>java.sql.Clob</literal> and
+ <literal>java.sql.Blob</literal>. Ces types peuvent ne pas convenir pour certaines
+ applications car un objet blob ou clob peut ne pas être réutilisable en dehors
+ d'une transaction (de plus l'implémentation par les pilotes est moyennement bonne).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>imm_date, imm_time, imm_timestamp, imm_calendar, imm_calendar_date,
+ imm_serializable, imm_binary</literal>
+ </term>
+ <listitem>
+ <para>
+ Mappings de type pour ceux qui sont habituellement modifiable, pour lesquels
+ Hibernate effectue certains optimisations convenant seulement aux types Java immuables,
+ et l'application les traite comme immuable.
+ Par exemple, vous ne devriez pas appeler <literal>Date.setTime()</literal> sur une instance
+ mappée sur un <literal>imm_timestamp</literal>. Pour changer la valeur
+ de la propriété, et faire que cette modification soit persistée, l'application
+ doit assigner un nouvel (non identique) objet à la propriété.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para>
+ Les identifiants uniques des entités et collections peuvent être de n'importe quel type de base excepté
+ <literal>binary</literal>, <literal>blob</literal> et <literal>clob</literal> (les identifiants
+ composites sont aussi permis, voir plus bas).
+ </para>
+ <para>
+ Les types de base des valeurs ont des <literal>Type</literal> constants correspondants définis
+ dans <literal>org.hibernate.Hibernate</literal>. Par exemple, <literal>Hibernate.STRING</literal>
+ représenté le type <literal>string</literal>.
+ </para>
+ </sect2>
+ <sect2 id="mapping-types-custom" revision="2">
+ <title>Types de valeur définis par l'utilisateur</title>
+ <para>
+ Il est assez facile pour les développeurs de créer leurs propres types de valeurs. Par exemple,
+ vous pourriez vouloir persister des propriétés du type <literal>java.lang.BigInteger</literal>
+ dans des colonnnes <literal>VARCHAR</literal>. Hibernate ne procure pas par défaut un type pour cela.
+ Mais les types que vous pouvez créer ne se limitent pas à mapper des propriétés (ou élément collection)
+ à une simple colonne d'une table. Donc, par exemple, vous pourriez avoir une propriété Java
+ <literal>getName()</literal>/<literal>setName()</literal> de type
+ <literal>java.lang.String</literal> persistée dans les colonnes
+ <literal>FIRST_NAME</literal>, <literal>INITIAL</literal>, <literal>SURNAME</literal>.
+ </para>
+ <para>
+ Pour implémenter votre propre type, vous pouvez soit implémenter <literal>org.hibernate.UserType</literal>
+ soit <literal>org.hibernate.CompositeUserType</literal> et déclarer des propriétés utilisant des
+ noms de classes complets du type. Regardez <literal>org.hibernate.test.DoubleStringType</literal>
+ pour voir ce qu'il est possible de faire.
+ </para>
+ <programlisting><![CDATA[<property name="twoStrings" type="org.hibernate.test.DoubleStringType">
+ <column name="first_string"/>
+ <column name="second_string"/>
+</property>]]></programlisting>
+ <para>
+ Remarquez l'utilisation des tags <literal><column></literal> pour mapper une propriété sur des colonnes
+ multiples.
+ </para>
+ <para>
+ Les interfaces <literal>CompositeUserType</literal>, <literal>EnhancedUserType</literal>,
+ <literal>UserCollectionType</literal>, et <literal>UserVersionType</literal> permettent des utilisations
+ plus spécialisées.
+ </para>
+ <para>
+ Vous pouvez même donner des paramètres en indiquant <literal>UserType</literal> dans le fichier
+ de mapping ; Pour cela, votre <literal>UserType</literal> doit implémenter l'interface
+ <literal>org.hibernate.usertype.ParameterizedType</literal>. Pour spécifier des paramètres dans
+ votre type propre, vous pouvez utiliser l'élément <literal><type></literal> dans vos fichiers de mapping.
+ </para>
+ <programlisting><![CDATA[<property name="priority">
+ <type name="com.mycompany.usertypes.DefaultValueIntegerType">
+ <param name="default">0</param>
+ </type>
+</property>]]></programlisting>
+ <para>
+ Le <literal>UserType</literal> permet maintenant de récupérer la valeur pour le paramètre nommé
+ <literal>default</literal> à partir de l'objet <literal>Properties</literal> qui lui est passé.
+ </para>
+ <para>
+ Si vous utilisez fréquemment un <literal>UserType</literal>, cela peut être utile de lui définir un
+ nom plus court. Vous pouvez faire cela en utilisant l'élément <literal><typedef></literal>.
+ Les typedefs permettent d'assigner un nom à votre type propre et peuvent aussi contenir une liste de
+ valeurs de paramètres par défaut si ce type est paramétré.
+ </para>
+ <programlisting><![CDATA[<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
+ <param name="default">0</param>
+</typedef>]]></programlisting>
+ <programlisting><![CDATA[<property name="priority" type="default_zero"/>]]></programlisting>
+ <para>
+ Il est aussi possible de redéfinir les paramètres par défaut du typedef au cas par cas en
+ utilisant des paramètres type sur le mapping de la propriété.
+ </para>
+ <para>
+ Bien que le fait que Hibernate propose de base une riche variété de types, et qu'il supporte les composants
+ signifie que vous aurez très rarement <emphasis>besoin</emphasis> d'utiliser un nouveau type propre,
+ il est néanmoins de bonne pratique d'utiliser des types propres pour les classes (non entités) qui
+ apparaissent fréquemment dans votre application. Par exemple une classe <literal>MonetaryAmount</literal>
+ est un bon candidat pour un <literal>CompositeUserType</literal> même s'il pourrait facilement
+ être mappé comme un composant. Une motivation pour cela est l'abstraction. Avec un type propre
+ vos documents de mapping sont à l'abri des changements futurs dans votre façon de représenter des
+ valeurs monétaires.
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="mapping-entityname">
+ <title>Mapper une classe plus d'une fois</title>
+ <para>
+ Il est possible de proposer plus d'un mapping par classe persistante. Dans ce cas, vous
+ devez spécifier un <emphasis>nom d'entité</emphasis> pour lever l'ambiguité entre les instances
+ des entités mappées (par défaut, le nom de l'entité est celui de la classe). Hibernate
+ vous permet de spécifier le nom de l'entité lorsque vous utilisez des objets persistants, lorsque
+ vous écrivez des requêtes ou quand vous mappez des associations vers les entités nommées.
+ </para>
+
+ <programlisting><![CDATA[<class name="Contract" table="Contracts"
+ entity-name="CurrentContract">
+ ...
+ <set name="history" inverse="true"
+ order-by="effectiveEndDate desc">
+ <key column="currentContractId"/>
+ <one-to-many entity-name="HistoricalContract"/>
+ </set>
+</class>
+
+<class name="Contract" table="ContractHistory"
+ entity-name="HistoricalContract">
+ ...
+ <many-to-one name="currentContract"
+ column="currentContractId"
+ entity-name="CurrentContract"/>
+</class>]]></programlisting>
+
+ <para>
+ Remarquez comment les associations sont désormais spécifiées en utilisant
+ <literal>entity-name</literal> au lieu de <literal>class</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="mapping-quotedidentifiers">
+ <title>SQL quoted identifiers</title>
+ <para>
+ Vous pouvez forcer Hibernate à mettre un identifiant entre quotes dans le SQL généré en mettant le nom
+ de la table ou de la colonne entre backticks dans le
+ document de mapping. Hibernate utilisera les bons styles de quotes pour le <literal>Dialect</literal> SQL
+ (habituellement des doubles quotes, mais des parenthèses pour SQL server et des backticks pour MySQL).
+ </para>
+ <programlisting><![CDATA[<class name="LineItem" table="`Line Item`">
+ <id name="id" column="`Item Id`"/><generator class="assigned"/></id>
+ <property name="itemNumber" column="`Item #`"/>
+ ...
+</class>]]></programlisting>
+ </sect1>
+ <sect1 id="mapping-alternatives">
+ <title>alternatives Metadata</title>
+ <para>
+ XML ne convient pas à tout le monde, il y a donc des moyens alternatifs pour définir des metatda
+ de mappings O/R dans Hibernate.
+ </para>
+ <sect2 id="mapping-xdoclet">
+ <title>utilisation de XDoclet</title>
+ <para>
+ De nombreux utilisateurs de Hibernate préfèrent embarquer les informations de mappings
+ directement au sein du code source en utilisant les tags XDoclet <literal>@hibernate.tags</literal>.
+ Nous ne couvrons pas cette approche dans ce document cependant, puisque c'est considéré comme faisant partie
+ de XDoclet. Cependant, nous présentons l'exemple suivant de la classe <literal>Cat</literal> avec
+ des mappings XDoclet.
+ </para>
+ <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+/**
+ * @hibernate.class
+ * table="CATS"
+ */
+public class Cat {
+ private Long id; // identifier
+ private Date birthdate;
+ private Cat mother;
+ private Set kittens
+ private Color color;
+ private char sex;
+ private float weight;
+
+ /*
+ * @hibernate.id
+ * generator-class="native"
+ * column="CAT_ID"
+ */
+ public Long getId() {
+ return id;
+ }
+ private void setId(Long id) {
+ this.id=id;
+ }
+
+ /**
+ * @hibernate.many-to-one
+ * column="PARENT_ID"
+ */
+ public Cat getMother() {
+ return mother;
+ }
+ void setMother(Cat mother) {
+ this.mother = mother;
+ }
+
+ /**
+ * @hibernate.property
+ * column="BIRTH_DATE"
+ */
+ public Date getBirthdate() {
+ return birthdate;
+ }
+ void setBirthdate(Date date) {
+ birthdate = date;
+ }
+ /**
+ * @hibernate.property
+ * column="WEIGHT"
+ */
+ public float getWeight() {
+ return weight;
+ }
+ void setWeight(float weight) {
+ this.weight = weight;
+ }
+
+ /**
+ * @hibernate.property
+ * column="COLOR"
+ * not-null="true"
+ */
+ public Color getColor() {
+ return color;
+ }
+ void setColor(Color color) {
+ this.color = color;
+ }
+ /**
+ * @hibernate.set
+ * inverse="true"
+ * order-by="BIRTH_DATE"
+ * @hibernate.collection-key
+ * column="PARENT_ID"
+ * @hibernate.collection-one-to-many
+ */
+ public Set getKittens() {
+ return kittens;
+ }
+ void setKittens(Set kittens) {
+ this.kittens = kittens;
+ }
+ // addKitten not needed by Hibernate
+ public void addKitten(Cat kitten) {
+ kittens.add(kitten);
+ }
+
+ /**
+ * @hibernate.property
+ * column="SEX"
+ * not-null="true"
+ * update="false"
+ */
+ public char getSex() {
+ return sex;
+ }
+ void setSex(char sex) {
+ this.sex=sex;
+ }
+}]]></programlisting>
+ <para>
+ Voyez le site web de Hibernate pour plus d'exemples sur XDoclet et Hibernate.
+ </para>
+ </sect2>
+ <sect2 id="mapping-annotations" revision="2">
+ <title>Utilisation des annotations JDK 5.0</title>
+ <para>
+ Le JDK 5.0 introduit des annotations proches de celles de XDoclet au niveau java, qui sont
+ type-safe et vérifiées à la compilation. Ce mécanisme est plus puissant que XDoclet et mieux
+ supporté par les outils et IDE. IntelliJ IDEA, par exemple, supporte l'auto-complétion et le
+ surlignement syntaxique des annotations JDK 5.0. La nouvelle révision des spécifications des EJB
+ (JSR-220) utilise les annotations JDK 5.0 comme mécanisme primaire pour les meta-données des beans entités.
+ Hibernate3 implémente l'<literal>EntityManager</literal> de la JSR-220 (API de persistance),
+ le support du mapping de meta-données est disponible via le package <emphasis>Hibernate Annotations</emphasis>,
+ en tant que module séparé à télécharger. EJB3 (JSR-220) et les métadata Hibernate3 sont supportés.
+ </para>
+ <para>
+ Ceci est un exemple d'une classe POJO annotée comme un EJB entité :
+ </para>
+ <programlisting><![CDATA[@Entity(access = AccessType.FIELD)
+public class Customer implements Serializable {
+
+ @Id;
+ Long id;
+
+ String firstName;
+ String lastName;
+ Date birthday;
+
+ @Transient
+ Integer age;
+
+ @Embedded
+ private Address homeAddress;
+
+ @OneToMany(cascade=CascadeType.ALL)
+ @JoinColumn(name="CUSTOMER_ID")
+ Set<Order> orders;
+
+ // Getter/setter and business methods
+}]]></programlisting>
+ <para>
+ Notez que le support des annotations JDK 5.0 (et de la JSR-220) est encore en cours et n'est pas terminé.
+ Référez vous au module Hibernate Annotation pour plus de détails.
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="mapping-generated" revision="1">
+ <title>Propriétés générées</title>
+ <para>
+ Les propriétés générées sont des propriétés dont les valeurs sont générées par
+ la base de données. Typiquement, les applications Hibernate avaient besoin d'invoquer
+ <literal>refresh</literal> sur les instances qui contenaient des propriétés pour lesquelles
+ la base de données générait des valeurs. Marquer les propriétés comme générées permet à
+ l'application de déléguer cette responsabilité à Hibernate. Principalement, à chaque fois
+ qu'Hibernate réalise une insertion ou une mise à jour en base de données pour une entité
+ marquée comme telle, cela provoque immédiatement un select pour récupérer les valeurs générées.
+ </para>
+ <para>
+ Les propriétés marquées comme générées doivent de plus ne pas être insérables et modifiables
+ Seuls <xref linkend="mapping-declaration-version">versions</xref>,
+ <xref linkend="mapping-declaration-timestamp">timestamps</xref>, et
+ <xref linkend="mapping-declaration-property">simple properties</xref> peuvent être marqués comme
+ générées.
+ </para>
+ <para>
+ <literal>never</literal> (par défaut) - indique la valeur de la propriété n'est pas générée
+ dans la base de données.
+ </para>
+ <para>
+ <literal>insert</literal> - indique que la valeur de la propriété donnée est
+ générée à l'insertion mais pas lors des futures mises à jour de l'enregistrement.
+ Les colonnes de type "date de création" sont le cas d'utilisation typique de cette option.
+ Notez que même les propriétés <xref linkend="mapping-declaration-version">version</xref> et
+ <xref linkend="mapping-declaration-timestamp">timestamp</xref> peuvent être
+ déclarées comme générées, cette option n'est pas disponible à cet endroit...
+ </para>
+ <para>
+ <literal>always</literal> - indique que la valeur de la propriété est générée à l'insert
+ comme aux updates.
+ </para>
+
+ </sect1>
+
+ <sect1 id="mapping-database-object">
+ <title>Objets auxiliaires de la base de données</title>
+ <para>
+ Permettent les ordres CREATE et DROP d'objets arbitraire de la base de donnéées, en conjonction avec
+ les outils Hibernate d'évolutions de schéma, pour permettre de définir complètement
+ un schéma utilisateur au sein des fichiers de mapping Hibernate. Bien que conçu spécifiquement
+ pour créer et supprimer des objets tels que des triggers et des procédures stockées,
+ ou toute commande pouvant être exécutée via une méthode de <literal>java.sql.Statement.execute()</literal>
+ (ALTERs, INSERTS, etc). Il y a principalement deux modes pour définir les objets auxiliaires de base de données...
+ </para>
+ <para>
+ Le premier mode est de lister explicitement les commandes CREATE et DROP dans le fichier
+ de mapping:
+ </para>
+ <programlisting><![CDATA[<hibernate-mapping>
+ ...
+ <database-object>
+ <create>CREATE TRIGGER my_trigger ...</create>
+ <drop>DROP TRIGGER my_trigger</drop>
+ </database-object>
+</hibernate-mapping>]]></programlisting>
+ <para>
+ Le second mode est de fournir une classe particulière qui connait comment construire
+ les commandes CREATE et DROP. Cette classe particulière doit implémenter l'interface
+ <literal>org.hibernate.mapping.AuxiliaryDatabaseObject</literal>.
+ </para>
+ <programlisting><![CDATA[<hibernate-mapping>
+ ...
+ <database-object>
+ <definition class="MyTriggerDefinition"/>
+ </database-object>
+</hibernate-mapping>]]></programlisting>
+ <para>
+ Additionnellement, ces objets de base de données peuvent être optionnellement traités
+ selon l'utilisation de dialectes particuliers..
+ </para>
+ <programlisting><![CDATA[<hibernate-mapping>
+ ...
+ <database-object>
+ <definition class="MyTriggerDefinition"/>
+ <dialect-scope name="org.hibernate.dialect.Oracle9Dialect"/>
+ <dialect-scope name="org.hibernate.dialect.OracleDialect"/>
+ </database-object>
+</hibernate-mapping>]]></programlisting>
+ </sect1>
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/batch.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/batch.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/batch.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,329 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="batch">
+ <title>Traitement par paquet</title>
+
+ <para>
+ Une approche naïve pour insérer 100 000 lignes dans la base de données en utilisant
+ Hibernate pourrait ressembler à ça :
+ </para>
+
+ <programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+for ( int i=0; i<100000; i++ ) {
+ Customer customer = new Customer(.....);
+ session.save(customer);
+}
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ Ceci devrait s'écrouler avec une <literal>OutOfMemoryException</literal> quelque
+ part aux alentours de la 50 000ème ligne. C'est parce qu'Hibernate cache toutes
+ les instances de <literal>Customer</literal> nouvellement insérées dans le cache
+ de second niveau.
+ </para>
+
+ <para>
+ Dans ce chapitre nous montrerons comment éviter ce problème. D'abord, cependant,
+ si vous faites des traitements par batch, il est absolument critique que vous
+ activiez l'utilisation ds paquet JDBC (NdT : JDBC batching), si vous avez l'intention
+ d'obtenir des performances raisonnables. Configurez la taille du paquet JDBC avec un
+ nombre raisonnable (disons, 10-50) :
+ </para>
+
+ <programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
+
+ <para>
+ Vous pourriez aussi vouloir faire cette sorte de travail dans un traitement où
+ l'interaction avec le cache de second niveau est complètement désactivé :
+ </para>
+
+ <programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
+
+ <sect1 id="batch-inserts">
+ <title>Insertions en paquet</title>
+
+ <para>
+ Lorsque vous rendez des nouveaux objets persistants, vous devez régulièrement appeler
+ <literal>flush()</literal> et puis <literal>clear()</literal> sur la session,
+ pour contrôler la taille du cache de premier niveau.
+ </para>
+
+ <programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+for ( int i=0; i<100000; i++ ) {
+ Customer customer = new Customer(.....);
+ session.save(customer);
+ if ( i % 20 == 0 ) { //20, même taille que la taille du paquet JDBC
+ //flush un paquet d'insertions et libère la mémoire :
+ session.flush();
+ session.clear();
+ }
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="batch-update" >
+ <title>Paquet de mises à jour</title>
+
+ <para>
+ Pour récupérer et mettre à jour des données les mêmes idées s'appliquent. En plus,
+ vous avez besoin d'utiliser <literal>scroll()</literal> pour tirer partie des
+ curseurs côté serveur pour les requêtes qui retournent beaucoup de lignes de données.
+ </para>
+
+ <programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+ .setCacheMode(CacheMode.IGNORE)
+ .scroll(ScrollMode.FORWARD_ONLY);
+int count=0;
+while ( customers.next() ) {
+ Customer customer = (Customer) customers.get(0);
+ customer.updateStuff(...);
+ if ( ++count % 20 == 0 ) {
+ //flush un paquet de mises à jour et libère la mémoire :
+ session.flush();
+ session.clear();
+ }
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="batch-statelesssession">
+ <title>L'interface StatelessSession</title>
+ <para>
+ Alternativement, Hibernate fournit une API orientée commande qui peut être
+ utilisée avec des flux de données pour et en provenance de la base de données
+ sous la forme d'objets détachés. Une <literal>StatelessSession</literal> n'a pas
+ de contexte de persistance associé et ne fournit pas beaucoup de sémantique de
+ durée de vie de haut niveau. En particulier, une session sans état n'implémente
+ pas de cache de premier niveau et n'interagit pas non plus avec un cache de
+ seconde niveau ou un cache de requêtes. Elle n'implémente pas les transactions
+ ou la vérification sale automatique (NdT : automatic dirty checking). Les
+ opérations réalisées avec une session sans état ne sont jamais répercutées
+ en cascade sur les instances associées. Les collections sont ignorées par une
+ session sans état. Les opérations exécutées via une session sans état outrepasse
+ le modèle d'événements d'Hibernate et les intercepteurs. Les sessions sans état sont
+ vulnérables aux effets de modification des données, ceci est dû au manque de cache
+ de premier niveau. Une session sans état est une abstraction bas niveau, plus
+ proche de la couche JDBC sous-jacente.
+ </para>
+
+ <programlisting><![CDATA[StatelessSession session = sessionFactory.openStatelessSession();
+Transaction tx = session.beginTransaction();
+
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+ .scroll(ScrollMode.FORWARD_ONLY);
+while ( customers.next() ) {
+ Customer customer = (Customer) customers.get(0);
+ customer.updateStuff(...);
+ session.update(customer);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ Notez que dans le code de l'exemple, les intances de <literal>Customer</literal>
+ retournées par la requête sont immédiatement détachées. Elles ne sont jamais
+ associées à un contexte de persistance.
+ </para>
+
+ <para>
+ Les opérations <literal>insert()</literal>, <literal>update()</literal> et
+ <literal>delete()</literal> définies par l'interface <literal>StatelessSession</literal>
+ sont considérées comme des opérations d'accès direct aux lignes de la base de données,
+ ce qui résulte en une exécution immédiate du SQL <literal>INSERT</literal>, <literal>UPDATE</literal>
+ ou <literal>DELETE</literal> respectif. De là, elles ont des sémantiques tres différentes des
+ opérations <literal>save()</literal>, <literal>saveOrUpdate()</literal>
+ et <literal>delete()</literal> définies par l'interface <literal>Session</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="batch-direct" revision="2">
+ <title>Opérations de style DML</title>
+
+ <para>
+ Comme déjà discuté avant, le mapping objet/relationnel automatique et transparent
+ est intéressé par la gestion de l'état de l'objet. Ceci implique que l'état de l'objet
+ est disponible en mémoire, d'où manipuler (en utilisant des expressions du langage de
+ manipulation de données - <literal>Data Manipulation Language</literal> (DML) - SQL)
+ les données directement dans la base n'affectera pas l'état en mémoire. Pourtant, Hibernate
+ fournit des méthodes pour l'exécution d'expression DML de style SQL lesquelles sont
+ réalisées à travers le langage de requête d'Hibernate (<xref linkend="queryhql">HQL</xref>).
+ </para>
+
+ <para>
+ La pseudo-syntaxe pour les expressions <literal>UPDATE</literal> et <literal>DELETE</literal>
+ est : <literal>( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?</literal>.
+ Certains points sont à noter :
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Dans la clause from, le mot-clef FROM est optionnel
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Il ne peut y avoir qu'une seule entité nommée dans la clause from ; elle peut
+ optionnellement avoir un alias. Si le nom de l'entité a un alias, alors
+ n'importe quelle référence de propriété doit être qualifiée en ayant un alias ;
+ si le nom de l'entité n'a pas d'alias, alors il est illégal pour n'importe quelle
+ référence de propriété d'être qualifiée.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Aucune jointure (implicite ou explicite) ne peut être spécifiée dans une requête HQL.
+ Les sous-requêtes peuvent être utilisées dans la clause where ; les sous-requêtes,
+ elles-mêmes, peuvent contenir des jointures.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ La clause where est aussi optionnelle.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Par exemple, pour exécuter un <literal>UPDATE</literal> HQL, utilisez la méthode
+ <literal>Query.executeUpdate()</literal> (la méthode est données pour ceux
+ qui sont familiers avec <literal>PreparedStatement.executeUpdate()</literal> de
+ JDBC) :
+ </para>
+
+ <programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
+// ou String hqlUpdate = "update Customer set name = :newName where name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+ .setString( "newName", newName )
+ .setString( "oldName", oldName )
+ .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ Pour exécuter un <literal>DELETE</literal> HQL, utilisez la même méthode
+ <literal>Query.executeUpdate()</literal> :
+ </para>
+
+ <programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlDelete = "delete Customer c where c.name = :oldName";
+// or String hqlDelete = "delete Customer where name = :oldName";
+int deletedEntities = s.createQuery( hqlDelete )
+ .setString( "oldName", oldName )
+ .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ La valeur du <literal>int</literal> retourné par la méthode <literal>Query.executeUpdate()</literal>
+ indique le nombre d'entités affectées par l'opération. Considérez que cela peut ou pas
+ corréler le nombre de lignes affectés dans la base de données. Une opération HQL
+ pourrait entraîner l'exécution de multiples expressions SQL réelles, pour des classes
+ filles mappées par jointure (NdT: join-subclass), par exemple. Le nombre retourné
+ indique le nombre d'entités réelles affectées par l'expression. Retour à l'exemple de la
+ classe fille mappée par jointure, un effacement d'une des classes filles peut réellement
+ entraîner des suppressions pas seulement dans la table qui mappe la classe fille, mais
+ aussi dans la table "racine" et potentillement dans les tables des classes filles plus bas
+ dans la hiérarchie d'héritage.
+ </para>
+
+ <para>
+ La pseudo-syntaxe pour l'expression <literal>INSERT</literal> est :
+ <literal>INSERT INTO EntityName properties_list select_statement</literal>. Quelques
+ points sont à noter :
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Seule la forme INSERT INTO ... SELECT ... est supportée ; pas la forme INSERT INTO ... VALUES ... .
+ </para>
+ <para>
+ La properties_list est analogue à la <literal>spécification de la colonne</literal>
+
+ The properties_list is analogous to the <literal>column speficiation</literal> dans
+ l'expression SQL <literal>INSERT</literal>. Pour les entités impliquées dans
+ un héritage mappé, seules les propriétés directement définies à ce niveau de classe
+ donné peuvent être utilisées dans properties_list. Les propriétés de la classe mère
+ ne sont pas permises ; et les propriétés des classes filles n'ont pas de sens. En
+ d'autres mots, les expressions <literal>INSERT</literal> par nature non polymorphiques.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ select_statement peut être n'importe quelle requête de sélection HQl valide, avec
+ l'avertissement que les types de retour doivent correspondre aux types attendus par
+ l'insertion. Actuellement, c'est vérifié durant la compilation de la requête plutôt
+ que la vérification soit reléguée à la base de données. Notez cependant que cela
+ pourrait poser des problèmes entre les <literal>Type</literal>s d'Hibernate qui
+ sont <emphasis>équivalents</emphasis> opposé à <emphasis>égaux</emphasis>. Cela
+ pourrait poser des problèmes avec des disparités entre une propriété définie
+ comme un <literal>org.hibernate.type.DateType</literal> et une propriété définie
+ comme un <literal>org.hibernate.type.TimestampType</literal>, même si la base de données
+ ne ferait pas de distinction ou ne serait pas capable de gérer la conversion.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Pour la propriéte id, l'expression d'insertion vous donne deux options. Vous
+ pouvez soit spécifier explicitement la propriété id dans properties_list
+ (auquel cas sa valeur est extraite de l'expression de sélection correspondante),
+ soit l'omettre de properties_list (auquel cas une valeur générée est utilisée).
+ Cette dernière option est seulement disponible en utilisant le générateur d'identifiant
+ qui opère dans la base de données ; tenter d'utiliser cette option avec n'importe quel
+ type de générateur "en mémoire" causera une exception durant l'analyse. Notez
+ que pour les buts de cette discussion, les générateurs "en base" sont considérés
+ être <literal>org.hibernate.id.SequenceGenerator</literal> (et ses classes filles)
+ et n'importe quelles implémentations de
+ <literal>org.hibernate.id.PostInsertIdentifierGenerator</literal>.
+ L'exception la plus notable ici est <literal>org.hibernate.id.TableHiLoGenerator</literal>,
+ qu ne peut pas être utilisée parce qu'il ne propose pas un moyen de d'exposer ses valeurs
+ par un select.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Pour des propriétés mappées comme <literal>version</literal> ou <literal>timestamp</literal>,
+ l'expression d'insertion vous donne deux options. Vous pouvez soit spécifier la propriété dans
+ properties_list (auquel cas sa valeur est extraite des expressions select correspondantes),
+ soit l'omettre de properties_list (auquel cas la <literal>valeur de graine</literal>
+ (NdT : seed value) définie par le <literal>org.hibernate.type.VersionType</literal> est utilisée).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Un exemple d'exécution d'une expression <literal>INSERT</literal> HQL :
+ </para>
+
+ <programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
+int createdEntities = s.createQuery( hqlInsert )
+ .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/best_practices.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/best_practices.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/best_practices.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,240 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="best-practices" revision="3">
+ <title>Meilleures pratiques</title>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>Découpez finement vos classes et mappez les en utilisant <literal><component></literal>.</term>
+ <listitem>
+ <para>
+ Utilisez une classe <literal>Adresse</literal> pour encapsuler <literal>Rue</literal>,
+ <literal>Region</literal>, <literal>CodePostal</literal>.
+ Ceci permet la réutilisation du code et simplifie la maintenance.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Déclarez des propriétés d'identifiants dans les classes persistantes.</term>
+ <listitem>
+ <para>
+ Hibernate rend les propriétés d'identifiants optionnelles. Il existe beaucoup de raisons
+ pour lesquelles vous devriez les utiliser. Nous recommandons que vous utilisiez des identifiants
+ techniques (générés, et sans connotation métier).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Identifiez les clefs naturelles.</term>
+ <listitem>
+ <para>
+ Identifiez les clefs naturelles pour toutes les entités, et mappez les avec
+ <literal><natural-id></literal>. Implémentez <literal>equals()</literal> et
+ <literal>hashCode()</literal> pour comparer les propriétés qui composent la clef naturelle.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Placez chaque mapping de classe dans son propre fichier.</term>
+ <listitem>
+ <para>
+ N'utilisez pas un unique document de mapping. Mappez <literal>com.eg.Foo</literal> dans
+ le fichier <literal>com/eg/Foo.hbm.xml</literal>. Cela prend tout son sens lors
+ d'un travail en équipe.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Chargez les mappings comme des ressources.</term>
+ <listitem>
+ <para>
+ Déployez les mappings en même temps que les classes qu'ils mappent.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Pensez à externaliser les chaînes de caractères.</term>
+ <listitem>
+ <para>
+ Ceci est une bonne habitude si vos requêtes appellent des fonctions SQL qui ne sont
+ pas au standard ANSI. Cette externalisation dans les fichiers de mapping rendra votre
+ application plus portable.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Utilisez les variables "bindées".</term>
+ <listitem>
+ <para>
+ Comme en JDBC, remplacez toujours les valeurs non constantes par "?". N'utilisez jamais
+ la manipulation des chaînes de caractères pour remplacer des valeurs non constantes dans
+ une requête ! Encore mieux, utilisez les paramètres nommés dans les requêtes.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Ne gérez pas vous même les connexions JDBC.</term>
+ <listitem>
+ <para>
+ Hibernate laisse l'application gérer les connexions JDBC. Vous ne devriez gérer vos connexions
+ qu'en dernier recours. Si vous ne pouvez pas utiliser les systèmes de connexions livrés,
+ réfléchissez à l'idée de fournir votre propre implémentation de <literal>org.hibernate.connection.ConnectionProvider</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Pensez à utiliser les types utilisateurs.</term>
+ <listitem>
+ <para>
+ Supposez que vous ayez une type Java, de telle bibliothèque, qui a besoin d'être persisté mais
+ qui ne fournit pas les accesseurs nécessaires pour le mapper comme composant. Vous devriez
+ implémenter
+ <literal>org.hibernate.UserType</literal>.Cette approche libère le code de l'application
+ de l'implémentation des transformations vers / depuis les types Hibernate.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Utilisez du JDBC pur dans les goulets d'étranglement.</term>
+ <listitem>
+ <para>
+ Dans certaines parties critiques de votre système d'un point de vue performance, quelques opérations
+ peuvent tirer partie d'un appel JDBC natif.
+ Mais attendez de <emphasis>savoir</emphasis>
+ que c'est un goulet d'étranglement. Ne supposez jamais qu'un appel JDBC sera forcément plus
+ rapide. Si vous avez besoin d'utiliser JDBC directement, ouvrez une <literal>Session</literal>
+ Hibernate et utilisez la connexion SQL sous-jacente. Ainsi vous pourrez utiliser la même stratégie
+ de transation et la même gestion des connexions.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Comprendre le flush de <literal>Session</literal>.</term>
+ <listitem>
+ <para>
+ De temps en temps la Session synchronise ses états persistants avec la base de données.
+ Les performances seront affectées si ce processus arrive trop souvent. Vous pouvez parfois
+ minimiser les flush non nécessaires en désactivant le flush automatique ou même en changeant
+ l'ordre des opérations menées dans une transaction particulière.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Dans une architecture à trois couches, pensez à utiliser <literal>saveOrUpdate()</literal>.</term>
+ <listitem>
+ <para>
+ Quand vous utilisez une architecture à base de servlet / session bean, vous pourriez passer
+ des objets chargés dans le bean session vers et depuis la couche servlet / JSP. Utilisez
+ une nouvelle session pour traiter chaque requête.
+ Utilisez <literal>Session.merge()</literal> ou <literal>Session.saveOrUpdate()</literal> pour
+ synchroniser les objets avec la base de données.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Dans une architecture à deux couches, pensez à utiliser la déconnexion de session.</term>
+ <listitem>
+ <para>
+ Les transactions de bases de données doivent être aussi courtes que possible
+ pour une meilleure montée en charge.Cependant, il est souvent nécessaire d'implémenter
+ de longues <emphasis>transactions applicatives</emphasis>, une simple unité de travail du point de vue de
+ l'utilisateur. Une transaction applicative
+ peut s'étaler sur plusieurs cycles de requêtes/réponses du client.
+ Il est commun d'utiliser des objets détachés pour implémenter des transactions applicatives.
+ Une alternative, extrêmement appropriée dans une architecture à 2 couches, est de
+ maintenir un seul contact de persistance ouvert (session) pour toute la durée de vie
+ de la transaction applicative et simplement se déconnecter de la connexion JDBC à la fin de chaque requête,
+ et se reconnecter au début de la requête suivante. Ne partagez jamais une seule
+ session avec plus d'une transaction applicative, ou vous travaillerez avec des
+ données périmées.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Considérez que les exceptions ne sont pas rattrapables.</term>
+ <listitem>
+ <para>
+ Il s'agit plus d'une pratique obligatoire que d'une "meilleure pratique". Quand une exception
+ intervient, il faut faire un rollback de la <literal>Transaction</literal> et
+ fermer la <literal>Session</literal>.
+ Sinon, Hibernate ne peut garantir l'intégrité des états persistants en mémoire. En particulier,
+ n'utilisez pas <literal>Session.load()</literal> pour déterminer si une instance avec un identifiant
+ donné existe en base de données, utilisez <literal>Session.get()</literal> ou un requête.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Préférez le chargement tardif des associations.</term>
+ <listitem>
+ <para>
+ Utilisez le chargement complet avec modération.
+ Utilisez les proxies et les collections chargées tardivement
+ pour la plupart des associations vers des classes qui ne sont pas susceptibles
+ d'être complètement retenues dans le cache de second niveau.
+ Pour les assocations de classes en cache, où il y a une extrêmement
+ forte probabilité que l'élément soit en cache, désactivez explicitement le chargement
+ par jointures ouvertes en utilisant <literal>outer-join="false"</literal>.
+ Lorsqu'un chargement par jointure ouverte est approprié pour un cas d'utilisation
+ particulier, utilisez une requête avec un <literal>left join fetch</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ Utilisez le pattern <emphasis>d'une ouverture de session dans une vue</emphasis>,
+ ou une <emphasis>phase d'assemblage</emphasis> disciplinée pour éviter des problèmes
+ avec des données non rapatriées.
+ </term>
+ <listitem>
+ <para>
+ Hibernate libère les développeurs de l'écriture fastidieuse des <emphasis>objets de transfert
+ de données (NdT : Data Transfer Objects)</emphasis> (DTO). Dans une architecture EJB traditionnelle,
+ les DTOs ont deux buts : premièrement, ils contournent le problème des "entity bean" qui ne sont pas
+ sérialisables ; deuxièmement, ils définissent implicitement une phase d'assemblage où toutes les
+ données utilisées par la vue sont rapatriées et organisées dans les DTOs avant de retourner sous le
+ contrôle de la couche de présentation. Hibernate élimine le premier but. Pourtant, vous aurez encore
+ besoin d'une phase d'assemblage (pensez vos méthodes métier comme ayant un contrat strict avec la
+ couche de présentation à propos de quelles données sont disponibles dans les objets détachés)
+ à moins que vous soyez préparés à garder le contexte de
+ persistance (la session) ouvert à travers tout le processus de rendu de la vue.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Pensez à abstraite votre logique métier d'Hibernate.</term>
+ <listitem>
+ <para>
+ Cachez le mécanisme d'accès aux données (Hibernate) derrière une interface. Combinez les patterns
+ <emphasis>DAO</emphasis> et <emphasis>Thread Local Session</emphasis>. Vous pouvez même avoir quelques
+ classes persistées par du JDBC pur, associées à Hibernate via un <literal>UserType</literal> (ce conseil est
+ valable pour des applications de taille respectables ; il n'est pas valable pour une application
+ avec cinq tables).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>N'utilisez pas d'associations de mapping exotiques.</term>
+ <listitem>
+ <para>
+ De bons cas d'utilisation pour de vraies associations plusieurs-vers-plusieurs
+ sont rares. La plupart du temps vous avez besoin d'informations additionnelles
+ stockées dans la table d'association.
+ Dans ce cas, il est préférable d'utiliser deux associations un-vers-plusieurs vers une classe
+ de liaisons intermédiaire. En fait, nous pensons que la plupart des associations sont
+ de type un-vers-plusieurs ou plusieurs-vers-un, vous devez être très attentifs lorsque
+ vous utilisez autre chose et vous demander si c'est vraiment nécessaire.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Préférez les associations bidirectionnelles.</term>
+ <listitem>
+ <para>
+ Les associations unidirectionnelles sont plus difficiles à questionner.
+ Dans une grande application, la plupart des associations devraient être navigables dans les deux directions dans les requêtes.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/collection_mapping.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/collection_mapping.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/collection_mapping.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,1216 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="collections">
+ <title>Mapping des collections</title>
+
+ <sect1 id="collections-persistent" revision="3">
+ <title>Collections persistantes</title>
+
+ <para>
+ Hibernate requiert que les champs contenant des collections persistantes soient déclarés
+ comme des types d'interface, par exemple :
+ </para>
+
+ <programlisting><![CDATA[public class Product {
+ private String serialNumber;
+ private Set parts = new HashSet();
+
+ public Set getParts() { return parts; }
+ void setParts(Set parts) { this.parts = parts; }
+ public String getSerialNumber() { return serialNumber; }
+ void setSerialNumber(String sn) { serialNumber = sn; }
+}]]></programlisting>
+
+ <para>
+ L'interface réelle devrait être <literal>java.util.Set</literal>,
+ <literal>java.util.Collection</literal>, <literal>java.util.List</literal>,
+ <literal>java.util.Map</literal>, <literal>java.util.SortedSet</literal>,
+ <literal>java.util.SortedMap</literal> ou ... n'importe quoi d'autre ! (Où
+ "n'importe quoi d'autre" signifie que vous devrez écrire une implémentation de
+ <literal>org.hibernate.usertype.UserCollectionType</literal>.)
+ </para>
+
+ <para>
+ Notez comment nous avons initialisé les variables d'instance avec une instance de
+ <literal>HashSet</literal>. C'est le meilleur moyen pour initialiser les
+ collections d'instances nouvellement créées (non persistantes). Quand
+ nous fabriquons l'instance persistante - en appelant <literal>persist()</literal>,
+ par exemple - Hibernate remplacera réellement le <literal>HashSet</literal>
+ avec une instance d'une implémentation propre à Hibernate de <literal>Set</literal>.
+ Prenez garde aux erreurs :
+ </para>
+
+ <programlisting><![CDATA[Cat cat = new DomesticCat();
+Cat kitten = new DomesticCat();
+....
+Set kittens = new HashSet();
+kittens.add(kitten);
+cat.setKittens(kittens);
+session.persist(cat);
+kittens = cat.getKittens(); // Ok, la collection kittens est un Set
+(HashSet) cat.getKittens(); // Erreur !]]></programlisting>
+
+ <para>
+ Les collections persistantes injectées par Hibernate se comportent de la même manière que
+ <literal>HashMap</literal>, <literal>HashSet</literal>,
+ <literal>TreeMap</literal>, <literal>TreeSet</literal> ou
+ <literal>ArrayList</literal>, selon le type de l'interface.
+ </para>
+
+ <para>
+ Les instances des collections ont le comportement habituel des types des valeurs.
+ Elles sont automatiquement persistées quand elles sont référencées par un objet persistant et
+ automatiquement effacées quand elles sont déréférencées. Si une collection est passée
+ d'un objet persistant à un autre, ses éléments pourraient être déplacés d'une table
+ à une autre. Deux entités ne peuvent pas partager une référence vers une même instance
+ d'une collection. Dû au modèle relationnel sous-jacent, les propriétés contenant des
+ collections ne supportent pas la sémantique de la valeur null ; Hibernate ne distingue pas
+ une référence vers une collection nulle d'une collection vide.
+ </para>
+
+ <para>
+ Vous ne devriez pas vous préoccuper trop de ça. Utilisez les collections persistantes de
+ la même manière que vous utilisez des collections Java ordinaires. Assurez-vous
+ de comprendre la sémantique des associations bidirectionnelles (traitée plus loin).
+ </para>
+
+ </sect1>
+
+ <sect1 id="collections-mapping" revision="4">
+ <title>Mapper une collection</title>
+
+ <para>
+ L'élément de mapping d'Hibernate utilisé pour mapper une collection dépend du type de
+ l'interface. Par exemple, un élément <literal><set></literal> est utilisé
+ pour mapper des propriétés de type <literal>Set</literal>.
+ </para>
+
+ <programlisting><![CDATA[<class name="Product">
+ <id name="serialNumber" column="productSerialNumber"/>
+ <set name="parts">
+ <key column="productSerialNumber" not-null="true"/>
+ <one-to-many class="Part"/>
+ </set>
+</class>]]></programlisting>
+
+ <para>
+ À part <literal><set></literal>, il y aussi les éléments de mapping
+ <literal><list></literal>, <literal><map></literal>,
+ <literal><bag></literal>, <literal><array></literal> et
+ <literal><primitive-array></literal>.
+ L'élément <literal><map></literal> est représentatif :
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="mappingcollection1" coords="2 65"/>
+ <area id="mappingcollection2" coords="3 65"/>
+ <area id="mappingcollection3" coords="4 65"/>
+ <area id="mappingcollection4" coords="5 65"/>
+ <area id="mappingcollection5" coords="6 65"/>
+ <area id="mappingcollection6" coords="7 65"/>
+ <area id="mappingcollection7" coords="8 65"/>
+ <area id="mappingcollection8" coords="9 65"/>
+ <area id="mappingcollection9" coords="10 65"/>
+ <area id="mappingcollection10" coords="11 65"/>
+ <area id="mappingcollection11" coords="12 65"/>
+ <area id="mappingcollection12" coords="13 65"/>
+ <area id="mappingcollection13" coords="14 65"/>
+ <area id="mappingcollection14" coords="15 65"/>
+ </areaspec>
+ <programlisting><![CDATA[<map
+ name="nomDePropriete"
+ table="nom_de_table"
+ schema="nom_du_schema"
+ lazy="true|extra|false"
+ inverse="true|false"
+ cascade="all|none|save-update|delete|all-delete-orphan"
+ sort="unsorted|natural|ClasseDeComparateur"
+ order-by="nom_de_column asc|desc"
+ where="condition sql where quelcconque"
+ fetch="join|select|subselect"
+ batch-size="N"
+ access="field|property|NomDeClasse"
+ optimistic-lock="true|false"
+ mutable="true|false"
+ node="nom-d-element|."
+ embed-xml="true|false"
+>
+
+ <key .... />
+ <map-key .... />
+ <element .... />
+</map>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="mappingcollection1">
+ <para>
+ <literal>name</literal> : le nom de la propriété contenant la collection
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection2">
+ <para>
+ <literal>table</literal> (optionnel - par défaut = nom de la propriété) : le
+ nom de la table de la collection (non utilisé pour les associations one-to-many)
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection3">
+ <para>
+ <literal>schema</literal> (optionnel) : le nom du schéma pour surcharger le
+ schéma déclaré dans l'élément racine
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection4">
+ <para>
+ <literal>lazy</literal> (optionnel - par défaut = <literal>true</literal>) :
+ peut être utilisé pour désactiver l'initialisation tardive et spécifier
+ que l'association est toujours rapportée, ou pour activer la
+ récupération extra-paresseuse (NdT : extra-lazy) où la plupart des
+ opérations n'initialisent pas la collection (approprié pour de très
+ grosses collections)
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection5">
+ <para>
+ <literal>inverse</literal> (optionnel - par défaut = <literal>false</literal>) :
+ définit cette collection comme l'extrêmité "inverse" de l'association
+ bidirectionnelle
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection6">
+ <para>
+ <literal>cascade</literal> (optionnel - par défaut = <literal>none</literal>) :
+ active les opérations de cascade vers les entités filles
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection7">
+ <para>
+ <literal>sort</literal> (optionnel) : spécifie une collection triée via un ordre
+ de tri <literal>naturel</literal>, ou via une classe comparateur donnée (implémentant Comparator)
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection8">
+ <para>
+ <literal>order-by</literal> (optionnel, seulement à partir du JDK1.4) :
+ spécifie une colonne de table
+ (ou des colonnes) qui définit l'ordre d'itération de <literal>Map</literal>, <literal>Set</literal>
+ ou Bag, avec en option <literal>asc</literal> ou <literal>desc</literal>
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection9">
+ <para>
+ <literal>where</literal> (optionnel) : spécifie une condition SQL arbitraire <literal>WHERE</literal>
+ à utiliser au chargement ou à la suppression d'une collection (utile si la collection
+ ne doit contenir qu'un sous ensemble des données disponibles)
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection10">
+ <para>
+ <literal>fetch</literal> (optionnel, par défaut = <literal>select</literal>) :
+ à choisir entre récupération par jointures externes, récupération par
+ selects séquentiels, et récupération par sous-selects séquentiels
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection11">
+ <para>
+ <literal>batch-size</literal> (optionnel, par défaut = <literal>1</literal>) : une taille
+ de batch (batch size) utilisée pour charger plusieurs instances de cette collection en
+ initialisation tardive
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection12">
+ <para>
+ <literal>access</literal> (optionnel - par défaut = <literal>property</literal>) : La
+ stratégie qu'Hibernate doit utiliser pour accéder à la valeur de la propriété
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection13">
+ <para>
+ <literal>optimistic-lock</literal> (optionnel - par défaut = <literal>true</literal>) :
+ spécifie que changer l'état de la collection entraîne l'incrémentation
+ de la version appartenant à l'entité (Pour une association un vers plusieurs,
+ il est souvent raisonnable de désactiver ce paramètre)
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection14">
+ <para>
+ <literal>mutable</literal> (optionnel - par défaut = <literal>true</literal>) :
+ une valeur à <literal>false</literal> spécifie que les éléments de la
+ collection ne changent jamais (une optimisation mineure dans certains cas)
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <sect2 id="collections-foreignkeys" >
+ <title>Les clefs étrangères d'une collection</title>
+
+ <para>
+ Les instances d'une collection sont distinguées dans la base par la clef étrangère
+ de l'entité qui possède la collection. Cette clef étrangère est référencée comme la(es)
+ <emphasis>colonne(s) de la clef de la collection</emphasis> de la table de la collection.
+ La colonne de la clef de la collection est mappée par l'élément <literal><key></literal>.
+ </para>
+
+ <para>
+ Il peut y avoir une contrainte de nullité sur la colonne de la clef étrangère. Pour les
+ associations unidirectionnelles un vers plusieurs, la colonne de la clef étrangère
+ peut être nulle par défaut, donc vous pourriez avoir besoin de spécifier
+ <literal>not-null="true"</literal>.
+ </para>
+
+ <programlisting><![CDATA[<key column="productSerialNumber" not-null="true"/>]]></programlisting>
+
+ <para>
+ La contraite de la clef étrangère peut utiliser <literal>ON DELETE CASCADE</literal>.
+ </para>
+
+ <programlisting><![CDATA[<key column="productSerialNumber" on-delete="cascade"/>]]></programlisting>
+
+ <para>
+ Voir le chapitre précédent pour une définition complète de l'élément <literal><key></literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="collections-elements" >
+ <title>Les éléments d'une collection</title>
+
+ <para>
+ Les collections peuvent contenir la plupart des autres types Hibernate, dont tous les types
+ basiques, les types utilisateur, les composants, et bien sûr, les références vers
+ d'autres entités. C'est une distinction importante : un objet dans une collection
+ pourrait être géré avec une sémantique de "valeur" (sa durée de vie dépend complètement
+ du propriétaire de la collection) ou il pourrait avoir une référence vers une autre
+ entité, avec sa propre durée de vie. Dans le dernier cas, seul le "lien" entre les 2 objets
+ est considéré être l'état retenu par la collection.
+ </para>
+
+ <para>
+ Le type contenu est référencé comme le <emphasis>type de l'élément de la collection</emphasis>.
+ Les éléments de la collections sont mappés par <literal><element></literal> ou
+ <literal><composite-element></literal>, ou dans le cas des références d'entité, avec
+ <literal><one-to-many></literal> ou <literal><many-to-many></literal>.
+ Les deux premiers mappent des éléments avec un sémantique de valeur, les deux suivants sont
+ utilisés pour mapper des associations d'entité.
+ </para>
+
+ </sect2>
+
+ <sect2 id="collections-indexed">
+ <title>Collections indexées</title>
+
+ <para>
+ Tous les mappings de collection, exceptés ceux avec les sémantiques d'ensemble (NdT : set) et
+ de sac (NdT : bag), ont besoin d'une <emphasis>colonne d'index</emphasis> dans la
+ table de la collection - une colonne qui mappe un index de tableau, ou un index de
+ <literal>List</literal>, ou une clef de <literal>Map</literal>. L'index d'une
+ <literal>Map</literal> peut être n'importe quel type basique, mappé avec
+ <literal><map-key></literal>, ça peut être une référence d'entité mappée avec
+ <literal><map-key-many-to-many></literal>, ou ça peut être un type composé, mappé avec
+ <literal><composite-map-key></literal>. L'index d'un tableau ou d'une liste est toujours
+ de type <literal>integer</literal> et est mappé en utilisant l'élément <literal><list-index></literal>.
+ Les colonnes mappées contiennent des entiers séquentiels (numérotés à partir de zéro par défaut).
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="index1" coords="2 45"/>
+ <area id="index2" coords="3 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<list-index
+ column="nom_de_colonne"
+ base="0|1|..."/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="index1">
+ <para>
+ <literal>nom_de_colonne</literal> (requis) : le nom de la colonne contenant les valeurs de l'index de la collection
+ </para>
+ </callout>
+ <callout arearefs="index1">
+ <para>
+ <literal>base</literal> (optionnel, par défaut = <literal>0</literal>) : la valeur
+ de la colonne de l'index qui correspond au premier élément de la liste ou du tableau
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <programlistingco>
+ <areaspec>
+ <area id="mapkey1" coords="2 45"/>
+ <area id="mapkey2" coords="3 45"/>
+ <area id="mapkey3" coords="4 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<map-key
+ column="nom_de_colonne"
+ formula="n'importe quelle expression SQL"
+ type="nom_du_type"
+ node="@nom-d-attribut"
+ length="N"/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="mapkey1">
+ <para>
+ <literal>column</literal> (optionnel) :
+ le nom de la colonne contenant les valeurs de l'index de la collection
+ </para>
+ </callout>
+ <callout arearefs="mapkey2">
+ <para>
+ <literal>formula</literal> (optionnel) :
+ une formule SQL utilisée pour évaluer la clef de la map
+ </para>
+ </callout>
+ <callout arearefs="mapkey3">
+ <para>
+ <literal>type</literal> (reguis): le type des clefs de la map
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <programlistingco>
+ <areaspec>
+ <area id="indexmanytomany1" coords="2 45"/>
+ <area id="indexmanytomany2" coords="3 45"/>
+ <area id="indexmanytomany3" coords="3 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<map-key-many-to-many
+ column="nom_de_colonne"
+ formula="n'importe quelle expression SQL"
+ class="NomDeClasse"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="indexmanytomany1">
+ <para>
+ <literal>column</literal> (optionnel) :
+ le nom de la colonne de la clef étrangère pour les valeurs de l'index de la collection
+ </para>
+ </callout>
+ <callout arearefs="indexmanytomany2">
+ <para>
+ <literal>formula</literal> (optionnel) :
+ une formulre SQL utilisée pour évaluer la clef étrangère de la clef de la map
+ </para>
+ </callout>
+ <callout arearefs="indexmanytomany3">
+ <para>
+ <literal>class</literal> (requis): la classe de l'entité utilisée comme clef de la map
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Si votre table n'a pas de colonne d'index, et que vous souhaitez tout de même utiliser
+ <literal>List</literal> comme type de propriété, vous devriez mapper la propriété comme un
+ <emphasis><bag></emphasis> Hibernate. Un sac (NdT : bag) ne garde pas son ordre quand
+ il est récupéré de la base de données, mais il peut être optionnellement trié ou ordonné.
+ </para>
+
+ </sect2>
+
+ <para>
+ Il y a pas mal de variétés de mappings qui peuvent être générés pour les collections,
+ couvrant beaucoup des modèles relationnels communs. Nous vous suggérons d'expérimenter avec l'outil de
+ génération de schéma pour avoir une idée de comment traduire les différentes déclarations de mapping vers des table de la base de données.
+ </para>
+
+ <sect2 id="collections-ofvalues" revision="2">
+ <title>Collections de valeurs et associations plusieurs-vers-plusieurs</title>
+
+ <para>
+ N'importe quelle collection de valeurs ou association plusieurs-vers-plusieurs requiert une
+ <emphasis>table de collection</emphasis> avec une(des) colonne(s) de clef étrangère, une(des)
+ <emphasis>colonne(s) d'élément de la collection</emphasis> ou des colonnes et possiblement
+ une(des) colonne(s) d'index.
+ </para>
+
+ <para>
+ Pour une collection de valeurs, nous utilisons la balise <literal><element></literal>.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="element1b" coords="2 50"/>
+ <area id="element2b" coords="3 50"/>
+ <area id="element3b" coords="4 50"/>
+ </areaspec>
+ <programlisting><![CDATA[<element
+ column="nom_de_colonne"
+ formula="n'importe quelle expression SQL"
+ type="nomDeType"
+ length="L"
+ precision="P"
+ scale="S"
+ not-null="true|false"
+ unique="true|false"
+ node="nom-d-element"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="element1b">
+ <para>
+ <literal>column</literal> (optionnel) : le nom de la colonne contenant les valeurs de l'élément de la collection
+ </para>
+ </callout>
+ <callout arearefs="element2b">
+ <para>
+ <literal>formula</literal> (optionnel) : une formule SQL utilisée pour évaluer l'élément
+ </para>
+ </callout>
+ <callout arearefs="element3b">
+ <para>
+ <literal>type</literal> (requis) : le type de l'élément de la collection
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Une <emphasis>association plusieurs-vers-plusieurs</emphasis> est spécifiée en
+ utilisant l'élément <literal><many-to-many></literal>.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="manytomany1" coords="2 60"/>
+ <area id="manytomany2" coords="3 60"/>
+ <area id="manytomany3" coords="4 60"/>
+ <area id="manytomany4" coords="5 60"/>
+ <area id="manytomany5" coords="6 60"/>
+ <area id="manytomany6" coords="7 60"/>
+ <area id="manytomany7" coords="8 60"/>
+ <area id="manytomany8" coords="9 60"/>
+ </areaspec>
+ <programlisting><![CDATA[<many-to-many
+ column="nom_de_colonne"
+ formula="n'importe quelle expression SQL"
+ class="NomDeClasse"
+ fetch="select|join"
+ unique="true|false"
+ not-found="ignore|exception"
+ entity-name="NomDEntite"
+ property-ref="nomDeProprieteDeLaClasseAssociee"
+ node="nom-d-element"
+ embed-xml="true|false"
+ />]]></programlisting>
+ <calloutlist>
+ <callout arearefs="manytomany1">
+ <para>
+ <literal>column</literal> (optionnel) : le nom de la colonne de la clef étrangère de l'élément
+ </para>
+ </callout>
+ <callout arearefs="manytomany2">
+ <para>
+ <literal>formula</literal> (optionnel) :
+ une formule SQL utilisée pour évaluer la valeur de la clef étrangère de l'élément
+ </para>
+ </callout>
+ <callout arearefs="manytomany3">
+ <para>
+ <literal>class</literal> (requis) : le nom de la classe associée
+ </para>
+ </callout>
+ <callout arearefs="manytomany4">
+ <para>
+ <literal>fetch</literal> (optionnel - par défaut <literal>join</literal>) :
+ active les récupérations par jointures externes ou par selects séquentiels pour cette association.
+ C'est un cas spécial ; pour une récupération complète sans attente (dans un seul <literal>SELECT</literal>) d'une
+ entité et de ses relations plusieurs-vers-plusieurs vers d'autres entités,
+ vous devriez activer la récupération <literal>join</literal> non seulement sur
+ la collection elle-même, mais aussi avec cet attribut sur l'élément imbriqué
+ <literal><many-to-many></literal>.
+ </para>
+ </callout>
+ <callout arearefs="manytomany5">
+ <para>
+ <literal>unique</literal> (optionnel) : activer la génération DDL d'une
+ contrainte d'unicité pour la colonne de la clef étrangère. Ça rend la pluralité
+ de l'association effectivement un-vers-plusieurs.
+ </para>
+ </callout>
+ <callout arearefs="manytomany6">
+ <para>
+ <literal>not-found</literal> (optionnel - par défaut <literal>exception</literal>) :
+ spécifie comment les clefs étrangères qui référencent la lignes
+ manquantes seront gérées : <literal>ignore</literal> traitera
+ une ligne manquante comme une association nulle.
+ </para>
+ </callout>
+ <callout arearefs="manytomany7">
+ <para>
+ <literal>entity-name</literal> (optionnel) : le nom de l'entité de la classe associée, comme une alternative à <literal>class</literal>
+ </para>
+ </callout>
+ <callout arearefs="manytomany8">
+ <para>
+ <literal>property-ref</literal> (optionnel) : le nom d'une propriété de
+ la classe associée qui est jointe à cette clef étrangère. Si non spécifiée,
+ la clef primaire de la classe associée est utilisée.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Quelques exemples, d'abord, un ensemble de chaînes de caractères :
+ </para>
+
+ <programlisting><![CDATA[<set name="names" table="person_names">
+ <key column="person_id"/>
+ <element column="person_name" type="string"/>
+</set>]]></programlisting>
+
+ <para>
+ Un bag contenant des entiers (avec un ordre d'itération déterminé par l'attribut <literal>order-by</literal>) :
+ </para>
+
+ <programlisting><![CDATA[<bag name="sizes"
+ table="item_sizes"
+ order-by="size asc">
+ <key column="item_id"/>
+ <element column="size" type="integer"/>
+</bag>]]></programlisting>
+
+ <para>
+ Un tableau d'entités - dans ce cas, une association plusieurs-vers-plusieurs :
+ </para>
+
+ <programlisting><![CDATA[<array name="addresses"
+ table="PersonAddress"
+ cascade="persist">
+ <key column="personId"/>
+ <list-index column="sortOrder"/>
+ <many-to-many column="addressId" class="Address"/>
+</array>]]></programlisting>
+
+ <para>
+ Une map de chaînes de caractères vers des dates :
+ </para>
+
+ <programlisting><![CDATA[<map name="holidays"
+ table="holidays"
+ schema="dbo"
+ order-by="hol_name asc">
+ <key column="id"/>
+ <map-key column="hol_name" type="string"/>
+ <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+ <para>
+ Une liste de composants (discute dans le prochain chapitre) :
+ </para>
+
+ <programlisting><![CDATA[<list name="carComponents"
+ table="CarComponents">
+ <key column="carId"/>
+ <list-index column="sortOrder"/>
+ <composite-element class="CarComponent">
+ <property name="price"/>
+ <property name="type"/>
+ <property name="serialNumber" column="serialNum"/>
+ </composite-element>
+</list>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="collections-onetomany">
+ <title>Association un-vers-plusieurs</title>
+
+ <para>
+ Une <emphasis>association un vers plusieurs</emphasis> lie les tables de deux classes
+ par une clef étrangère, sans l'intervention d'une table de collection. Ce mapping perd certaines sémantiques des collections Java normales :
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Une instance de la classe de l'entité contenue ne peut pas appartenir à plus d'une
+ instance de la collection
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Une instance de la classe de l'entité contenue ne peut pas apparaître plus plus d'une valeur d'index de la collection
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Une association de <literal>Product</literal> vers <literal>Part</literal> requiert l'existence d'une
+ clef étrangère et possiblement une colonne d'index pour la table <literal>Part</literal>. Une balise
+ <literal><one-to-many></literal> indique que c'est une association un vers plusieurs.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="onetomany1" coords="2 60"/>
+ <area id="onetomany2" coords="3 60"/>
+ <area id="onetomany3" coords="4 60"/>
+ </areaspec>
+ <programlisting><![CDATA[<one-to-many
+ class="NomDeClasse"
+ not-found="ignore|exception"
+ entity-name="NomDEntite"
+ node="nom-d-element"
+ embed-xml="true|false"
+ />]]></programlisting>
+ <calloutlist>
+ <callout arearefs="onetomany1">
+ <para>
+ <literal>class</literal> (requis) : le nom de la classe associée
+ </para>
+ </callout>
+ <callout arearefs="onetomany2">
+ <para>
+ <literal>not-found</literal> (optionnel - par défaut <literal>exception</literal>) :
+ spécifie comment les identifiants cachés qui référencent des lignes manquantes seront gérés :
+ <literal>ignore</literal> traitera une ligne manquante comme une association nulle
+ </para>
+ </callout>
+ <callout arearefs="onetomany3">
+ <para>
+ <literal>entity-name</literal> (optionnel) : le nom de l'entité de la
+ classe associée, comme une alternative à <literal>class</literal>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Notez que l'élément <literal><one-to-many></literal> n'a pas besoin de déclarer de colonnes. Il n'est pas non plus nécessaire de spécifier le nom de la table nulle part.
+ </para>
+
+ <para>
+ <emphasis>Note très importante :</emphasis> si la colonne de la clef d'une association
+ <literal><one-to-many></literal> est déclarée <literal>NOT NULL</literal>, vous devez déclarer le
+ mapping de <literal><key></literal> avec <literal>not-null="true"</literal> ou
+ <emphasis>utiliser une association bidirectionnelle</emphasis> avec le mapping de la
+ collection marqué <literal>inverse="true"</literal>. Voir la discussion sur les associations bidirectionnelles plus tard dans ce chapitre.
+ </para>
+
+ <para>
+ Cet exemple montre une map d'entités <literal>Part</literal> par nom (où
+ <literal>partName</literal> est une propriété persistante de <literal>Part</literal>).
+ Notez l'utilisation d'un index basé sur une formule.
+ </para>
+
+ <programlisting><![CDATA[<map name="parts"
+ cascade="all">
+ <key column="productId" not-null="true"/>
+ <map-key formula="partName"/>
+ <one-to-many class="Part"/>
+</map>]]></programlisting>
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="collections-advancedmappings">
+ <title>Mappings de collection avancés</title>
+
+ <sect2 id="collections-sorted" revision="2">
+ <title>Collections triées</title>
+
+ <para>
+ Hibernate supporte des collections implémentant <literal>java.util.SortedMap</literal> et
+ <literal>java.util.SortedSet</literal>. Vous devez spécifier un comparateur dans le fichier de mapping :
+ </para>
+
+ <programlisting><![CDATA[<set name="aliases"
+ table="person_aliases"
+ sort="natural">
+ <key column="person"/>
+ <element column="name" type="string"/>
+</set>
+
+<map name="holidays" sort="my.custom.HolidayComparator">
+ <key column="year_id"/>
+ <map-key column="hol_name" type="string"/>
+ <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+ <para>
+ Les valeurs permises pour l'attribut <literal>sort</literal> sont <literal>unsorted</literal>,
+ <literal>natural</literal> et le nom d'une classe implémentant
+ <literal>java.util.Comparator</literal>.
+ </para>
+
+ <para>
+ Les collections triées se comportent réellement comme <literal>java.util.TreeSet</literal> ou
+ <literal>java.util.TreeMap</literal>.
+ </para>
+
+ <para>
+ Si vous voulez que la base de données elle-même ordonne les éléments de la collection, utilisez l'attribut
+ <literal>order-by</literal> des mappings <literal>set</literal>, <literal>bag</literal>
+ ou <literal>map</literal>. Cette solution est seulement disponible à partir du JDK 1.4 (c'est
+ implémenté en utilisant <literal>LinkedHashSet</literal> ou
+ <literal>LinkedHashMap</literal>). Ceci exécute le tri dans la requête SQL, pas en mémoire.
+ </para>
+
+ <programlisting><![CDATA[<set name="aliases" table="person_aliases" order-by="lower(name) asc">
+ <key column="person"/>
+ <element column="name" type="string"/>
+</set>
+
+<map name="holidays" order-by="hol_date, hol_name">
+ <key column="year_id"/>
+ <map-key column="hol_name" type="string"/>
+ <element column="hol_date type="date"/>
+</map>]]></programlisting>
+
+ <para>
+ Notez que la valeur de l'attribut <literal>order-by</literal> est un ordre SQL, pas un ordre HQL !
+ </para>
+
+ <para>
+ Les associations peuvent même être triées sur des critères arbitraires à l'exécution en utilisant un <literal>filter()</literal> de collection.
+ </para>
+
+ <programlisting><![CDATA[sortedUsers = s.createFilter( group.getUsers(), "order by this.name" ).list();]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="collections-bidirectional" revision="1">
+ <title>Associations bidirectionnelles</title>
+
+ <para>
+ Une <emphasis>association bidirectionnelle</emphasis> permet une navigation à
+ partir de la "fin" de l'association. Deux sortes d'associations bidirectionnelles sont supportées :
+ <variablelist>
+ <varlistentry>
+ <term>un-vers-plusieurs (NdT : one-to-many)</term>
+ <listitem>
+ <para>
+ ensemble ou sac à une extrémité, une seule valeur à l'autre
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>plusieurs-vers-plusieurs (NdT : many-to-many)</term>
+ <listitem>
+ <para>
+ ensemble ou sac aux deux extrémités
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
+ <para>
+ Vous pouvez spécifier une association plusieurs-vers-plusieurs bidirectionnelle simplement
+ en mappant deux associations plusieurs-vers-plusieurs vers la même table de base de données et en déclarant une extrémité comme <emphasis>inverse</emphasis> (celle de votre choix, mais ça ne peut pas être une collection indexée).
+ </para>
+
+ <para>
+ Voici un exemple d'association bidirectionnelle plusieurs-vers-plusieurs ; chaque catégorie peut
+ avoir plusieurs objets et chaque objet peut être dans plusieurs catégories :
+ </para>
+
+ <programlisting><![CDATA[<class name="Category">
+ <id name="id" column="CATEGORY_ID"/>
+ ...
+ <bag name="items" table="CATEGORY_ITEM">
+ <key column="CATEGORY_ID"/>
+ <many-to-many class="Item" column="ITEM_ID"/>
+ </bag>
+</class>
+
+<class name="Item">
+ <id name="id" column="CATEGORY_ID"/>
+ ...
+
+ <!-- inverse end -->
+ <bag name="categories" table="CATEGORY_ITEM" inverse="true">
+ <key column="ITEM_ID"/>
+ <many-to-many class="Category" column="CATEGORY_ID"/>
+ </bag>
+</class>]]></programlisting>
+
+ <para>
+ Les changements faits uniquement sur l'extréminté inverse de l'association <emphasis>ne sont pas</emphasis>
+ persistés. Ceci signifie qu'Hibernate a deux représentations en mémoire pour chaque
+ association bidirectionnelles, un lien de A vers B et un autre de B vers A. C'est
+ plus facile à comprendre si vous pensez au modèle objet de Java et comment nous
+ créons une relation plusieurs-vers-plusieurs en Java :
+ </para>
+
+ <programlisting><![CDATA[
+category.getItems().add(item); // La catégorie est maintenant "au courant" de la relation
+item.getCategories().add(category); // L'objet est maintenant "au courant" de la relation
+
+session.persist(item); // La relation ne sera pas sauvegardée !
+session.persist(category); // La relation sera sauvegardée]]></programlisting>
+
+ <para>
+ La partie non-inverse est utilisée pour sauvegarder la représentation en mémoire dans la base de données.
+ </para>
+
+ <para>
+ Vous pouvez définir une association un-vers-plusieurs bidirectionnelle en mappant une
+ association un-vers-plusieurs vers la(es) même(s) colonne(s) de table qu'une association
+ plusieurs-vers-un et en déclarant l'extrémité pluri-valuée <literal>inverse="true"</literal>.
+ </para>
+
+ <programlisting><![CDATA[<class name="Parent">
+ <id name="id" column="parent_id"/>
+ ....
+ <set name="children" inverse="true">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+ </set>
+</class>
+
+<class name="Child">
+ <id name="id" column="child_id"/>
+ ....
+ <many-to-one name="parent"
+ class="Parent"
+ column="parent_id"
+ not-null="true"/>
+</class>]]></programlisting>
+
+ <para>
+ Mapper une extrémité d'une association avec <literal>inverse="true"</literal> n'affecte
+ pas l'opération de cascades, ce sont des concepts orthogonaux !
+ </para>
+
+ </sect2>
+
+ <sect2 id="collections-indexedbidirectional">
+ <title>Associations bidirectionnelles avec des collections indexées</title>
+ <para>
+ Une association bidirectionnelle où une extrémité est représentée comme une <literal><list></literal>
+ ou une <literal><map></literal> requiert une considération spéciale. Si il y a une
+ propriété de la classe enfant qui mappe la colonne de l'index, pas de problème, nous pouvons
+ continuer à utiliser <literal>inverse="true"</literal> sur le mapping de la collection :
+ </para>
+
+ <programlisting><![CDATA[<class name="Parent">
+ <id name="id" column="parent_id"/>
+ ....
+ <map name="children" inverse="true">
+ <key column="parent_id"/>
+ <map-key column="name"
+ type="string"/>
+ <one-to-many class="Child"/>
+ </map>
+</class>
+
+<class name="Child">
+ <id name="id" column="child_id"/>
+ ....
+ <property name="name"
+ not-null="true"/>
+ <many-to-one name="parent"
+ class="Parent"
+ column="parent_id"
+ not-null="true"/>
+</class>]]></programlisting>
+
+ <para>
+ Mais, si il n'y a pas de telle prorpriété sur la classe enfant, nous ne pouvons pas penser
+ à l'association comme vraiment bidirectionnelle (il y a des informations disponibles à une
+ extrémité de l'association qui ne sont pas disponibles à l'autre extrémité). Dans ce cas,
+ nous ne pouvons pas mapper la collection <literal>inverse="true"</literal>. À la place, nous
+ pourrions utiliser le mapping suivant :
+ </para>
+
+ <programlisting><![CDATA[<class name="Parent">
+ <id name="id" column="parent_id"/>
+ ....
+ <map name="children">
+ <key column="parent_id"
+ not-null="true"/>
+ <map-key column="name"
+ type="string"/>
+ <one-to-many class="Child"/>
+ </map>
+</class>
+
+<class name="Child">
+ <id name="id" column="child_id"/>
+ ....
+ <many-to-one name="parent"
+ class="Parent"
+ column="parent_id"
+ insert="false"
+ update="false"
+ not-null="true"/>
+</class>]]></programlisting>
+
+ <para>
+ Notez que dans ce mapping, l'extrémité de l'association contenant la collection est responsable
+ des mises à jour de la clef étrangère. À faire : cela entraîne-t-il réellement des expressions
+ updates inutiles ?
+ </para>
+
+ </sect2>
+
+ <sect2 id="collections-ternary">
+ <title>Associations ternaires</title>
+
+ <para>
+ Il y a trois approches possibles pour mapper une association ternaire. L'une est d'utiliser
+ une <literal>Map</literal> avec une association en tant qu'index :
+ </para>
+
+ <programlisting><![CDATA[<map name="contracts">
+ <key column="employer_id" not-null="true"/>
+ <map-key-many-to-many column="employee_id" class="Employee"/>
+ <one-to-many class="Contract"/>
+</map>]]></programlisting>
+
+ <programlisting><![CDATA[<map name="connections">
+ <key column="incoming_node_id"/>
+ <map-key-many-to-many column="outgoing_node_id" class="Node"/>
+ <many-to-many column="connection_id" class="Connection"/>
+</map>]]></programlisting>
+
+ <para>
+ Une seconde approche est simplement de remodeler l'association comme une classe d'entité. C'est
+ l'approche la plus commune.
+ </para>
+
+ <para>
+ Une alternative finale est d'utiliser des éléments composites, dont nous discuterons plus tard.
+ </para>
+
+ </sect2>
+
+ <sect2 id="collections-idbag" revision="1">
+ <title>Utiliser un <literal><idbag></literal></title>
+
+ <para>
+ Si vous embrassez pleinement notre vue que les clefs composées sont une mauvaise
+ chose et que des entités devraient avoir des identifiants artificiels (des clefs
+ subrogées), alors vous pourriez trouver un peu curieux que les associations
+ plusieurs-vers-plusieurs et les collections de valeurs que nous avons montré jusqu'ici
+ mappent toutes des tables avec des clefs composées ! Maintenant, ce point est assez
+ discutable ; une table d'association pure ne semble pas beaucoup bénéficier d'une clef
+ subrogée (bien qu'une collection de valeur composées le <emphasis>pourrait</emphasis>).
+ Néanmoins, Hibernate fournit une foncionnalité qui vous permet de mapper
+ des associations plusieurs-vers-plusieurs et des collections de valeurs vers une
+ table avec une clef subrogée.
+ </para>
+
+ <para>
+ L'élément <literal><idbag></literal> vous laisse mapper une <literal>List</literal>
+ (ou une <literal>Collection</literal>) avec une sémantique de sac.
+ </para>
+
+<programlisting><![CDATA[<idbag name="lovers" table="LOVERS">
+ <collection-id column="ID" type="long">
+ <generator class="sequence"/>
+ </collection-id>
+ <key column="PERSON1"/>
+ <many-to-many column="PERSON2" class="Person" fetch="join"/>
+</idbag>]]></programlisting>
+
+ <para>
+ Comme vous pouvez voir, un <literal><idbag></literal> a un généréteur d'id
+ artificiel, comme une classe d'entité ! Une clef subrogée différente est assignée
+ à chaque ligne de la collection. Cependant, Hibernate ne fournit pas de mécanisme pour
+ découvrir la valeur d'une clef subrogée d'une ligne particulière.
+ </para>
+
+ <para>
+ Notez que les performances de la mise à jour d'un <literal><idbag></literal>
+ sont <emphasis>bien</emphasis> meilleures qu'un <literal><bag></literal> ordinaire !
+ Hibernate peut localiser des lignes individuelles efficacement et les mettre à jour ou
+ les effacer individuellement, comme une liste, une map ou un ensemble.
+ </para>
+
+ <para>
+ Dans l'implémentation actuelle, la stratégie de la génération de l'identifiant <literal>native</literal>
+ n'est pas supportée pour les identifiants de collection <literal><idbag></literal>.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <!--undocumenting this stuff -->
+
+ <!--sect1 id="collections-heterogeneous">
+ <title>Heterogeneous Associations</title>
+
+ <para>
+ The <literal><many-to-any></literal> and <literal><index-many-to-any></literal>
+ elements provide for true heterogeneous associations. These mapping elements work in the
+ same way as the <literal><any></literal> element - and should also be used
+ rarely, if ever.
+ </para>
+
+ </sect1-->
+
+ <sect1 id="collections-example" revision="1">
+ <title>Exemples de collections</title>
+
+ <para>
+ Les sections précédentes sont assez confuses. Donc prenons un exemple. Cette classe :
+ </para>
+
+ <programlisting><![CDATA[package eg;
+import java.util.Set;
+
+public class Parent {
+ private long id;
+ private Set children;
+
+ public long getId() { return id; }
+ private void setId(long id) { this.id=id; }
+
+ private Set getChildren() { return children; }
+ private void setChildren(Set children) { this.children=children; }
+
+ ....
+ ....
+}]]></programlisting>
+
+ <para>
+ a une collection d'instances de <literal>Child</literal>. Si chaque enfant
+ a au plus un parent, le mapping le plus naturel est une association
+ un-vers-plusieurs :
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Parent">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <set name="children">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+ </set>
+ </class>
+
+ <class name="Child">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <property name="name"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Ceci mappe les définitions de tables suivantes :
+ </para>
+
+ <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255), parent_id bigint )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+ <para>
+ Si le parent est <emphasis>requis</emphasis>, utilisez une association un-vers-plusieurs unidirectionnelle :
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Parent">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <set name="children" inverse="true">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+ </set>
+ </class>
+
+ <class name="Child">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <property name="name"/>
+ <many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Notez la contrainte <literal>NOT NULL</literal> :
+ </para>
+
+ <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null
+ primary key,
+ name varchar(255),
+ parent_id bigint not null )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+ <para>
+ Alternativement, si vous insistez absolument pour que cette association soit unidirectionnelle,
+ vous pouvez déclarer la contrainte <literal>NOT NULL</literal> sur le mapping <literal><key></literal> :
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Parent">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <set name="children">
+ <key column="parent_id" not-null="true"/>
+ <one-to-many class="Child"/>
+ </set>
+ </class>
+
+ <class name="Child">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <property name="name"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ D'un autre côté, si un enfant pouvait avoir plusieurs parent, une association
+ plusieurs-vers-plusieurs est plus appropriée :
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Parent">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <set name="children" table="childset">
+ <key column="parent_id"/>
+ <many-to-many class="Child" column="child_id"/>
+ </set>
+ </class>
+
+ <class name="Child">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <property name="name"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Définitions des tables :
+ </para>
+
+ <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255) )
+create table childset ( parent_id bigint not null,
+ child_id bigint not null,
+ primary key ( parent_id, child_id ) )
+alter table childset add constraint childsetfk0 (parent_id) references parent
+alter table childset add constraint childsetfk1 (child_id) references child]]></programlisting>
+
+ <para>
+ Pour plus d'exemples et une revue complète du mapping de la relation parent/enfant, voir
+ see <xref linkend="example-parentchild"/>.
+ </para>
+
+ <para>
+ Des mappings d'association plus exotiques sont possibles, nous cataloguerons toutes les possibilités
+ dans le prochain chapitre.
+ </para>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/component_mapping.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/component_mapping.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/component_mapping.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,402 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+<chapter id="components">
+ <title>Mapping de composants</title>
+
+ <para>
+ La notion de <emphasis>composants</emphasis> est réutilisé dans différents contextes,
+ avec différents objectifs, à travers Hibernate.
+ </para>
+
+ <sect1 id="components-dependentobjects" revision="2" >
+ <title>Objects dépendants</title>
+
+ <para>
+ Le composant est un objet inclu dans un autre qui est sauvegardé comme une valeur, et
+ non pas comme une entité.
+ Le composant fait référence à la notion (au sens objet) de composition
+ (et non pas de composant au sens d'architecture de composants).
+ Par exemple on pourrait modélisé l'objet personne de cette façon:
+ </para>
+
+ <programlisting><![CDATA[public class Person {
+ private java.util.Date birthday;
+ private Name name;
+ private String key;
+ public String getKey() {
+ return key;
+ }
+ private void setKey(String key) {
+ this.key=key;
+ }
+ public java.util.Date getBirthday() {
+ return birthday;
+ }
+ public void setBirthday(java.util.Date birthday) {
+ this.birthday = birthday;
+ }
+ public Name getName() {
+ return name;
+ }
+ public void setName(Name name) {
+ this.name = name;
+ }
+ ......
+ ......
+}]]></programlisting>
+
+<programlisting><![CDATA[public class Name {
+ char initial;
+ String first;
+ String last;
+ public String getFirst() {
+ return first;
+ }
+ void setFirst(String first) {
+ this.first = first;
+ }
+ public String getLast() {
+ return last;
+ }
+ void setLast(String last) {
+ this.last = last;
+ }
+ public char getInitial() {
+ return initial;
+ }
+ void setInitial(char initial) {
+ this.initial = initial;
+ }
+}]]></programlisting>
+
+ <para>
+ Maintenant <literal>Name</literal> peut-être sauvegardé comme un composant de
+ <literal>Person</literal>. Remarquer que <literal>Name</literal> définit des methodes
+ d'accès et de modification pour ses propriétés persistantes, mais il n'a pas besoin
+ des interfaces ou des propriétés d'identification ( par exemple getId() ) qui sont propres aux entités.
+ </para>
+
+ <para>
+ Nous serions alors amené à mapper ce composant de cette façon:
+ </para>
+
+ <programlisting><![CDATA[<class name="eg.Person" table="person">
+ <id name="Key" column="pid" type="string">
+ <generator class="uuid"/>
+ </id>
+ <property name="birthday" type="date"/>
+ <component name="Name" class="eg.Name"> <!-- class attribute optional -->
+ <property name="initial"/>
+ <property name="first"/>
+ <property name="last"/>
+ </component>
+</class>]]></programlisting>
+
+ <para>
+ La table person aurai les colonnes <literal>pid</literal>,
+ <literal>birthday</literal>,
+ <literal>initial</literal>,
+ <literal>first</literal> and
+ <literal>last</literal>.
+ </para>
+
+ <para>
+ Comme tous les types valeurs, les composants ne supportent pas les références partagés.
+ En d'autres mots, deux instances de person peuvent avoir un même nom, mais ces noms sont
+ indépendants, ils peuvent être identiques si on les compare par valeur mais ils représentent
+ deux objets distincts en mémoire. La notion de nullité pour un composant est
+ <emphasis>ad hoc</emphasis>. Quand il recharge l'objet qui contient le composant, Hibernate
+ supposera que si tous les champs du composants sont nuls alors le composant sera positionné
+ à la valeur null. Ce choix programmatif devrait être satisfaisant dans la plupart des cas.
+ </para>
+
+ <para>
+ Les propriétés d'un composant peuvent être de tous les types qu'Hibernate supporte habituellement
+ (collections, many-to-one associations, autres composants, etc). Les composants inclus ne doivent <emphasis>pas</emphasis>
+ être vus comme quelque chose d'exotique. Hibernate a été conçu pour supporter un modèle objet très granulaire.
+ </para>
+
+ <para>
+ Le <literal><component></literal> peut inclure dans la liste de ses propriétés
+ une référence au <literal><parent></literal> conteneur.
+ </para>
+
+ <programlisting><![CDATA[<class name="eg.Person" table="person">
+ <id name="Key" column="pid" type="string">
+ <generator class="uuid"/>
+ </id>
+ <property name="birthday" type="date"/>
+ <component name="Name" class="eg.Name" unique="true">
+ <parent name="namedPerson"/> <!-- référence arrière à Person -->
+ <property name="initial"/>
+ <property name="first"/>
+ <property name="last"/>
+ </component>
+</class>]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="components-incollections" revision="1">
+ <title>Collection d'objets dépendants</title>
+
+ <para>
+ Les collections d'objets dépendants sont supportés (exemple: un tableau de type
+ <literal>Name</literal>). Déclarer la collection de composants en remplaçant le tag <literal><element></literal>
+ par le tag <literal><composite-element></literal>.
+ </para>
+
+ <programlisting><![CDATA[<set name="someNames" table="some_names" lazy="true">
+ <key column="id"/>
+ <composite-element class="eg.Name"> <!-- class attribute required -->
+ <property name="initial"/>
+ <property name="first"/>
+ <property name="last"/>
+ </composite-element>
+</set>]]></programlisting>
+
+ <para>
+ Remarque: Si vous définissez un <literal>Set</literal> d'élément composite,
+ il est très important d'implémenter la méthode <literal>equals()</literal> et
+ <literal>hashCode()</literal> correctement.
+ </para>
+
+ <para>
+ Les élements composite peuvent aussi contenir des composants mais pas des collections.
+ Si votre élément composite contient aussi des composants, utilisez l'élément <literal><nested-composite-element></literal>
+ . Une collections de composants qui ccontiennent eux-mêmes des composants est un cas très exotique.
+ A ce stade demandez-vous si une association un-à-plusieurs ne serait pas plus approprié.
+ Essayez de re remodeler votre élément composite comme une entité ( Dans ce cas même si le modèle
+ Java est le même la logique de persitence et de relation sont tout de même différentes)
+ </para>
+
+ <para>
+ Remarque, le mapping d'éléments composites ne supporte pas la nullité des
+ propriétés lorsqu'on utilise un <literal><set></literal>. Hibernate
+ lorsqu'il supprime un objet utilise chaque colonne pour identifier un objet
+ (on ne peut pas utiliser des clés primaires distinctes dans une table d'éléments composites),
+ ce qui n'est pas possible avec des valeurs nulles. Vous devez donc choisir d'interdire la nullité
+ des propriétés d'un élément composite ou choisir un autre type de collection comme :
+ <literal><list></literal>, <literal><map></literal>,
+ <literal><bag></literal> ou <literal><idbag></literal>.
+ </para>
+
+ <para>
+ Un cas particulier d'élément composite est un élément composite qui inclut un élément
+ <literal><many-to-one></literal>. Un mapping comme celui-ci
+ vous permet d'associer les colonnes d'une table d'association plusieurs à plusieurs (many-to-many)
+ à la classse de l'élément composite. L'exemple suivant est une association plusieurs à plusieurs
+ de <literal>Order</literal> à <literal>Item</literal> à
+ <literal>purchaseDate</literal>, <literal>price</literal> et
+ <literal>quantity</literal> sont des propriétés de l'association.
+ </para>
+
+ <programlisting><![CDATA[<class name="eg.Order" .... >
+ ....
+ <set name="purchasedItems" table="purchase_items" lazy="true">
+ <key column="order_id">
+ <composite-element class="eg.Purchase">
+ <property name="purchaseDate"/>
+ <property name="price"/>
+ <property name="quantity"/>
+ <many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
+ </composite-element>
+ </set>
+</class>]]></programlisting>
+
+ <para>
+ Bien sûr, il ne peut pas y avoir de référence à l'achat (purchase) depuis l'article (item), pour
+ pouvoir naviguer de façon bidirectionnelle dans l'association. N'oubliez pas que les composants
+ sont de type valeurs et n'autorise pas les références partagées.
+ </para>
+
+ <para>Même les associations ternaires ou quaternaires sont possibles:</para>
+
+ <programlisting><![CDATA[<class name="eg.Order" .... >
+ ....
+ <set name="purchasedItems" table="purchase_items" lazy="true">
+ <key column="order_id">
+ <composite-element class="eg.OrderLine">
+ <many-to-one name="purchaseDetails class="eg.Purchase"/>
+ <many-to-one name="item" class="eg.Item"/>
+ </composite-element>
+ </set>
+</class>]]></programlisting>
+
+ <para>
+ Les éléments composites peuvent apparaître dans les requêtes en utilisant
+ la même syntaxe que associations
+ </para>
+
+ </sect1>
+
+ <sect1 id="components-asmapindex">
+ <title>Utiliser les composants comme index de map</title>
+
+ <para>
+ l'élément <literal><composite-map-key></literal>
+ vous permet d'utiliser une classe de composant comme indice de
+ <literal>Map</literal>. Assurez-vous d'avoir surdéfini
+ <literal>hashCode()</literal> et <literal>equals()</literal> dans la
+ classe du composant.
+ </para>
+ </sect1>
+
+ <sect1 id="components-compositeid" revision="1">
+ <title>Utiliser un composant comme identifiant</title>
+
+ <para>
+ Vous pouvez utiliser un composant comme identifiant d'une entité.
+ Mais pour cela la classe du composant doit respecter certaines règles.
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Elle doit implémenter <literal>java.io.Serializable</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Elle doit redéfinir <literal>equals()</literal> et
+ <literal>hashCode()</literal>, de façon cohérente avec le
+ fait qu'elle définit une clé composite dans la base de
+ données.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ <emphasis>
+ Remarque: avec hibernate3, la seconde règle n'est plus absolument
+ necessaire mais faîtes le quand même.</emphasis>
+ </para>
+
+ <para>
+ Vous ne pouvez pas utiliser de <literal>IdentifierGenerator</literal> pour générer
+ une clé composite, l'application devra définir elle même ses propres identifiants.
+ </para>
+
+ <para>
+ Utiliser l'élément <literal><composite-id></literal> (en incluant l'élément
+ <literal><key-property></literal>) à la place de l'habituel déclaration
+ <literal><id></literal>. Par exemple la classe
+ <literal>OrderLine</literal> qui dépend de la clé primaire
+ (composite) de <literal>Order</literal>.
+ </para>
+
+ <programlisting><![CDATA[<class name="OrderLine">
+
+ <composite-id name="id" class="OrderLineId">
+ <key-property name="lineId"/>
+ <key-property name="orderId"/>
+ <key-property name="customerId"/>
+ </composite-id>
+
+ <property name="name"/>
+
+ <many-to-one name="order" class="Order"
+ insert="false" update="false">
+ <column name="orderId"/>
+ <column name="customerId"/>
+ </many-to-one>
+ ....
+
+</class>]]></programlisting>
+
+ <para>
+ Maintenant toutes clés étrangères référençant la table <literal>OrderLine</literal>
+ devra aussi être composite. Vous devez en tenir compte lorsque vous écrivez vos mapping d'association pour les autres classes.
+ Une association à <literal>OrderLine</literal> devrait être mappé de la façon suivante :
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
+<!-- the "class" attribute is optional, as usual -->
+ <column name="lineId"/>
+ <column name="orderId"/>
+ <column name="customerId"/>
+</many-to-one>]]></programlisting>
+
+ <para>
+ (Remarque: l'élément <literal><column></literal> est une alternative à l'attribut
+ <literal>column</literal> que l'on utilise partout.)
+ </para>
+
+ <para>
+ Une association <literal>plusieurs-à-plusieurs</literal> (many-to-many) à <literal>OrderLine</literal>
+ utilisera aussi une clé étrangère composite:
+ </para>
+
+ <programlisting><![CDATA[<set name="undeliveredOrderLines">
+ <key column name="warehouseId"/>
+ <many-to-many class="OrderLine">
+ <column name="lineId"/>
+ <column name="orderId"/>
+ <column name="customerId"/>
+ </many-to-many>
+</set>]]></programlisting>
+
+ <para>
+ La collection des <literal>OrderLine</literal>s dans <literal>Order</literal>
+ utilisera:
+ </para>
+
+ <programlisting><![CDATA[<set name="orderLines" inverse="true">
+ <key>
+ <column name="orderId"/>
+ <column name="customerId"/>
+ </key>
+ <one-to-many class="OrderLine"/>
+</set>]]></programlisting>
+
+ <para>
+ (L'élément <literal><one-to-many></literal>, comme d'habitude, ne déclare pas de colonne.)
+ </para>
+
+ <para>
+ Si <literal>OrderLine</literal> lui-même possède une collection, celle-ci aura aussi
+ une clé composite étrangère.
+ </para>
+
+ <programlisting><![CDATA[<class name="OrderLine">
+ ....
+ ....
+ <list name="deliveryAttempts">
+ <key> <!-- a collection inherits the composite key type -->
+ <column name="lineId"/>
+ <column name="orderId"/>
+ <column name="customerId"/>
+ </key>
+ <list-index column="attemptId" base="1"/>
+ <composite-element class="DeliveryAttempt">
+ ...
+ </composite-element>
+ </set>
+</class>]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="components-dynamic" revision="1">
+ <title>Composant Dynamique</title>
+
+ <para>
+ Vous pouvez même mapper une propriété de type <literal>Map</literal>:
+ </para>
+
+ <programlisting><![CDATA[<dynamic-component name="userAttributes">
+ <property name="foo" column="FOO"/>
+ <property name="bar" column="BAR"/>
+ <many-to-one name="baz" class="Baz" column="BAZ_ID"/>
+</dynamic-component>]]></programlisting>
+
+ <para>
+ La sémantique de l'association à un <literal><dynamic-component></literal>
+ est identique à celle que l'on utilise pour les composants.
+ L'avantage de ce type de mapping est qu'il pemet de déterminer les véritables propriétés
+ du bean au moment su déploiement en éditant simplement le document de mapping.
+ La manipulation du document de mapping pendant l'execution de l'application est aussi
+ possible en utilisant un parser DOM. Il ya même mieux, vous pouvez accéder (et changer)
+ le metamodel de configuration d'hibernate en utilisant l'objet <literal>Configuration</literal>
+ </para>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/configuration.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/configuration.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/configuration.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,1759 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+<chapter id="session-configuration" revision="1">
+
+ <title>Configuration</title>
+
+ <para>
+ Parce qu'Hibernate est conçu pour fonctionner dans différents environnements,
+ il existe beaucoup de paramètres de configuration. Heureusement, la plupart
+ ont des valeurs par défaut appropriées et la distribution d'Hibernate contient
+ un exemple de fichier <literal>hibernate.properties</literal> dans le répertoire
+ <literal>etc/</literal> qui montre les différentes options. Vous n'avez qu'à
+ placer ce fichier dans votre classpath et à l'adapter.
+ </para>
+
+ <sect1 id="configuration-programmatic" revision="1">
+ <title>Configuration par programmation</title>
+
+ <para>
+ Une instance de <literal>org.hibernate.cfg.Configuration</literal>
+ représente un ensemble de mappings des classes Java d'une application vers
+ la base de données SQL. La <literal>Configuration</literal> est utilisée
+ pour construire un objet (immuable) <literal>SessionFactory</literal>.
+ Les mappings sont constitués d'un ensemble de fichiers de mapping XML.
+ </para>
+
+ <para>
+ Vous pouvez obtenir une instance de <literal>Configuration</literal>
+ en l'instanciant directement et en spécifiant la liste des documents
+ XML de mapping. Si les fichiers de mapping sont dans le classpath, vous
+ pouvez le faire à l'aide de la méthode <literal>addResource()</literal> :
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = new Configuration()
+ .addResource("Item.hbm.xml")
+ .addResource("Bid.hbm.xml");]]></programlisting>
+
+ <para>
+ Une alternative (parfois meilleure) est de spécifier les classes mappées
+ et de laisser Hibernate trouver les documents de mapping pour vous :
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = new Configuration()
+ .addClass(org.hibernate.auction.Item.class)
+ .addClass(org.hibernate.auction.Bid.class);]]></programlisting>
+
+ <para>
+ Hibernate va rechercher les fichiers de mappings
+ <literal>/org/hibernate/auction/Item.hbm.xml</literal> et
+ <literal>/org/hibernate/auction/Bid.hbm.xml</literal> dans le classpath.
+ Cette approche élimine les noms de fichiers en dur.
+ </para>
+
+ <para>
+ Une <literal>Configuration</literal> vous permet également de préciser des
+ propriétés de configuration :
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = new Configuration()
+ .addClass(org.hibernate.auction.Item.class)
+ .addClass(org.hibernate.auction.Bid.class)
+ .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
+ .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
+ .setProperty("hibernate.order_updates", "true");]]></programlisting>
+
+ <para>
+ Ce n'est pas le seul moyen de passer des propriétés de configuration à Hibernate.
+ Les différentes options sont :
+ </para>
+
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ Passer une instance de <literal>java.util.Properties</literal>
+ à <literal>Configuration.setProperties()</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Placer <literal>hibernate.properties</literal> dans un répertoire racine
+ du classpath
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Positionner les propriétés <literal>System</literal> en utilisant
+ <literal>java -Dproperty=value</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Inclure des éléments <literal><property></literal> dans le
+ fichier <literal>hibernate.cfg.xml</literal> (voir plus loin).
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ L'utilisation d'<literal>hibernate.properties</literal> est l'approche la plus
+ simple si vous voulez démarrer rapidement
+ </para>
+ <para>
+ La <literal>Configuration</literal> est un objet de démarrage qui sera supprimé
+ une fois qu'une <literal>SessionFactory</literal> aura été créée.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-sessionfactory">
+ <title>Obtenir une SessionFactory</title>
+
+ <para>
+ Une fois que tous les mappings ont été parsés par la <literal>Configuration</literal>,
+ l'application doit obtenir une fabrique d'instances de <literal>Session</literal>.
+ Cette fabrique sera partagée entre tous les threads de l'application :
+ </para>
+
+ <programlisting><![CDATA[SessionFactory sessions = cfg.buildSessionFactory();]]></programlisting>
+
+ <para>
+ Hibernate permet à votre application d'instancier plus d'une <literal>SessionFactory</literal>.
+ Cela est pratique lorsque vous utilisez plus d'une base de données.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-hibernatejdbc" revision="1">
+ <title>Connexions JDBC</title>
+
+ <para>
+ Habituellement, vous voulez que la <literal>SessionFactory</literal> crée les connexions JDBC et
+ les mette dans un pool pour vous. Si vous suivez cette approche, ouvrir une <literal>Session</literal>
+ est aussi simple que :
+ </para>
+
+ <programlisting><![CDATA[Session session = sessions.openSession(); // open a new Session]]></programlisting>
+
+ <para>
+ Dès que vous ferez quelquechose qui requiert un accès à la base de données, une connexion
+ JDBC sera récupérée dans le pool.
+ </para>
+
+ <para>
+ Pour faire cela, il faut passer les propriétés de la connexion JDBC à Hibernate.
+ Tous les noms des propriétés Hibernate et leur signification sont définies dans
+ la classe <literal>org.hibernate.cfg.Environment</literal>. Nous allons maintenant
+ décrire les paramètres de configuration des connexions JDBC les plus importants.
+ </para>
+
+ <para>
+ Hibernate obtiendra des connexions (et les mettra dans un pool) en utilisant
+ <literal>java.sql.DriverManager</literal> si vous positionnez les paramètres de la manière
+ suivante :
+ </para>
+
+ <table frame="topbot">
+ <title>Propriétés JDBC d'Hibernate</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nom de la propriété</entry>
+ <entry>Fonction</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.connection.driver_class</literal>
+ </entry>
+ <entry>
+ <emphasis>Classe du driver jdbc</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.url</literal>
+ </entry>
+ <entry>
+ <emphasis>URL jdbc</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.username</literal>
+ </entry>
+ <entry>
+ <emphasis>utilisateur de la base de données</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.password</literal>
+ </entry>
+ <entry>
+ <emphasis>mot de passe de la base de données</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.pool_size</literal>
+ </entry>
+ <entry>
+ <emphasis>nombre maximum de connexions dans le pool</emphasis>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ L'algorithme natif de pool de connexions d'Hibernate est plutôt rudimentaire. Il a été fait
+ dans le but de vous aider à démarrer et <emphasis>n'est pas prévu pour un système en production</emphasis>
+ ou même pour un test de peformance. Utilisez plutôt un pool tiers pour de meilleures performances et une
+ meilleure stabilité : pour cela, remplacez la propriété <literal>hibernate.connection.pool_size</literal> avec les propriétés
+ spécifique au pool de connexions que vous avez choisi. Cela désactivera le pool de connexions interne
+ d'Hibernate. Vous pouvez par exemple utiliser C3P0.
+ </para>
+
+ <para>
+ C3P0 est un pool de connexions JDBC open source distribué avec Hibernate dans le répertoire
+ <literal>lib</literal>. Hibernate utilisera son provider <literal>C3P0ConnectionProvider</literal>
+ pour le pool de connexions si vous positionnez les propriétés <literal>hibernate.c3p0.*</literal>.
+ Si vous voulez utiliser Proxool, référez vous au groupe de propriétés d'<literal>hibernate.properties</literal>
+ correspondant et regardez sur le site web d'Hibernate pour plus d'informations.
+ </para>
+
+ <para>
+ Voici un exemple de fichier <literal>hibernate.properties</literal> pour C3P0:
+ </para>
+
+ <programlisting id="c3p0-configuration" revision="1"><![CDATA[hibernate.connection.driver_class = org.postgresql.Driver
+hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
+hibernate.connection.username = myuser
+hibernate.connection.password = secret
+hibernate.c3p0.min_size=5
+hibernate.c3p0.max_size=20
+hibernate.c3p0.timeout=1800
+hibernate.c3p0.max_statement=50
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+ <para>
+ Dans le cadre de l'utilisation au sein d'un serveur d'applications,
+ vous devriez quasiment toujours configurer Hibernate pour qu'il obtienne
+ ses connexions de la <literal>DataSource</literal> du serveur d'application
+ enregistrée dans le JNDI. Pour cela vous devrez définir au moins une des
+ propriétés suivantes :
+ </para>
+
+ <table frame="topbot">
+ <title>Propriété d'une Datasource Hibernate</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nom d'une propriété</entry>
+ <entry>fonction</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.connection.datasource</literal>
+ </entry>
+ <entry>
+ <emphasis>Nom JNDI de la datasource</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jndi.url</literal>
+ </entry>
+ <entry>
+ <emphasis>URL du fournisseur JNDI</emphasis> (optionnelle)
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jndi.class</literal>
+ </entry>
+ <entry>
+ <emphasis>Classe de l'<literal>InitialContextFactory</literal> du JNDI</emphasis> (optionnelle)
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.username</literal>
+ </entry>
+ <entry>
+ <emphasis>utilisateur de la base de données</emphasis> (optionnelle)
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.password</literal>
+ </entry>
+ <entry>
+ <emphasis>mot de passe de la base de données</emphasis> (optionnelle)
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ Voici un exemple de fichier <literal>hibernate.properties</literal>
+ pour l'utilisation d'une datasource JNDI fournie par un serveur d'applications :
+ </para>
+
+ <programlisting><![CDATA[hibernate.connection.datasource = java:/comp/env/jdbc/test
+hibernate.transaction.factory_class = \
+ org.hibernate.transaction.JTATransactionFactory
+hibernate.transaction.manager_lookup_class = \
+ org.hibernate.transaction.JBossTransactionManagerLookup
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+ <para>
+ Les connexions JDBC obtenues à partir d'une datasource JNDI participeront automatiquement
+ aux transactions gérées par le conteneur du serveur d'applications.
+ </para>
+
+ <para>
+ Des propriétés supplémentaires de connexion peuvent être passées en préfixant
+ le nom de la propriété par "<literal>hibernate.connnection</literal>". Par exemple,
+ vous pouvez spécifier un jeu de caractères en utilisant
+ <literal>hibernate.connection.charSet</literal>.
+ </para>
+
+ <para>
+ Vous pouvez fournir votre propre stratégie d'obtention des connexions JDBC en implémentant l'interface
+ <literal>org.hibernate.connection.ConnectionProvider</literal>. Vous pouvez sélectionner
+ une implémentation spécifique en positionnant <literal>hibernate.connection.provider_class</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-optional" revision="1">
+ <title>Propriétés de configuration optionnelles</title>
+
+ <para>
+ Il y a un certain nombre d'autres propriétés qui contrôlent le fonctionnement
+ d'Hibernate à l'exécution. Toutes sont optionnelles et ont comme valeurs par défaut
+ des valeurs "raisonnables" pour un fonctionnement nominal.
+ </para>
+
+ <para>
+ <emphasis>Attention : Certaines de ces propriétés sont uniquement de niveau System.</emphasis>
+ Les propriétés de niveau System ne peuvent être positionnées que via la ligne de commande
+ (<literal>java -Dproperty=value</literal>) ou être définies dans <literal>hibernate.properties</literal>.
+ Elle <emphasis>ne peuvent pas</emphasis> l'être via une des autres techniques décrites ci-dessus.
+ </para>
+
+ <table frame="topbot" id="configuration-optional-properties" revision="8">
+ <title>Propriétés de configuration d'Hibernate</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nom de la propriété</entry>
+ <entry>Fonction</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.dialect</literal>
+ </entry>
+ <entry>
+ Le nom de la classe du <literal>Dialect</literal> Hibernate.
+ qui permet à Hibernate de générer du SQL optimisé pour une
+ base de données relationnelle particulière.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>nom.complet.de.ma.classe.de.Dialect</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.show_sql</literal>
+ </entry>
+ <entry>
+ Ecrit toutes les requêtes SQL sur la console. Il s'agit d'une
+ alternative au positionnement de la catégorie de log
+ <literal>org.hibernate.SQL</literal> au niveau <literal>debug</literal>.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.format_sql</literal>
+ </entry>
+ <entry>
+ Formate et indente le sql dans la console et dans le log
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.default_schema</literal>
+ </entry>
+ <entry>
+ Positionne dans le SQL généré un schéma/tablespace par défaut pour les noms de
+ table ne l'ayant pas surchargé.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>MON_SCHEMA</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.default_catalog</literal>
+ </entry>
+ <entry>
+ Qualifie les noms de tables non qualifiées avec ce catalogue
+ dans le SQL généré.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>CATALOG_NAME</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.session_factory_name</literal>
+ </entry>
+ <entry>
+ La <literal>SessionFactory</literal> sera automatiquement
+ liée à ce nom dans le JNDI après sa création.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>jndi/nom/hierarchique</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.max_fetch_depth</literal>
+ </entry>
+ <entry>
+ Définit la profondeur maximale d'un arbre de chargement par
+ jointures ouvertes pour les associations à cardinalité unitaire
+ (un-à-un, plusieurs-à-un).
+ Un <literal>0</literal> désactive le chargement par jointure
+ ouverte.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ valeurs recommandées entre <literal>0</literal> et <literal>3</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.default_batch_fetch_size</literal>
+ </entry>
+ <entry>
+ Définit une taille par défaut pour le chargement par lot des associations
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ Valeurs recommandées : <literal>4</literal>, <literal>8</literal>,
+ <literal>16</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.default_entity_mode</literal>
+ </entry>
+ <entry>
+ Définit un mode de représentation par défaut des entités pour
+ toutes les sessions ouvertes depuis cette <literal>SessionFactory</literal>
+ <para>
+ <literal>dynamic-map</literal>, <literal>dom4j</literal>,
+ <literal>pojo</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.order_updates</literal>
+ </entry>
+ <entry>
+ Force Hibernate à trier les updates SQL par la valeur de la clé
+ primaire des éléments qui sont mis à jour. Cela permet de limiter
+ les deadlocks de transaction dans les systèmes hautement concurents.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.generate_statistics</literal>
+ </entry>
+ <entry>
+ Si activé, Hibernate va collecter des statistiques utiles
+ pour le réglage des performances.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.use_identifer_rollback</literal>
+ </entry>
+ <entry>
+ Si activé, les propriétés correspondant à l'identifiant
+ des objets vont être remises aux valeurs par défaut lorsque
+ les objets seront supprimés.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.use_sql_comments</literal>
+ </entry>
+ <entry>
+ Si activé, Hibernate va générer des commentaires à l'intérieur
+ des requêtes SQL pour faciliter le debogage., par défaut à <literal>false</literal>.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot" id="configuration-jdbc-properties" revision="8">
+ <title>Propriétés Hibernate liées à JDBC et aux connexions</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nom de la propriété</entry>
+ <entry>Fonction</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.fetch_size</literal>
+ </entry>
+ <entry>
+ Une valeur non nulle détermine la taille de chargement
+ des statements JDBC (appelle
+ <literal>Statement.setFetchSize()</literal>).
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.batch_size</literal>
+ </entry>
+ <entry>
+ Une valeur non nulle active l'utilisation par Hibernate des mises
+ à jour par batch de JDBC2.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ les valeurs recommandées entre <literal>5</literal> et <literal>30</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.batch_versioned_data</literal>
+ </entry>
+ <entry>
+ Paramétrez cette propriété à <literal>true</literal> si votre pilote JDBC
+ retourne des row counts corrects depuis <literal>executeBatch()</literal> (il est
+ souvent approprié d'activer cette option). Hibernate utilisera alors le "batched DML" pour
+ versionner automatiquement les données. Par défaut = <literal>false</literal>.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.factory_class</literal>
+ </entry>
+ <entry>
+ Sélectionne un <literal>Batcher</literal> personnalisé. La
+ plupart des applications n'auront pas besoin de cette propriété
+ de configuration
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>classname.of.Batcher</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.use_scrollable_resultset</literal>
+ </entry>
+ <entry>
+ Active l'utilisation par Hibernate des resultsets scrollables
+ de JDBC2. Cette propriété est seulement nécessaire lorsque l'on
+ utilise une connexion JDBC fournie par l'utilisateur. Autrement,
+ Hibernate utilise les métadonnées de la connexion.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.use_streams_for_binary</literal>
+ </entry>
+ <entry>
+ Utilise des flux lorsque l'on écrit/lit des types
+ <literal>binary</literal> ou <literal>serializable</literal>
+ vers et à partir de JDBC (propriété de niveau système).
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.use_get_generated_keys</literal>
+ </entry>
+ <entry>
+ Active l'utilisation de <literal>PreparedStatement.getGeneratedKeys()</literal> de JDBC3
+ pour récupérer nativement les clés générées après insertion. Nécessite un pilote
+ JDBC3+, le mettre à false si votre pilote a des problèmes avec les générateurs
+ d'identifiant Hibernate. Par défaut, essaie de déterminer les possibilités du
+ pilote en utilisant les meta données de connexion.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.provider_class</literal>
+ </entry>
+ <entry>
+ Le nom de la classe d'un <literal>ConnectionProvider</literal> personnalisé
+ qui fournit des connexions JDBC à Hibernate
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>classname.of.ConnectionProvider</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.isolation</literal>
+ </entry>
+ <entry>
+ Définit le niveau d'isolation des transactions JDBC. Regardez
+ <literal>java.sql.Connection</literal> pour connaître le
+ sens des différentes valeurs mais notez également que la plupart
+ des bases de données ne supportent pas tous les niveaux d'isolation.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>1, 2, 4, 8</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.autocommit</literal>
+ </entry>
+ <entry>
+ Active le mode de commit automatique (autocommit) pour les connexions
+ JDBC du pool (non recommandé).
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.release_mode</literal>
+ </entry>
+ <entry>
+ Spécifie à quel moment Hibernate doit relacher les connexion JDBC.
+ Par défaut une connexion JDBC est conservée jusqu'à ce que la session
+ soit explicitement fermée ou déconnectée. Pour une source de données
+ JTA d'un serveur d'application, vous devriez utiliser <literal>after_statement</literal>
+ pour libérer les connexions de manière plus agressive après chaque appel
+ JDBC. Pour une connexion non JTA, il est souvent préférable de libérer
+ la connexion à la fin de chaque transaction en utilisant <literal>after_transaction</literal>.
+ <literal>auto</literal> choisira <literal>after_statement</literal> pour
+ des transactions JTA et CMT et <literal>after_transaction</literal> pour
+ des transactions JDBC.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>on_close</literal> (default) | <literal>after_transaction</literal> |
+ <literal>after_statement</literal> | <literal>auto</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.<emphasis><propertyName></emphasis></literal>
+ </entry>
+ <entry>
+ Passe la propriété JDBC<literal>propertyName</literal>
+ à <literal>DriverManager.getConnection()</literal>.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jndi.<emphasis><propertyName></emphasis></literal>
+ </entry>
+ <entry>
+ Passe la propriété <literal>propertyName</literal> à l'<literal>InitialContextFactory</literal>
+ de JNDI.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot" id="configuration-cache-properties" revision="7">
+ <title>Propriétés du Cache d'Hibernate</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nom de la propriété</entry>
+ <entry>Fonction</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.cache.provider_class</literal>
+ </entry>
+ <entry>
+ Le nom de classe d'un <literal>CacheProvider</literal>
+ spécifique.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>nom.de.classe.du.CacheProvider</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.use_minimal_puts</literal>
+ </entry>
+ <entry>
+ Optimise le cache de second niveau en minimisant les écritures,
+ au prix de plus de lectures. Ce paramètre est surtout utile pour
+ les caches en cluster et est activé par défaut dans hibernate3
+ pour les implémentations de cache en cluster.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.use_query_cache</literal>
+ </entry>
+ <entry>
+ Activer le cache de requête, les requêtes individuelles doivent tout
+ de même être déclarées comme pouvant être mise en cache.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.use_second_level_cache</literal>
+ </entry>
+ <entry>
+ Peut être utilisé pour désactiver complètement le cache de second niveau
+ qui est activé par défaut pour les classes qui spécifient un élément
+ <literal><cache></literal> dans leur mapping.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.query_cache_factory</literal>
+ </entry>
+ <entry>
+ Le nom de classe d'une interface <literal>QueryCacheFactory</literal> ,
+ par défaut = built-in <literal>StandardQueryCacheFactory</literal>.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>nom.de.la.classe.de.QueryCacheFactory</literal>
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <literal>hibernate.cache.region_prefix</literal>
+ </entry>
+ <entry>
+ Un préfixe à utiliser pour le nom des régions du
+ cache de second niveau.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>prefix</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.use_structured_entries</literal>
+ </entry>
+ <entry>
+ Force Hibernate à stocker les données dans le cache de
+ second niveau dans un format plus adapté à la visualisation
+ par un humain.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot" id="configuration-transaction-properties" revision="9">
+ <title>Propriétés des transactions Hibernate</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nom de la propriété</entry>
+ <entry>Fonction</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.transaction.factory_class</literal>
+ </entry>
+ <entry>
+ Le nom de classe d'une <literal>TransactionFactory</literal>
+ qui sera utilisée par l'API <literal>Transaction</literal>
+ d'Hibernate (la valeur par défaut est
+ <literal>JDBCTransactionFactory</literal>).
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>nom.de.classe.d.une.TransactionFactory</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>jta.UserTransaction</literal>
+ </entry>
+ <entry>
+ Le nom JNDI utilisé par la <literal>JTATransactionFactory</literal>
+ pour obtenir la <literal>UserTransaction</literal> JTA du serveur
+ d'applications.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>jndi/nom/compose</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.transaction.manager_lookup_class</literal>
+ </entry>
+ <entry>
+ Le nom de la classe du <literal>TransactionManagerLookup</literal>
+ - requis lorsque le cache de niveau JVM est activé ou lorsque l'on
+ utilise un générateur hilo dans un environnement JTA.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>nom.de.classe.du.TransactionManagerLookup</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.transaction.flush_before_completion</literal>
+ </entry>
+ <entry>
+ Si activé, la session sera automatiquement vidée durant la phase
+ qui précède la fin de la transaction (before completion).
+ La gestion automatique de contexte fourni par Hibernate est
+ recommandée, voir
+ <xref linkend="architecture-current-session"/>.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.transaction.auto_close_session</literal>
+ </entry>
+ <entry>
+ Si activé, la session sera automatiquement fermé pendant la phase
+ qui suit la fin de la transaction (after completion).
+ La gestion automatique de contexte fourni par Hibernate est
+ recommandée, voir
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot" id="configuration-misc-properties" revision="9">
+ <title>Propriétés diverses</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nom de la propriété</entry>
+ <entry>Fonction</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.current_session_context_class</literal>
+ </entry>
+ <entry>
+ Fournit une stratégie particulière pour contextualiser
+ la <literal>Session</literal> courante. Voir
+ <xref linkend="architecture-current-session"/> pour plus
+ d'informations sur les stratégies fournies.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>jta</literal> | <literal>thread</literal> |
+ <literal>custom.Class</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.query.factory_class</literal>
+ </entry>
+ <entry>
+ Choisi l'implémentation du parseur de requête
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> ou
+ <literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.query.substitutions</literal>
+ </entry>
+ <entry>
+ Lien entre les tokens de requêtes Hibernate et les
+ tokens SQL (les tokens peuvent être des fonctions ou des
+ noms littéraux par exemple).
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.hbm2ddl.auto</literal>
+ </entry>
+ <entry>
+ Valide ou exporte automatiquement le schéma DDL vers la base de données
+ lorsque la <literal>SessionFactory</literal> est créée.
+ La valeur <literal>create-drop</literal> permet de supprimer
+ le schéma de base de données lorsque la <literal>SessionFactory</literal>
+ est fermée explicitement.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>validate</literal> | <literal>update</literal> |
+ <literal>create</literal> | <literal>create-drop</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cglib.use_reflection_optimizer</literal>
+ </entry>
+ <entry>
+ Active l'utilisation de CGLIB à la place de la réflexion à l'exécution
+ (Propriété de niveau système). La réflexion peut parfois être utile pour
+ résoudre des problèmes. Notez qu'Hibernate a tout de même toujours besoin
+ de CGLIB même si l'optimiseur est désactivé. Cette optimisation ne peut être
+ définie que dans le fichier <literal>hibernate.cfg.xml</literal>.
+ <para>
+ <emphasis role="strong">ex.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <sect2 id="configuration-optional-dialects" revision="1">
+ <title>Dialectes SQL</title>
+
+ <para>
+ Vous devriez toujours positionner la propriété <literal>hibernate.dialect</literal> à
+ la sous-classe de <literal>org.hibernate.dialect.Dialect</literal> appropriée à
+ votre base de données. Si vous spécifiez un dialecte,
+ Hibernate utilisera des valeurs adaptées pour certaines autres
+ propriétés listées ci-dessus, vous évitant l'effort de le faire à la main.
+ </para>
+
+ <table frame="topbot" id="sql-dialects" revision="2">
+ <title>Dialectes SQL d'Hibernate (<literal>hibernate.dialect</literal>)</title>
+ <tgroup cols="2">
+ <colspec colwidth="1*"/>
+ <colspec colwidth="2.5*"/>
+ <thead>
+ <row>
+ <entry>SGBD</entry>
+ <entry>Dialecte</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>DB2</entry> <entry><literal>org.hibernate.dialect.DB2Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>DB2 AS/400</entry> <entry><literal>org.hibernate.dialect.DB2400Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>DB2 OS390</entry> <entry><literal>org.hibernate.dialect.DB2390Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>PostgreSQL</entry> <entry><literal>org.hibernate.dialect.PostgreSQLDialect</literal></entry>
+ </row>
+ <row>
+ <entry>MySQL</entry> <entry><literal>org.hibernate.dialect.MySQLDialect</literal></entry>
+ </row>
+ <row>
+ <entry>MySQL with InnoDB</entry> <entry><literal>org.hibernate.dialect.MySQLInnoDBDialect</literal></entry>
+ </row>
+ <row>
+ <entry>MySQL with MyISAM</entry> <entry><literal>org.hibernate.dialect.MySQLMyISAMDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Oracle (any version)</entry> <entry><literal>org.hibernate.dialect.OracleDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Oracle 9i/10g</entry> <entry><literal>org.hibernate.dialect.Oracle9Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>Sybase</entry> <entry><literal>org.hibernate.dialect.SybaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Sybase Anywhere</entry> <entry><literal>org.hibernate.dialect.SybaseAnywhereDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Microsoft SQL Server</entry> <entry><literal>org.hibernate.dialect.SQLServerDialect</literal></entry>
+ </row>
+ <row>
+ <entry>SAP DB</entry> <entry><literal>org.hibernate.dialect.SAPDBDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Informix</entry> <entry><literal>org.hibernate.dialect.InformixDialect</literal></entry>
+ </row>
+ <row>
+ <entry>HypersonicSQL</entry> <entry><literal>org.hibernate.dialect.HSQLDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Ingres</entry> <entry><literal>org.hibernate.dialect.IngresDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Progress</entry> <entry><literal>org.hibernate.dialect.ProgressDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Mckoi SQL</entry> <entry><literal>org.hibernate.dialect.MckoiDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Interbase</entry> <entry><literal>org.hibernate.dialect.InterbaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Pointbase</entry> <entry><literal>org.hibernate.dialect.PointbaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>FrontBase</entry> <entry><literal>org.hibernate.dialect.FrontbaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Firebird</entry> <entry><literal>org.hibernate.dialect.FirebirdDialect</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-outerjoin" revision="4">
+ <title>Chargement par Jointure Ouverte</title>
+
+ <para>
+ Si votre base de données supporte les outer joins de type ANSI, Oracle ou Sybase,
+ <emphasis>le chargement par jointure ouverte</emphasis> devrait améliorer les
+ performances en limitant le nombre d'aller-retour avec la base de données (la
+ base de données effectuant donc potentiellement plus de travail). Le chargement par
+ jointure ouverte permet à un graphe entier d'objets connectés par une relation plusieurs-à-un,
+ un-à-plusieurs ou un-à-un d'être chargé en un seul <literal>SELECT</literal> SQL.
+ </para>
+
+ <para>
+ Le chargement par jointure ouverte peut être désactiver <emphasis>globalement</emphasis>
+ en mettant la propriété <literal>hibernate.max_fetch_depth</literal> à <literal>0</literal>.
+ Une valeur de <literal>1</literal> ou plus active le chargement par jointure ouverte
+ pour les associatiosn un-à-un et plusieurs-à-un qui ont été mappée avec
+ <literal>fetch="join"</literal>.
+ </para>
+
+ <para>
+ Reportez vous à <xref linkend="performance-fetching"/> pour plus d'information.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-binarystreams" revision="1">
+ <title>Flux binaires</title>
+
+ <para>
+ Oracle limite la taille d'un tableau de <literal>byte</literal> qui peuvent être
+ passées à et vers son pilote JDBC. Si vous souhaitez utiliser des instances larges
+ de type <literal>binary</literal> ou <literal>serializable</literal>, vous devez activer
+ la propriété <literal>hibernate.jdbc.use_streams_for_binary</literal>. <emphasis>C'est une
+ fonctionalité de niveau système uniquement.</emphasis>
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-cacheprovider" revision="2">
+ <title>Cache de second niveau et cache de requêtes</title>
+
+ <para>
+ Les propriétés préfixées par <literal>hibernate.cache</literal>
+ vous permettent d'utiliser un système de cache de second niveau. Ce cache
+ peut avoir une portée dans le processus ou même être utilisable dans un
+ système distribué. Référez vous au chapitre <xref linkend="performance-cache"/>
+ pour plus de détails.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-querysubstitution">
+ <title>Substitution dans le langage de requêtage</title>
+
+ <para>
+ Vous pouvez définir de nouveaux tokens dans les requêtes Hibernate en utilisant la propriété
+ <literal>hibernate.query.substitutions</literal>. Par exemple :
+ </para>
+
+ <programlisting>hibernate.query.substitutions vrai=1, faux=0</programlisting>
+
+ <para>
+ remplacerait les tokens <literal>vrai</literal> et <literal>faux</literal> par
+ des entiers dans le SQL généré.
+ </para>
+
+ <programlisting>hibernate.query.substitutions toLowercase=LOWER</programlisting>
+
+ <para>
+ permettrait de renommer la fonction SQL <literal>LOWER</literal> en <literal>toLowercase</literal>
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-statistics" revision="2">
+ <title>Statistiques Hibernate</title>
+
+ <para>
+ Si vous activez <literal>hibernate.generate_statistics</literal>, Hibernate va
+ fournir un certains nombre de métriques utiles pour régler les performances
+ d'une application qui tourne via <literal>SessionFactory.getStatistics()</literal>.
+ Hibernate peut aussi être configuré pour exposer ces statistiques via JMX.
+ Lisez les Javadoc des interfaces dans le package
+ <literal>org.hibernate.stats</literal> pour plus d'informations.
+ </para>
+
+ </sect2>
+ </sect1>
+
+ <sect1 id="configuration-logging">
+ <title>Tracer</title>
+
+ <para>
+ Hibernate trace divers évènements en utilisant Apache commons-logging.
+ </para>
+
+ <para>
+ Le service commons-logging délèguera directement à Apache Log4j
+ (si vous incluez <literal>log4j.jar</literal> dans votre classpath)
+ ou le système de trace du JDK 1.4 (si vous tournez sous le JDK 1.4
+ et supérieur). Vous pouvez télécharger Log4j à partir de
+ <literal>http://jakarta.apache.org</literal>. Pour utiliser Log4j,
+ vous devrez placer dans votre classpath un fichier
+ <literal>log4j.properties</literal>. Un exemple de fichier est distribué
+ avec Hibernate dans le répertoire <literal>src/</literal>.
+ </para>
+
+ <para>
+ Nous vous recommandons fortement de vous familiariser avec les messages des traces
+ d'Hibernate. Beaucoup de soins a été apporté pour donner le plus de détails
+ possible sans les rendre illisibles. C'est un outil essentiel en cas de soucis.
+ Les catégories de trace les plus intéressantes sont les suivantes :
+ </para>
+
+ <table frame="topbot" id="log-categories" revision="2">
+ <title>Catégories de trace d'Hibernate</title>
+ <tgroup cols="2">
+ <colspec colwidth="1*"/>
+ <colspec colwidth="2.5*"/>
+ <thead>
+ <row>
+ <entry>Catégorie</entry>
+ <entry>Fonction</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>org.hibernate.SQL</literal></entry>
+ <entry>Trace toutes les requêts SQL de type DML (gestion des données) qui sont exécutées</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.type</literal></entry>
+ <entry>Trace tous les paramètres JDBC</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.tool.hbm2ddl</literal></entry>
+ <entry>Trace toutes les requêts SQL de type DDL (gestion de la structure de la base) qui sont exécutées</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.pretty</literal></entry>
+ <entry>
+ Trace l'état de toutes les entités (20 entités maximum) qui
+ sont associées avec la session hibernate au moment du flush
+ </entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.cache</literal></entry>
+ <entry>Trace toute l'activité du cache de second niveau</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction</literal></entry>
+ <entry>Trace toute l'activité relative aux transactions</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.jdbc</literal></entry>
+ <entry>Trace toute acquisition de ressource JDBC</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.hql.ast.AST</literal></entry>
+ <entry>
+ Trace l'arbre syntaxique des requêtes HQL et SQL durant l'analyse syntaxique des requêtes
+ </entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.secure</literal></entry>
+ <entry>Trace toutes les demandes d'autorisation JAAS</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate</literal></entry>
+ <entry>
+ Trace tout (beaucoupe d'informations, mais très utile pour résoudre les problèmes).
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ Lorsque vous développez des applications avec Hibernate, vous devriez quasiment toujours
+ travailler avec le niveau <literal>debug</literal> activé pour la catégorie
+ <literal>org.hibernate.SQL</literal>, ou sinon avec la propriété
+ <literal>hibernate.show_sql</literal> activée.
+ </para>
+
+
+ </sect1>
+
+ <sect1 id="configuration-namingstrategy">
+ <title>Implémenter une <literal>NamingStrategy</literal></title>
+
+ <para>
+ L'interface <literal>org.hibernate.cfg.NamingStrategy</literal> vous permet de
+ spécifier une "stratégie de nommage" des objets et éléments de la base de données.
+ </para>
+
+ <para>
+ Vous pouvez fournir des règles pour automatiquement générer les identifiants
+ de base de données à partir des identifiants Java, ou transformer une colonne
+ ou table "logique" donnée dans le fichier de mapping en une colonne ou table
+ "physique". Cette fonctionnalité aide à réduire la verbosité de documents
+ de mapping, en éliminant le bruit répétitif (les préfixes <literal>TBL_</literal>
+ par exemple). La stratégie par défaut utilisée par Hibernate est minimale.
+ </para>
+
+ <para>
+ Vous pouvez définir une stratégie différente en appelant
+ <literal>Configuration.setNamingStrategy()</literal> avant d'ajouter des
+ mappings :
+ </para>
+
+ <programlisting><![CDATA[SessionFactory sf = new Configuration()
+ .setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
+ .addFile("Item.hbm.xml")
+ .addFile("Bid.hbm.xml")
+ .buildSessionFactory();]]></programlisting>
+
+ <para>
+ <literal>net.sf.hibernate.cfg.ImprovedNamingStrategy</literal> est une
+ stratégie fournie qui peut être utile comme point de départ de quelques
+ applications.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-xmlconfig" revision="2">
+ <title>Fichier de configuration XML</title>
+
+ <para>
+ Une approche alternative est de spécifier toute la configuration dans un
+ fichier nommé <literal>hibernate.cfg.xml</literal>. Ce fichier peut être
+ utilisé à la place du fichier <literal>hibernate.properties</literal>, voire
+ même peut servir à surcharger les propriétés si les deux fichiers sont présents.
+ </para>
+
+ <para>
+ Le fichier de configuration XML doit par défaut se placer à la racine
+ du <literal>CLASSPATH</literal>. En voici un exemple :
+ </para>
+
+ <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+ "-//Hibernate/Hibernate Configuration DTD//EN"
+ "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+ <!-- a SessionFactory instance listed as /jndi/name -->
+ <session-factory
+ name="java:hibernate/SessionFactory">
+
+ <!-- properties -->
+ <property name="connection.datasource">java:/comp/env/jdbc/MyDB</property>
+ <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
+ <property name="show_sql">false</property>
+ <property name="transaction.factory_class">
+ org.hibernate.transaction.JTATransactionFactory
+ </property>
+ <property name="jta.UserTransaction">java:comp/UserTransaction</property>
+
+ <!-- mapping files -->
+ <mapping resource="org/hibernate/auction/Item.hbm.xml"/>
+ <mapping resource="org/hibernate/auction/Bid.hbm.xml"/>
+
+ <!-- cache settings -->
+ <class-cache class="org.hibernate.auction.Item" usage="read-write"/>
+ <class-cache class="org.hibernate.auction.Bid" usage="read-only"/>
+ <collection-cache collection="org.hibernate.auction.Item.bids" usage="read-write"/>
+
+ </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+ <para>
+ Commme vous pouvez le voir, l'avantage de cette approche est l'externalisation
+ des noms des fichiers de mapping de la configuration. Le fichier <literal>hibernate.cfg.xml</literal>
+ est également plus pratique quand on commence à régler le cache d'Hibernate. Notez
+ que vous pouvez choisir entre utiliser <literal>hibernate.properties</literal> ou
+ <literal>hibernate.cfg.xml</literal>, les deux sont équivalents, sauf en ce qui
+ concerne les bénéfices de l'utilisation de la syntaxe XML mentionnés ci-dessus.
+ </para>
+
+ <para>
+ Avec la configuration XML, démarrer Hibernate devient donc aussi simple que ceci :
+ </para>
+
+ <programlisting><![CDATA[SessionFactory sf = new Configuration().configure().buildSessionFactory();]]></programlisting>
+
+
+
+ </sect1>
+
+ <sect1 id="configuration-j2ee" revision="1">
+ <title>Intégration à un serveur d'application J2EE</title>
+
+ <para>
+ Hibernate possède les points suivants d'intégration à l'infrastructure J2EE :
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Source de données gérée par le conteneur</emphasis> : Hibernate peut
+ utiliser des connexions JDBC gérées par le conteneur et fournie par l'intermédiaire
+ de JNDI. Souvent, un <literal>TransactionManager</literal> compatible JTA
+ et un <literal>ResourceManager</literal> s'occupent de la gestion des transactions (CMT).
+ Ils sont particulièrement prévus pour pouvoir gérer des transactions distribuées
+ sur plusieurs sources de données. Vous pouvez bien sûr également définir vos
+ limites de transaction dans votre programme (BMT) ou vous pouvez sinon aussi
+ utiliser l'API optionnelle <literal>Transaction</literal> d'Hibernate qui vous garantira
+ la portabilité de votre code entre plusieurs serveurs d'application.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Association JNDI automatique</emphasis>: Hibernate peut associer sa
+ <literal>SessionFactory</literal> à JNDI après le démarrage.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Association de la Session à JTA:</emphasis> La <literal>Session</literal> Hibernate
+ peut être associée automatiquement à une transaction JTA si vous utilisez les EJBs.
+ Vous avez juste à récupérer la <literal>SessionFactory</literal> depuis JNDI et
+ à récupérer la <literal>Session</literal> courante. Hibernate s'occupe de vider et
+ fermer la <literal>Session</literal> lorsque le transaction JTA se termine. La
+ démarcation des transactions se fait de manière déclarative dans les descripteurs de déploiement.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Déploiement JMX :</emphasis>Si vous avez un serveur d'application compatible JMX
+ (JBoss AS par exemple), vous pouvez choisir de déployer Hibernate en temps que MBean géré par
+ le serveur. Cela vous évite de coder la ligne de démarrage qui permet de construire
+ la <literal>SessionFactory</literal> depuis la <literal>Configuration</literal>.
+ Le conteneur va démarrer votre <literal>HibernateService</literal>, et va idéalement
+ s'occuper des dépendances entre les services (la source de données doit être disponible
+ avant qu'Hibernate ne démarre, etc).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ En fonction de votre environnement, vous devrez peut être mettre l'option de
+ configuration <literal>hibernate.connection.aggressive_release</literal> à vrai si
+ le serveur d'application affiche des exceptions de type "connection containment".
+ </para>
+
+ <sect2 id="configuration-optional-transactionstrategy" revision="3">
+ <title>Configuration de la stratégie transactionnelle</title>
+
+ <para>
+ L'API de la <literal>Session</literal> Hibernate est indépendante de tout système
+ de démarcation des transactions qui peut être présent dans votre architecture. Si
+ vous laissez Hibernate utiliser l'API JDBC directement via un pool de connexion, vous
+ devrez commencer et terminer vos transactions en utilisant l'API JDBC. Si votre
+ application tourne à l'intérieur d'un serveur d'application J2EE, vous voudrez peut être
+ utiliser les transactions gérées par les beans (BMT) et appeller l'API JTA et
+ <literal>UserTransaction</literal> lorsque cela est nécessaire.
+ </para>
+ <para>
+ Pour conserver votre code portable entre ces deux environnements (et d'autres éventuels)
+ nous vous recommandons d'utiliser l'API optionnelle <literal>Transaction</literal> d'Hibernate,
+ qui va encapsuler et masquer le système de transaction sous-jacent.
+ Pour cela, vous devez préciser une classe de fabrique d'instances de <literal>Transaction</literal>
+ en positionnant la propriété
+ <literal>hibernate.transaction.factory_class</literal>.
+ </para>
+
+ <para>
+ Il existe trois choix standards (fournis) :
+ </para>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term><literal>net.sf.hibernate.transaction.JDBCTransactionFactory</literal></term>
+ <listitem>
+ <para>délègue aux transactions de la base de données (JDBC). Valeur par défaut.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>org.hibernate.transaction.JTATransactionFactory</literal></term>
+ <listitem>
+ <para>
+ délègue à CMT si une transaction existante est sous ce contexte (ex: méthode
+ d'un EJB session), sinon une nouvelle transaction est entamée et
+ une transaction gérée par le bean est utilisée.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>org.hibernate.transaction.CMTTransactionFactory</literal></term>
+ <listitem>
+ <para>délègue à aux transactions JTA gérées par le conteneur</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ Vous pouvez également définir votre propre stratégie transactionnelle
+ (pour un service de transaction CORBA par exemple).
+ </para>
+
+ <para>
+ Certaines fonctionnalités d'Hibernate (i.e. le cache de second niveau, l'association
+ automatique des Session à JTA, etc.) nécessitent l'accès au <literal>TransactionManager</literal>
+ JTA dans un environnement "managé". Dans un serveur d'application, vous devez indiquer
+ comment Hibernate peut obtenir une référence vers le <literal>TransactionManager</literal>,
+ car J2EE ne fournit pas un seul mécanisme standard.
+ </para>
+
+ <table frame="topbot" id="jtamanagerlookup" revision="1">
+ <title>TransactionManagers JTA</title>
+ <tgroup cols="2">
+ <colspec colwidth="2.5*"/>
+ <colspec colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Fabrique de Transaction</entry>
+ <entry align="center">Serveur d'application</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>org.hibernate.transaction.JBossTransactionManagerLookup</literal></entry>
+ <entry align="center">JBoss</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.WeblogicTransactionManagerLookup</literal></entry>
+ <entry align="center">Weblogic</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.WebSphereTransactionManagerLookup</literal></entry>
+ <entry align="center">WebSphere</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</literal></entry>
+ <entry align="center">WebSphere 6</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.OrionTransactionManagerLookup</literal></entry>
+ <entry align="center">Orion</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.ResinTransactionManagerLookup</literal></entry>
+ <entry align="center">Resin</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.JOTMTransactionManagerLookup</literal></entry>
+ <entry align="center">JOTM</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.JOnASTransactionManagerLookup</literal></entry>
+ <entry align="center">JOnAS</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.JRun4TransactionManagerLookup</literal></entry>
+ <entry align="center">JRun4</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.BESTransactionManagerLookup</literal></entry>
+ <entry align="center">Borland ES</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-jndi" revision="3">
+ <title><literal>SessionFactory</literal> associée au JNDI</title>
+
+ <para>
+ Une <literal>SessionFactory</literal> Hibernate associée au JNDI peut
+ simplifier l'accès à la fabrique et donc la création de nouvelles
+ <literal>Session</literal>s. Notez que cela n'est pas lié avec les <literal>Datasource</literal>
+ associées au JNDI, elles utilisent juste le même registre.
+ </para>
+
+ <para>
+ Si vous désirez associer la <literal>SessionFactory</literal> à un nom JNDI,
+ spécifiez un nom (ex. <literal>java:hibernate/SessionFactory</literal>) en
+ utilisant la propriété <literal>hibernate.session_factory_name</literal>.
+ Si cette propriété est omise, la <literal>SessionFactory</literal> ne sera pas
+ associée au JNDI (c'est particulièrement pratique dans les environnements ayant une
+ implémentation de JNDI en lecture seule, comme c'est le cas pour Tomcat).
+ </para>
+
+ <para>
+ Lorsqu'il associe la <literal>SessionFactory</literal> au JNDI, Hibernate utilisera
+ les valeurs de <literal>hibernate.jndi.url</literal>, <literal>hibernate.jndi.class</literal>
+ pour instancier un contexte d'initialisation. S'ils ne sont pas spécifiés,
+ l'<literal>InitialContext</literal> par défaut sera utilisé.
+ </para>
+
+ <para>
+ Hibernate va automatiquement placer la <literal>SessionFactory</literal> dans JNDI
+ après avoir appelé <literal>cfg.buildSessionFactory()</literal>. Cela signifie que vous
+ devez avoir cet appel dans un code de démarrage (ou dans une classe utilitaire) dans
+ votre application sauf si vous utilisez le déploiement JMX avec le service
+ <literal>HibernateService</literal> présenté plus tard dans ce document.
+ </para>
+ <para>
+ Si vous utilisez <literal>SessionFactory</literal> JNDI, un EJB ou n'importe quelle autre classe
+ peut obtenir la <literal>SessionFactory</literal> en utilisant un lookup JNDI.
+ </para>
+
+ <para>
+ Nous recommandons que vous liiez la <literal>SessionFactory</literal> à JNDI dans les
+ environnements managés et que vous utilisiez un singleton <literal>static</literal> si ce n'est pas le cas.
+ Pour isoler votre application de ces détails, nous vous recommandons aussi de masquer
+ le code de lookup actuel pour une <literal>SessionFactory</literal> dans une classe helper,
+ comme <literal>HibernateUtil.getSessionFactory()</literal>. Notez qu'une telle classe
+ est aussi un moyen efficace de démarrer Hibernate—voir chapitre 1.
+ </para>
+ </sect2>
+
+ <sect2 id="configuration-j2ee-currentsession" revision="4">
+ <title>Association automatique de la Session à JTA</title>
+
+ <para>
+ Le moyen le plus simple de gérer les <literal>Session</literal>s et transactions est
+ la gestion automatique de session "courante" offerte par Hibernate.
+ Voir détail à <xref linkend="architecture-current-session">current sessions</xref>.
+ En utilisant le contexte de session <literal>"jta"</literal> session context, s'il n'y a pas
+ de <literal>Session</literal> associée à la transaction JTA courante, une session sera
+ démarrée et associée à la transaction JTA courante la première fois que vous appelez
+ <literal>sessionFactory.getCurrentSession()</literal>. Les <literal>Session</literal>s
+ obtenue via <literal>getCurrentSession()</literal> dans une contexte <literal>"jta"</literal>
+ seront automatiquement flushées avant la validation de la transaction, fermées une fois
+ la transaction complétée, et libéreront les connexions JDBC de manière aggressive
+ après chaque statement. Ceci permet aux <literal>Session</literal>s d'être
+ gérées par le cycle de vie de la transaction JTA à la quelle est sont associées,
+ laissant le code de l'utilisateur propre de ce type de gestion. Votre code peut
+ soit utiliser JTA de manière programmatique via <literal>UserTransaction</literal>, ou (ce qui est recommandé
+ pour la portabilité du code) utiliser l'API <literal>Transaction</literal> API pour marquer
+ les limites. Si vous exécutez sous un conteneur EJB, la démarcation déclarative des transactions
+ avec CMT est recommandée.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-j2ee-jmx" revision="1">
+ <title>Déploiement JMX</title>
+
+ <para>
+ La ligne <literal>cfg.buildSessionFactory()</literal> doit toujours être exécutée
+ quelque part pour avoir une <literal>SessionFactory</literal> dans JNDI. Vous pouvez
+ faire cela dans un bloc d'initialisation <literal>static</literal> (comme
+ celui qui se trouve dans la classe <literal>HibernateUtil</literal>) ou vous pouvez
+ déployer Hibernate en temps que <emphasis>service managé</emphasis>.
+ </para>
+
+ <para>
+ Hibernate est distribué avec <literal>org.hibernate.jmx.HibernateService</literal>
+ pour le déploiement sur un serveur d'application avec le support de JMX comme JBoss AS.
+ Le déploiement et la configuration sont spécifiques à chaque vendeur. Voici un fichier
+ <literal>jboss-service.xml</literal> d'exemple pour JBoss 4.0.x:
+ </para>
+
+ <programlisting><![CDATA[<?xml version="1.0"?>
+<server>
+
+<mbean code="org.hibernate.jmx.HibernateService"
+ name="jboss.jca:service=HibernateFactory,name=HibernateFactory">
+
+ <!-- Required services -->
+ <depends>jboss.jca:service=RARDeployer</depends>
+ <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends>
+
+ <!-- Bind the Hibernate service to JNDI -->
+ <attribute name="JndiName">java:/hibernate/SessionFactory</attribute>
+
+ <!-- Datasource settings -->
+ <attribute name="Datasource">java:HsqlDS</attribute>
+ <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute>
+
+ <!-- Transaction integration -->
+ <attribute name="TransactionStrategy">
+ org.hibernate.transaction.JTATransactionFactory</attribute>
+ <attribute name="TransactionManagerLookupStrategy">
+ org.hibernate.transaction.JBossTransactionManagerLookup</attribute>
+ <attribute name="FlushBeforeCompletionEnabled">true</attribute>
+ <attribute name="AutoCloseSessionEnabled">true</attribute>
+
+ <!-- Fetching options -->
+ <attribute name="MaximumFetchDepth">5</attribute>
+
+ <!-- Second-level caching -->
+ <attribute name="SecondLevelCacheEnabled">true</attribute>
+ <attribute name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute>
+ <attribute name="QueryCacheEnabled">true</attribute>
+
+ <!-- Logging -->
+ <attribute name="ShowSqlEnabled">true</attribute>
+
+ <!-- Mapping files -->
+ <attribute name="MapResources">auction/Item.hbm.xml,auction/Category.hbm.xml</attribute>
+
+</mbean>
+
+</server>]]></programlisting>
+
+ <para>
+ Ce fichier est déployé dans un répertoire <literal>META-INF</literal> et est packagé
+ dans un fichier JAR avec l'extension <literal>.sar</literal> (service archive).
+ Vous devez également packager Hibernate, les librairies tierces requises, vos classes
+ persistantes compilées et vos fichiers de mapping dans la même archive. Vos beans
+ entreprise (souvent des EJBs session) peuvent rester dans leur propre fichier JAR mais
+ vous pouvez inclure ce fichier JAR dans le jar principal du service pour avoir une seule unité
+ déployable à chaud. Vous pouvez consulter la documentation de JBoss AS pour plus d'information
+ sur les services JMX et le déploiement des EJBs.
+ </para>
+
+ </sect2>
+
+
+ </sect1>
+
+
+
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/events.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/events.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/events.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,263 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="events">
+ <title>Les intercepteurs et les événements</title>
+
+ <para>
+ Il est souvent utile pour l'application de réagir à certains événements
+ qui surviennent dans Hibernate. Cela autorise l'implémentation de certaines sortes de
+ fonctionnalités génériques, et d'extensions de fonctionnalités d'Hibernate.
+ </para>
+
+ <sect1 id="objectstate-interceptors" revision="2">
+ <title>Intercepteurs</title>
+
+ <para>
+ L'interface <literal>Interceptor</literal> fournit des "callbacks" de la session vers l'application
+ et permettent à l'application de consulter et/ou de manipuler des propriétés
+ d'un objet persistant avant qu'il soit sauvegardé, mis à jour, supprimé ou chargé.
+ Une utilisation possible de cette fonctionnalité est de tracer l'accès à l'information.
+ Par exemple, l'<literal>Interceptor</literal> suivant positionne
+ <literal>createTimestamp</literal> quand un <literal>Auditable</literal> est créé
+ et met à jour la propriété <literal>lastUpdateTimestamp</literal> quand un
+ <literal>Auditable</literal> est mis à jour.
+ </para>
+
+ <para>
+ Vous pouvez soit implémenter <literal>Interceptor</literal> directement ou (mieux)
+ étendre <literal>EmptyInterceptor</literal>.
+ </para>
+
+ <programlisting><![CDATA[package org.hibernate.test;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.Transaction;
+import org.hibernate.type.Type;
+
+public class AuditInterceptor extends EmptyInterceptor {
+
+ private int updates;
+ private int creates;
+ private int loads;
+
+ public void onDelete(Object entity,
+ Serializable id,
+ Object[] state,
+ String[] propertyNames,
+ Type[] types) {
+ // ne fait rien
+ }
+
+ public boolean onFlushDirty(Object entity,
+ Serializable id,
+ Object[] currentState,
+ Object[] previousState,
+ String[] propertyNames,
+ Type[] types) {
+
+ if ( entity instanceof Auditable ) {
+ updates++;
+ for ( int i=0; i < propertyNames.length; i++ ) {
+ if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
+ currentState[i] = new Date();
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean onLoad(Object entity,
+ Serializable id,
+ Object[] state,
+ String[] propertyNames,
+ Type[] types) {
+ if ( entity instanceof Auditable ) {
+ loads++;
+ }
+ return false;
+ }
+
+ public boolean onSave(Object entity,
+ Serializable id,
+ Object[] state,
+ String[] propertyNames,
+ Type[] types) {
+
+ if ( entity instanceof Auditable ) {
+ creates++;
+ for ( int i=0; i<propertyNames.length; i++ ) {
+ if ( "createTimestamp".equals( propertyNames[i] ) ) {
+ state[i] = new Date();
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public void postFlush(Iterator entities) {
+ System.out.println("Creations: " + creates + ", Updates: " + updates);
+ }
+
+ public void afterTransactionCompletion(Transaction tx) {
+ if ( tx.wasCommitted() ) {
+ System.out.println("Creations: " + creates + ", Updates: " + updates, "Loads: " + loads);
+ }
+ updates=0;
+ creates=0;
+ loads=0;
+ }
+
+}]]></programlisting>
+
+ <para>
+ L'intercepteur doit être spécifié quand une session est créée.
+ </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>
+
+ <programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="objectstate-events" revision="3">
+ <title>Système d'événements</title>
+
+ <para>
+ Si vous devez réagir à des événements particuliers dans votre couche de persistance,
+ vous pouvez aussi utiliser l'architecture d'<emphasis>événements</emphasis> d'Hibernate3.
+ Le système d'événements peut être utilisé en supplément ou en remplacement des interceptors.
+ </para>
+
+ <para>
+ Essentiellement toutes les méthodes de l'interface <literal>Session</literal> sont corrélées à
+ un événement. Vous avez un <literal>LoadEvent</literal>, un <literal>FlushEvent</literal>, etc
+ (consultez la DTD du fichier de configuration XML ou le paquet <literal>org.hibernate.event</literal>
+ pour avoir la liste complète des types d'événement définis).
+ Quand une requête est faite à partir d'une de ces méthodes, la
+ <literal>Session</literal> Hibernate génère un événement approprié et le passe
+ au listener configuré pour ce type.
+ Par défaut, ces listeners implémentent le même traitement dans lequel ces méthodes
+ aboutissent toujours.
+ Cependant, vous êtes libre d'implémenter une version personnalisée d'une de ces
+ interfaces de listener (c'est-à-dire, le <literal>LoadEvent</literal> est traité par
+ l'implémentation de l'interface <literal>LoadEventListener</literal> déclarée), dans
+ quel cas leur implémentation devrait être responsable du traitement des
+ requêtes <literal>load()</literal> faites par la <literal>Session</literal>.
+ </para>
+
+ <para>
+ Les listeners devraient effectivement être considérés comme des singletons ; dans le sens
+ où ils sont partagés entre des requêtes, et donc ne devraient pas sauvegarder des états
+ de variables d'instance.
+ </para>
+
+ <para>
+ Un listener personnalisé devrait implémenter l'interface appropriée pour l'événement
+ qu'il veut traiter et/ou étendre une des classes de base (ou même l'événement prêt à
+ l'emploi utilisé par Hibernate comme ceux déclarés non-finaux à cette intention). Les
+ listeners personnalisés peuvent être soit inscrits par programmation à travers l'objet
+ <literal>Configuration</literal>, ou spécifiés la configuration XML d'Hibernate
+ (la configuration déclarative à travers le fichier de propriétés n'est pas supportée).
+ Voici un exemple de listener personnalisé pour l'événement de chargement :
+ </para>
+
+ <programlisting><![CDATA[public class MyLoadListener implements LoadEventListener {
+ // C'est une simple méthode définie par l'interface LoadEventListener
+ public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
+ throws HibernateException {
+ if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
+ throw MySecurityException("Unauthorized access");
+ }
+ }
+}]]></programlisting>
+
+ <para>
+ Vous avez aussi besoin d'une entrée de configuration disant à Hibernate d'utiliser
+ ce listener en plus du listener par défaut :
+ </para>
+
+<programlisting><![CDATA[<hibernate-configuration>
+ <session-factory>
+ ...
+ <event type="load">
+ <listener class="com.eg.MyLoadListener"/>
+ <listener class="org.hibernate.event.def.DefaultLoadEventListener"/>
+ </event>
+ </session-factory>
+</hibernate-configuration>]]></programlisting>
+
+ <para>
+ Vous pouvez aussi l'inscrire par programmation :
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = new Configuration();
+LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() };
+cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
+
+ <para>
+ Les listeners inscrits déclarativement ne peuvent pas partager d'instances. Si le même
+ nom de classe est utilisée dans plusieurs éléments <literal><listener/></literal>,
+ chaque référence sera une instance distincte de cette classe. Si vous avez besoin de la
+ faculté de partager des instances de listener entre plusieurs types de listener, vous devez
+ utiliser l'approche d'inscription par programmation.
+ </para>
+
+ <para>
+ Pourquoi implémenter une interface et définir le type spécifique durant la configuration ?
+ Une implémentation de listener pourrait implémenter plusieurs interfaces de listener
+ d'événements. Avoir en plus le type défini durant l'inscription rend plus facile
+ l'activation ou la désactivation pendant la configuration.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-decl-security" revision="2">
+ <title>Sécurité déclarative d'Hibernate</title>
+ <para>
+ Généralement, la sécurité déclarative dans les applications Hibernate est gérée dans la
+ couche de session. Maintenant, Hibernate3 permet à certaines actions d'être approuvées
+ via JACC, et autorisées via JAAS. Cette fonctionnalité optionnelle est construite
+ au dessus de l'architecture d'événements.
+ </para>
+
+ <para>
+ D'abord, vous devez configurer les listeners d'événements appropriés pour permettre
+ l'utilisation d'autorisations JAAS.
+ </para>
+
+ <programlisting><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
+<listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/>
+<listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/>
+<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
+
+ <para>
+ Notez que <literal><listener type="..." class="..."/></literal> est juste un raccourci
+ pour <literal><event type="..."><listener class="..."/></event></literal>
+ quand il y a exactement un listener pour un type d'événement particulier.
+ </para>
+
+ <para>
+ Ensuite, toujours dans <literal>hibernate.cfg.xml</literal>, lier les permissions aux rôles :
+ </para>
+
+ <programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
+<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
+
+ <para>
+ Les noms de rôle sont les rôles compris par votre fournisseur JAAC.
+ </para>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/example_mappings.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/example_mappings.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/example_mappings.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,657 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="example-mappings">
+ <title>Exemple : quelques mappings</title>
+
+ <para>
+ Ce chapitre montre quelques mappings plus complexes.
+ </para>
+
+ <sect1 id="example-mappings-emp">
+ <title>Employeur/Employé (Employer/Employee)</title>
+
+ <para>
+ Le modèle suivant de relation entre <literal>Employer</literal> et
+ <literal>Employee</literal> utilise une vraie classe entité (<literal>Employment</literal>)
+ pour représenter l'association. On a fait cela parce qu'il peut y avoir plus d'une période
+ d'emploi pour les deux mêmes parties. Des composants sont utilisés pour modéliser les
+ valeurs monétaires et les noms des employés.
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="images/EmployerEmployee.gif" format="GIF" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../shared/images/EmployerEmployee.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ Voici un document de mapping possible :
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Employer" table="employers">
+ <id name="id">
+ <generator class="sequence">
+ <param name="sequence">employer_id_seq</param>
+ </generator>
+ </id>
+ <property name="name"/>
+ </class>
+
+ <class name="Employment" table="employment_periods">
+
+ <id name="id">
+ <generator class="sequence">
+ <param name="sequence">employment_id_seq</param>
+ </generator>
+ </id>
+ <property name="startDate" column="start_date"/>
+ <property name="endDate" column="end_date"/>
+
+ <component name="hourlyRate" class="MonetaryAmount">
+ <property name="amount">
+ <column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>
+ </property>
+ <property name="currency" length="12"/>
+ </component>
+
+ <many-to-one name="employer" column="employer_id" not-null="true"/>
+ <many-to-one name="employee" column="employee_id" not-null="true"/>
+
+ </class>
+
+ <class name="Employee" table="employees">
+ <id name="id">
+ <generator class="sequence">
+ <param name="sequence">employee_id_seq</param>
+ </generator>
+ </id>
+ <property name="taxfileNumber"/>
+ <component name="name" class="Name">
+ <property name="firstName"/>
+ <property name="initial"/>
+ <property name="lastName"/>
+ </component>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Et voici le schéma des tables générées par <literal>SchemaExport</literal>.
+ </para>
+
+ <programlisting><![CDATA[create table employers (
+ id BIGINT not null,
+ name VARCHAR(255),
+ primary key (id)
+)
+
+create table employment_periods (
+ id BIGINT not null,
+ hourly_rate NUMERIC(12, 2),
+ currency VARCHAR(12),
+ employee_id BIGINT not null,
+ employer_id BIGINT not null,
+ end_date TIMESTAMP,
+ start_date TIMESTAMP,
+ primary key (id)
+)
+
+create table employees (
+ id BIGINT not null,
+ firstName VARCHAR(255),
+ initial CHAR(1),
+ lastName VARCHAR(255),
+ taxfileNumber VARCHAR(255),
+ primary key (id)
+)
+
+alter table employment_periods
+ add constraint employment_periodsFK0 foreign key (employer_id) references employers
+alter table employment_periods
+ add constraint employment_periodsFK1 foreign key (employee_id) references employees
+create sequence employee_id_seq
+create sequence employment_id_seq
+create sequence employer_id_seq]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="example-mappings-authorwork">
+ <title>Auteur/Travail (Author/Work)</title>
+
+ <para>
+ Soit le modèle de la relation entre <literal>Work</literal>, <literal>Author</literal>
+ et <literal>Person</literal>. Nous représentons la relation entre <literal>Work</literal>
+ et <literal>Author</literal> comme une association plusieurs-vers-plusieurs. Nous avons choisi de
+ représenter la relation entre <literal>Author</literal> et <literal>Person</literal>
+ comme une association un-vers-un. Une autre possibilité aurait été que
+ <literal>Author</literal> hérite de <literal>Person</literal>.
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="images/AuthorWork.gif" format="GIF" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../shared/images/AuthorWork.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ Le mapping suivant représente exactement ces relations :
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Work" table="works" discriminator-value="W">
+
+ <id name="id" column="id">
+ <generator class="native"/>
+ </id>
+ <discriminator column="type" type="character"/>
+
+ <property name="title"/>
+ <set name="authors" table="author_work">
+ <key column name="work_id"/>
+ <many-to-many class="Author" column name="author_id"/>
+ </set>
+
+ <subclass name="Book" discriminator-value="B">
+ <property name="text"/>
+ </subclass>
+
+ <subclass name="Song" discriminator-value="S">
+ <property name="tempo"/>
+ <property name="genre"/>
+ </subclass>
+
+ </class>
+
+ <class name="Author" table="authors">
+
+ <id name="id" column="id">
+ <!-- The Author must have the same identifier as the Person -->
+ <generator class="assigned"/>
+ </id>
+
+ <property name="alias"/>
+ <one-to-one name="person" constrained="true"/>
+
+ <set name="works" table="author_work" inverse="true">
+ <key column="author_id"/>
+ <many-to-many class="Work" column="work_id"/>
+ </set>
+
+ </class>
+
+ <class name="Person" table="persons">
+ <id name="id" column="id">
+ <generator class="native"/>
+ </id>
+ <property name="name"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Il y a quatre tables dans ce mapping. <literal>works</literal>,
+ <literal>authors</literal> et <literal>persons</literal> qui contiennent
+ respectivement les données de work, author et person.
+ <literal>author_work</literal> est une table d'association qui lie authors
+ à works. Voici le schéma de tables, généré par <literal>SchemaExport</literal>.
+ </para>
+
+ <programlisting><![CDATA[create table works (
+ id BIGINT not null generated by default as identity,
+ tempo FLOAT,
+ genre VARCHAR(255),
+ text INTEGER,
+ title VARCHAR(255),
+ type CHAR(1) not null,
+ primary key (id)
+)
+
+create table author_work (
+ author_id BIGINT not null,
+ work_id BIGINT not null,
+ primary key (work_id, author_id)
+)
+
+create table authors (
+ id BIGINT not null generated by default as identity,
+ alias VARCHAR(255),
+ primary key (id)
+)
+
+create table persons (
+ id BIGINT not null generated by default as identity,
+ name VARCHAR(255),
+ primary key (id)
+)
+
+alter table authors
+ add constraint authorsFK0 foreign key (id) references persons
+alter table author_work
+ add constraint author_workFK0 foreign key (author_id) references authors
+alter table author_work
+ add constraint author_workFK1 foreign key (work_id) references works]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="example-mappings-customerorderproduct">
+ <title>Client/Commande/Produit (Customer/Order/Product)</title>
+
+ <para>
+ Imaginons maintenant le modèle de relation entre <literal>Customer</literal>,
+ <literal>Order</literal>, <literal>LineItem</literal> et <literal>Product</literal>.
+ Il y a une association un-vers-plusieurs entre <literal>Customer</literal> et
+ <literal>Order</literal>, mais comment devrions nous représenter <literal>Order</literal> /
+ <literal>LineItem</literal> / <literal>Product</literal>? J'ai choisi de mapper
+ <literal>LineItem</literal> comme une classe d'association représentant l'association
+ plusieurs-vers-plusieurs entre <literal>Order</literal> et <literal>Product</literal>. Dans
+ Hibernate, on appelle cela un élément composite.
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../shared/images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ Le document de mapping :
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Customer" table="customers">
+ <id name="id">
+ <generator class="native"/>
+ </id>
+ <property name="name"/>
+ <set name="orders" inverse="true">
+ <key column="customer_id"/>
+ <one-to-many class="Order"/>
+ </set>
+ </class>
+
+ <class name="Order" table="orders">
+ <id name="id">
+ <generator class="native"/>
+ </id>
+ <property name="date"/>
+ <many-to-one name="customer" column="customer_id"/>
+ <list name="lineItems" table="line_items">
+ <key column="order_id"/>
+ <list-index column="line_number"/>
+ <composite-element class="LineItem">
+ <property name="quantity"/>
+ <many-to-one name="product" column="product_id"/>
+ </composite-element>
+ </list>
+ </class>
+
+ <class name="Product" table="products">
+ <id name="id">
+ <generator class="native"/>
+ </id>
+ <property name="serialNumber"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ <literal>customers</literal>, <literal>orders</literal>, <literal>line_items</literal> et
+ <literal>products</literal> contiennent les données de customer, order, order line item et product.
+ <literal>line_items</literal> est aussi la table d'association liant orders à products.
+ </para>
+
+ <programlisting><![CDATA[create table customers (
+ id BIGINT not null generated by default as identity,
+ name VARCHAR(255),
+ primary key (id)
+)
+
+create table orders (
+ id BIGINT not null generated by default as identity,
+ customer_id BIGINT,
+ date TIMESTAMP,
+ primary key (id)
+)
+
+create table line_items (
+ line_number INTEGER not null,
+ order_id BIGINT not null,
+ product_id BIGINT,
+ quantity INTEGER,
+ primary key (order_id, line_number)
+)
+
+create table products (
+ id BIGINT not null generated by default as identity,
+ serialNumber VARCHAR(255),
+ primary key (id)
+)
+
+alter table orders
+ add constraint ordersFK0 foreign key (customer_id) references customers
+alter table line_items
+ add constraint line_itemsFK0 foreign key (product_id) references products
+alter table line_items
+ add constraint line_itemsFK1 foreign key (order_id) references orders]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="misc">
+ <title>Divers mappings d'exemple</title>
+
+ <para>
+ Ces exemples sont tous pris de la suite de tests d'Hibernate. Vous en trouverez beaucoup d'autres.
+ Regardez dans le dossier <literal>test</literal> de la distribution d'Hibernate.
+ </para>
+
+ <para>TODO: put words around this stuff</para>
+
+ <sect2 id="example-mappings-typed-onetone">
+ <title>"Typed" one-to-one association</title>
+<programlisting><![CDATA[<class name="Person">
+ <id name="name"/>
+ <one-to-one name="address"
+ cascade="all">
+ <formula>name</formula>
+ <formula>'HOME'</formula>
+ </one-to-one>
+ <one-to-one name="mailingAddress"
+ cascade="all">
+ <formula>name</formula>
+ <formula>'MAILING'</formula>
+ </one-to-one>
+</class>
+
+<class name="Address" batch-size="2"
+ check="addressType in ('MAILING', 'HOME', 'BUSINESS')">
+ <composite-id>
+ <key-many-to-one name="person"
+ column="personName"/>
+ <key-property name="type"
+ column="addressType"/>
+ </composite-id>
+ <property name="street" type="text"/>
+ <property name="state"/>
+ <property name="zip"/>
+</class>]]></programlisting>
+ </sect2>
+
+ <sect2 id="example-mappings-composite-key">
+ <title>Exemple de clef composée</title>
+<programlisting><![CDATA[<class name="Customer">
+
+ <id name="customerId"
+ length="10">
+ <generator class="assigned"/>
+ </id>
+
+ <property name="name" not-null="true" length="100"/>
+ <property name="address" not-null="true" length="200"/>
+
+ <list name="orders"
+ inverse="true"
+ cascade="save-update">
+ <key column="customerId"/>
+ <index column="orderNumber"/>
+ <one-to-many class="Order"/>
+ </list>
+
+</class>
+
+<class name="Order" table="CustomerOrder" lazy="true">
+ <synchronize table="LineItem"/>
+ <synchronize table="Product"/>
+
+ <composite-id name="id"
+ class="Order$Id">
+ <key-property name="customerId" length="10"/>
+ <key-property name="orderNumber"/>
+ </composite-id>
+
+ <property name="orderDate"
+ type="calendar_date"
+ not-null="true"/>
+
+ <property name="total">
+ <formula>
+ ( select sum(li.quantity*p.price)
+ from LineItem li, Product p
+ where li.productId = p.productId
+ and li.customerId = customerId
+ and li.orderNumber = orderNumber )
+ </formula>
+ </property>
+
+ <many-to-one name="customer"
+ column="customerId"
+ insert="false"
+ update="false"
+ not-null="true"/>
+
+ <bag name="lineItems"
+ fetch="join"
+ inverse="true"
+ cascade="save-update">
+ <key>
+ <column name="customerId"/>
+ <column name="orderNumber"/>
+ </key>
+ <one-to-many class="LineItem"/>
+ </bag>
+
+</class>
+
+<class name="LineItem">
+
+ <composite-id name="id"
+ class="LineItem$Id">
+ <key-property name="customerId" length="10"/>
+ <key-property name="orderNumber"/>
+ <key-property name="productId" length="10"/>
+ </composite-id>
+
+ <property name="quantity"/>
+
+ <many-to-one name="order"
+ insert="false"
+ update="false"
+ not-null="true">
+ <column name="customerId"/>
+ <column name="orderNumber"/>
+ </many-to-one>
+
+ <many-to-one name="product"
+ insert="false"
+ update="false"
+ not-null="true"
+ column="productId"/>
+
+</class>
+
+<class name="Product">
+ <synchronize table="LineItem"/>
+
+ <id name="productId"
+ length="10">
+ <generator class="assigned"/>
+ </id>
+
+ <property name="description"
+ not-null="true"
+ length="200"/>
+ <property name="price" length="3"/>
+ <property name="numberAvailable"/>
+
+ <property name="numberOrdered">
+ <formula>
+ ( select sum(li.quantity)
+ from LineItem li
+ where li.productId = productId )
+ </formula>
+ </property>
+
+</class>]]></programlisting>
+ </sect2>
+
+ <sect2 id="example-mappings-composite-key-manytomany">
+ <title>Many-to-many avec une clef composée partagée</title>
+<programlisting><![CDATA[<class name="User" table="`User`">
+ <composite-id>
+ <key-property name="name"/>
+ <key-property name="org"/>
+ </composite-id>
+ <set name="groups" table="UserGroup">
+ <key>
+ <column name="userName"/>
+ <column name="org"/>
+ </key>
+ <many-to-many class="Group">
+ <column name="groupName"/>
+ <formula>org</formula>
+ </many-to-many>
+ </set>
+</class>
+
+<class name="Group" table="`Group`">
+ <composite-id>
+ <key-property name="name"/>
+ <key-property name="org"/>
+ </composite-id>
+ <property name="description"/>
+ <set name="users" table="UserGroup" inverse="true">
+ <key>
+ <column name="groupName"/>
+ <column name="org"/>
+ </key>
+ <many-to-many class="User">
+ <column name="userName"/>
+ <formula>org</formula>
+ </many-to-many>
+ </set>
+</class>
+]]></programlisting>
+ </sect2>
+
+ <sect2 id="example-mappings-content-discrimination">
+ <title>Contenu basé sur une discrimination</title>
+<programlisting><![CDATA[<class name="Person"
+ discriminator-value="P">
+
+ <id name="id"
+ column="person_id"
+ unsaved-value="0">
+ <generator class="native"/>
+ </id>
+
+
+ <discriminator
+ type="character">
+ <formula>
+ case
+ when title is not null then 'E'
+ when salesperson is not null then 'C'
+ else 'P'
+ end
+ </formula>
+ </discriminator>
+
+ <property name="name"
+ not-null="true"
+ length="80"/>
+
+ <property name="sex"
+ not-null="true"
+ update="false"/>
+
+ <component name="address">
+ <property name="address"/>
+ <property name="zip"/>
+ <property name="country"/>
+ </component>
+
+ <subclass name="Employee"
+ discriminator-value="E">
+ <property name="title"
+ length="20"/>
+ <property name="salary"/>
+ <many-to-one name="manager"/>
+ </subclass>
+
+ <subclass name="Customer"
+ discriminator-value="C">
+ <property name="comments"/>
+ <many-to-one name="salesperson"/>
+ </subclass>
+
+</class>]]></programlisting>
+ </sect2>
+
+ <sect2 id="example-mappings-association-alternatekeys" revision="2">
+ <title>Associations sur des clefs alternées</title>
+<programlisting><![CDATA[<class name="Person">
+
+ <id name="id">
+ <generator class="hilo"/>
+ </id>
+
+ <property name="name" length="100"/>
+
+ <one-to-one name="address"
+ property-ref="person"
+ cascade="all"
+ fetch="join"/>
+
+ <set name="accounts"
+ inverse="true">
+ <key column="userId"
+ property-ref="userId"/>
+ <one-to-many class="Account"/>
+ </set>
+
+ <property name="userId" length="8"/>
+
+</class>
+
+<class name="Address">
+
+ <id name="id">
+ <generator class="hilo"/>
+ </id>
+
+ <property name="address" length="300"/>
+ <property name="zip" length="5"/>
+ <property name="country" length="25"/>
+ <many-to-one name="person" unique="true" not-null="true"/>
+
+</class>
+
+<class name="Account">
+ <id name="accountId" length="32">
+ <generator class="uuid"/>
+ </id>
+
+ <many-to-one name="user"
+ column="userId"
+ property-ref="userId"/>
+
+ <property name="type" not-null="true"/>
+
+</class>]]></programlisting>
+ </sect2>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/example_parentchild.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/example_parentchild.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/example_parentchild.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,372 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="example-parentchild">
+ <title>Exemple : Père/Fils</title>
+
+ <para>
+ L'une des premières choses que les nouveaux utilisateurs essaient de faire avec Hibernate est de modéliser
+ une relation père/fils. Il y a deux approches différentes pour cela. Pour un certain nombre de raisons, la méthode la
+ plus courante, en particulier pour les nouveaux utilisateurs, est de modéliser les deux relations <literal>Père</literal>
+ et <literal>Fils</literal> comme des classes entités liées par une association <literal><one-to-many></literal> du
+ <literal>Père</literal> vers le <literal>Fils</literal> (l'autre approche est de déclarer le <literal>Fils</literal>
+ comme un <literal><composite-element></literal>). Il est évident que le sens de l'association un vers plusieurs
+ (dans Hibernate) est bien moins proche du sens habituel d'une relation père/fils que ne l'est celui d'un
+ élément cmposite. Nous allons vous expliquer comment utiliser une association <emphasis>un vers plusieurs bidirectionnelle
+ avec cascade</emphasis> afin de modéliser efficacement et élégamment une relation père/fils, ce n'est vraiment
+ pas difficile !
+ </para>
+
+ <sect1 id="example-parentchild-collections">
+ <title>Une note à propos des collections</title>
+
+ <para>
+ Les collections Hibernate sont considérées comme étant une partie logique
+ de l'entité dans laquelle elles sont contenues ; jamais des entités qu'elle
+ contient. C'est une distinction crutiale ! Les conséquences sont les suivantes :
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Quand nous ajoutons / retirons un objet d'une collection, le numéro de version du
+ propriétaire de la collection est incrémenté.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si un objet qui a été enlevé d'une collection est une instance de type valeur (ex :
+ élément composite), cet objet cessera d'être persistant et son état sera complètement effacé
+ de la base de données. Par ailleurs, ajouter une instance de type valeur dans une collection
+ aura pour conséquence que son état sera immédiatement persistant.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si une entité est enlevée d'une collection (association un-vers-plusieurs
+ ou plusieurs-vers-plusieurs), par défaut, elle ne sera pas effacée. Ce comportement
+ est complètement logique - une modification de l'un des états internes d'une entité
+ ne doit pas causer la disparition de l'entité associée !
+ De même, l'ajout d'une entité dans une collection n'engendre pas,
+ par défaut, la persistance de cette entité.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Le comportement par défaut est donc que l'ajout d'une entité dans une collection créé
+ simplement le lien entre les deux entités, et qu'effacer une entité supprime ce lien.
+ C'est le comportement le plus approprié dans la plupart des cas. Ce comportement n'est
+ cependant pas approprié lorsque la vie du fils est liée au cycle de vie du père.
+ </para>
+
+ </sect1>
+
+ <sect1 id="example-parentchild-bidir">
+ <title>un-vers-plusieurs bidirectionnel</title>
+
+ <para>
+ Supposons que nous ayons une simple association <literal><one-to-many></literal>
+ de <literal>Parent</literal> vers <literal>Child</literal>.
+ </para>
+
+ <programlisting><![CDATA[<set name="children">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+ </set>]]></programlisting>
+
+ <para>
+ Si nous executions le code suivant
+ </para>
+
+ <programlisting><![CDATA[Parent p = .....;
+Child c = new Child();
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+ <para>
+ Hibernate exécuterait deux ordres SQL:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>un <literal>INSERT</literal> pour créer l'enregistrement pour <literal>c</literal></para>
+ </listitem>
+ <listitem>
+ <para>
+ un <literal>UPDATE</literal> pour créer le lien de <literal>p</literal> vers
+ <literal>c</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Ceci est non seuleument inefficace, mais viole aussi toute contrainte <literal>NOT NULL</literal> sur
+ la colonne <literal>parent_id</literal>. Nous pouvons réparer la contrainte de nullité
+ en spécifiant <literal>not-null="true"</literal> dans le mapping de la collection :
+ </para>
+
+ <programlisting><![CDATA[<set name="children">
+ <key column="parent_id" not-null="true"/>
+ <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+ <para>
+ Cependant ce n'est pas la solution recommandée.
+ </para>
+
+ <para>
+ La cause sous jacente à ce comportement est que le lien (la clé étrangère <literal>parent_id</literal>) de
+ <literal>p</literal> vers <literal>c</literal> n'est pas considérée comme faisant partie de l'état
+ de l'objet <literal>Child</literal> et n'est donc pas créé par l'<literal>INSERT</literal>.
+ La solution est donc que ce lien fasse partie du mapping de <literal>Child</literal>.
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="parent" column="parent_id" not-null="true"/>]]></programlisting>
+
+ <para>
+ (Nous avons aussi besoin d'ajouter la propriété <literal>parent</literal> dans la classe <literal>Child</literal>).
+ </para>
+
+ <para>
+ Maintenant que l'état du lien est géré par l'entité <literal>Child</literal>, nous spécifions à la
+ collection de ne pas mettre à jour le lien. Nous utilisons l'attribut <literal>inverse</literal>.
+ </para>
+
+ <programlisting><![CDATA[<set name="children" inverse="true">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+ <para>
+ Le code suivant serait utilisé pour ajouter un nouveau <literal>Child</literal>
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+c.setParent(p);
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+ <para>
+ Maintenant, seul un <literal>INSERT</literal> SQL est nécessaire !
+ </para>
+
+ <para>
+ Pour alléger encore un peu les choses, nous devrions créer une méthode <literal>addChild()</literal>
+ dans <literal>Parent</literal>.
+ </para>
+
+ <programlisting><![CDATA[public void addChild(Child c) {
+ c.setParent(this);
+ children.add(c);
+}]]></programlisting>
+
+ <para>
+ Le code d'ajout d'un <literal>Child</literal> serait alors
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="example-parentchild-cascades">
+ <title>Cycle de vie en cascade</title>
+
+ <para>
+ L'appel explicite de <literal>save()</literal> est un peu fastidieux. Nous pouvons
+ simplifier cela en utilisant les cascades.
+ </para>
+
+ <programlisting><![CDATA[<set name="children" inverse="true" cascade="all">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+ <para>
+ Simplifie le code précédent en
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.flush();]]></programlisting>
+
+ <para>
+ De la même manière, nous n'avons pas à itérer sur les fils lorsque nous sauvons
+ ou effacons un <literal>Parent</literal>. Le code suivant efface <literal>p</literal>
+ et tous ses fils de la base de données.
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+session.delete(p);
+session.flush();]]></programlisting>
+
+ <para>
+ Par contre, ce code
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+c.setParent(null);
+session.flush();]]></programlisting>
+
+ <para>
+ n'effacera pas <literal>c</literal> de la base de données, il enlèvera seulement
+ le lien vers <literal>p</literal> (et causera une violation de contrainte
+ <literal>NOT NULL</literal>, dans ce cas).
+ Vous devez explicitement utiliser <literal>delete()</literal> sur <literal>Child</literal>.
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+session.delete(c);
+session.flush();]]></programlisting>
+
+ <para>
+ Dans notre cas, un <literal>Child</literal> ne peut pas vraiment exister sans son père. Si nous
+ effacons un <literal>Child</literal> de la collection, nous voulons vraiment qu'il soit effacé.
+ Pour cela, nous devons utiliser <literal>cascade="all-delete-orphan"</literal>.
+ </para>
+
+ <programlisting><![CDATA[<set name="children" inverse="true" cascade="all-delete-orphan">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+ <para>
+ A noter : même si le mapping de la collection spécifie <literal>inverse="true"</literal>, les cascades
+ sont toujours assurées par l'itération sur les éléments de la collection. Donc, si vous avez besoin
+ qu'un objet soit enregistré, effacé ou mis à jour par cascade, vous devez l'ajouter dans la colleciton.
+ Il ne suffit pas d'appeler explicitement <literal>setParent()</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="example-parentchild-update">
+ <title>Cascades et <literal>unsaved-value</literal></title>
+
+ <para>
+ Supposons que nous ayons chargé un <literal>Parent</literal> dans une <literal>Session</literal>,
+ que nous l'ayons ensuite modifié et que voulions persiter ces modifications dans une nouvelle session
+ en appelant <literal>update()</literal>.
+ Le <literal>Parent</literal> contiendra une collection de fils et, puisque la cascade est activée,
+ Hibernate a besoin de savoir quels fils viennent d'être instanciés et quels fils proviennent de la base
+ de données. Supposons aussi que <literal>Parent</literal> et <literal>Child</literal> ont tous deux
+ des identifiants du type <literal>Long</literal>.
+ Hibernate utilisera la propriété de l'identifiant et la propriété de la version/horodatage pour déterminer quels fils sont nouveaux
+ (vous pouvez aussi utiliser la propriété version ou timestamp, voir
+ <xref linkend="manipulatingdata-updating-detached"/>).
+ <emphasis>Dans Hibernate3, il n'est plus nécessaire de spécifier
+ une <literal>unsaved-value</literal> explicitement.</emphasis>
+ </para>
+
+ <para>
+ Le code suivant mettra à jour <literal>parent</literal> et <literal>child</literal>
+ et insérera <literal>newChild</literal>.
+ </para>
+
+ <programlisting><![CDATA[//parent et child ont été chargés dans une session précédente
+parent.addChild(child);
+Child newChild = new Child();
+parent.addChild(newChild);
+session.update(parent);
+session.flush();]]></programlisting>
+
+ <para>
+ Ceci est très bien pour des identifiants générés, mais qu'en est-il des identifiants assignés et des
+ identifiants composés ? C'est plus difficile,
+ puisqu'Hibernate ne peut pas utiliser la propriété de l'identifiant pour distinguer un objet
+ nouvellement instancié (avec un identifiant assigné par l'utilisateur) d'un objet chargé dans une session précédente.
+ Dans ce cas, Hibernate utilisera soit la propriété de version ou d'horodatage, soit effectuera vraiment une requête au cache
+ de second niveau, soit, dans le pire des cas, à la base de données, pour voir si la ligne existe.
+ </para>
+
+ <!-- undocumenting
+ <para>
+ There is one further possibility. The <literal>Interceptor</literal> method named
+ <literal>isUnsaved()</literal> lets the application implement its own strategy for distinguishing
+ newly instantiated objects. For example, you could define a base class for your persistent classes.
+ </para>
+
+ <programlisting><![CDATA[public class Persistent {
+ private boolean _saved = false;
+ public void onSave() {
+ _saved=true;
+ }
+ public void onLoad() {
+ _saved=true;
+ }
+ ......
+ public boolean isSaved() {
+ return _saved;
+ }
+}]]></programlisting>
+
+ <para>
+ (The <literal>saved</literal> property is non-persistent.)
+ Now implement <literal>isUnsaved()</literal>, along with <literal>onLoad()</literal>
+ and <literal>onSave()</literal> as follows.
+ </para>
+
+ <programlisting><![CDATA[public Boolean isUnsaved(Object entity) {
+ if (entity instanceof Persistent) {
+ return new Boolean( !( (Persistent) entity ).isSaved() );
+ }
+ else {
+ return null;
+ }
+}
+
+public boolean onLoad(Object entity,
+ Serializable id,
+ Object[] state,
+ String[] propertyNames,
+ Type[] types) {
+
+ if (entity instanceof Persistent) ( (Persistent) entity ).onLoad();
+ return false;
+}
+
+public boolean onSave(Object entity,
+ Serializable id,
+ Object[] state,
+ String[] propertyNames,
+ Type[] types) {
+
+ if (entity instanceof Persistent) ( (Persistent) entity ).onSave();
+ return false;
+}]]></programlisting>
+
+ <para>
+ Don't worry; in Hibernate3 you don't need to write any of this kind of code if you don't want to.
+ </para>
+ -->
+ </sect1>
+
+ <sect1 id="example-parentchild-conclusion">
+ <title>Conclusion</title>
+
+ <para>
+ Il y a quelques principes à maîtriser dans ce chapitre et tout cela peut paraître déroutant la première fois.
+ Cependant, dans la pratique, tout fonctionne parfaitement. La plupart des applications Hibernate utilisent
+ le pattern père / fils.
+ </para>
+
+ <para>
+ Nous avons évoqué une alternative dans le premier paragraphe. Aucun des points traités précédemment n'existe
+ dans le cas d'un mapping <literal><composite-element></literal> qui possède exactement la sémantique
+ d'une relation père / fils. Malheureusement, il y a deux grandes limitations pour les classes éléments
+ composites : les éléments composites ne peuvent contenir de collections, et ils ne peuvent être les fils
+ d'entités autres que l'unique parent.
+ </para>
+
+ </sect1>
+
+</chapter>
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/example_weblog.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/example_weblog.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/example_weblog.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,432 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="example-weblog">
+ <title>Exemple : application Weblog</title>
+
+ <sect1 id="example-weblog-classes">
+ <title>Classes persistantes</title>
+
+ <para>
+ Les classes persistantes representent un weblog, et un article posté
+ dans un weblog. Il seront modélisés comme une relation père/fils
+ standard, mais nous allons utiliser un "bag" trié au lieu d'un set.
+
+ </para>
+
+ <programlisting><![CDATA[package eg;
+
+import java.util.List;
+
+public class Blog {
+ private Long _id;
+ private String _name;
+ private List _items;
+
+ public Long getId() {
+ return _id;
+ }
+ public List getItems() {
+ return _items;
+ }
+ public String getName() {
+ return _name;
+ }
+ public void setId(Long long1) {
+ _id = long1;
+ }
+ public void setItems(List list) {
+ _items = list;
+ }
+ public void setName(String string) {
+ _name = string;
+ }
+}]]></programlisting>
+
+ <programlisting><![CDATA[package eg;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+
+public class BlogItem {
+ private Long _id;
+ private Calendar _datetime;
+ private String _text;
+ private String _title;
+ private Blog _blog;
+
+ public Blog getBlog() {
+ return _blog;
+ }
+ public Calendar getDatetime() {
+ return _datetime;
+ }
+ public Long getId() {
+ return _id;
+ }
+ public String getText() {
+ return _text;
+ }
+ public String getTitle() {
+ return _title;
+ }
+ public void setBlog(Blog blog) {
+ _blog = blog;
+ }
+ public void setDatetime(Calendar calendar) {
+ _datetime = calendar;
+ }
+ public void setId(Long long1) {
+ _id = long1;
+ }
+ public void setText(String string) {
+ _text = string;
+ }
+ public void setTitle(String string) {
+ _title = string;
+ }
+}]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="example-weblog-mappings">
+ <title>Mappings Hibernate</title>
+
+ <para>
+ Le mapping XML doit maintenant être relativement simple à vos yeux.
+ </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">
+
+<hibernate-mapping package="eg">
+
+ <class
+ name="Blog"
+ table="BLOGS">
+
+ <id
+ name="id"
+ column="BLOG_ID">
+
+ <generator class="native"/>
+
+ </id>
+
+ <property
+ name="name"
+ column="NAME"
+ not-null="true"
+ unique="true"/>
+
+ <bag
+ name="items"
+ inverse="true"
+ order-by="DATE_TIME"
+ cascade="all">
+
+ <key column="BLOG_ID"/>
+ <one-to-many class="BlogItem"/>
+
+ </bag>
+
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <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">
+
+<hibernate-mapping package="eg">
+
+ <class
+ name="BlogItem"
+ table="BLOG_ITEMS"
+ dynamic-update="true">
+
+ <id
+ name="id"
+ column="BLOG_ITEM_ID">
+
+ <generator class="native"/>
+
+ </id>
+
+ <property
+ name="title"
+ column="TITLE"
+ not-null="true"/>
+
+ <property
+ name="text"
+ column="TEXT"
+ not-null="true"/>
+
+ <property
+ name="datetime"
+ column="DATE_TIME"
+ not-null="true"/>
+
+ <many-to-one
+ name="blog"
+ column="BLOG_ID"
+ not-null="true"/>
+
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="example-weblog-code">
+ <title>Code Hibernate</title>
+
+ <para>
+ La classe suivante montre quelques utilisations que nous pouvons faire
+ de ces classes.
+ </para>
+
+ <programlisting><![CDATA[package eg;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+
+public class BlogMain {
+
+ private SessionFactory _sessions;
+
+ public void configure() throws HibernateException {
+ _sessions = new Configuration()
+ .addClass(Blog.class)
+ .addClass(BlogItem.class)
+ .buildSessionFactory();
+ }
+
+ public void exportTables() throws HibernateException {
+ Configuration cfg = new Configuration()
+ .addClass(Blog.class)
+ .addClass(BlogItem.class);
+ new SchemaExport(cfg).create(true, true);
+ }
+
+ public Blog createBlog(String name) throws HibernateException {
+
+ Blog blog = new Blog();
+ blog.setName(name);
+ blog.setItems( new ArrayList() );
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ try {
+ tx = session.beginTransaction();
+ session.persist(blog);
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return blog;
+ }
+
+ public BlogItem createBlogItem(Blog blog, String title, String text)
+ throws HibernateException {
+
+ BlogItem item = new BlogItem();
+ item.setTitle(title);
+ item.setText(text);
+ item.setBlog(blog);
+ item.setDatetime( Calendar.getInstance() );
+ blog.getItems().add(item);
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ try {
+ tx = session.beginTransaction();
+ session.update(blog);
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return item;
+ }
+
+ public BlogItem createBlogItem(Long blogid, String title, String text)
+ throws HibernateException {
+
+ BlogItem item = new BlogItem();
+ item.setTitle(title);
+ item.setText(text);
+ item.setDatetime( Calendar.getInstance() );
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ try {
+ tx = session.beginTransaction();
+ Blog blog = (Blog) session.load(Blog.class, blogid);
+ item.setBlog(blog);
+ blog.getItems().add(item);
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return item;
+ }
+
+ public void updateBlogItem(BlogItem item, String text)
+ throws HibernateException {
+
+ item.setText(text);
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ try {
+ tx = session.beginTransaction();
+ session.update(item);
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ }
+
+ public void updateBlogItem(Long itemid, String text)
+ throws HibernateException {
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ try {
+ tx = session.beginTransaction();
+ BlogItem item = (BlogItem) session.load(BlogItem.class, itemid);
+ item.setText(text);
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ }
+
+ public List listAllBlogNamesAndItemCounts(int max)
+ throws HibernateException {
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ List result = null;
+ try {
+ tx = session.beginTransaction();
+ Query q = session.createQuery(
+ "select blog.id, blog.name, count(blogItem) " +
+ "from Blog as blog " +
+ "left outer join blog.items as blogItem " +
+ "group by blog.name, blog.id " +
+ "order by max(blogItem.datetime)"
+ );
+ q.setMaxResults(max);
+ result = q.list();
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return result;
+ }
+
+ public Blog getBlogAndAllItems(Long blogid)
+ throws HibernateException {
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ Blog blog = null;
+ try {
+ tx = session.beginTransaction();
+ Query q = session.createQuery(
+ "from Blog as blog " +
+ "left outer join fetch blog.items " +
+ "where blog.id = :blogid"
+ );
+ q.setParameter("blogid", blogid);
+ blog = (Blog) q.uniqueResult();
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return blog;
+ }
+
+ public List listBlogsAndRecentItems() throws HibernateException {
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ List result = null;
+ try {
+ tx = session.beginTransaction();
+ Query q = session.createQuery(
+ "from Blog as blog " +
+ "inner join blog.items as blogItem " +
+ "where blogItem.datetime > :minDate"
+ );
+
+ Calendar cal = Calendar.getInstance();
+ cal.roll(Calendar.MONTH, false);
+ q.setCalendar("minDate", cal);
+
+ result = q.list();
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return result;
+ }
+}]]></programlisting>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/filters.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/filters.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/filters.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="filters">
+ <title>Filtrer les données</title>
+
+ <para>
+ Hibernate3 fournit une nouvelle approche innovatrice pour gérer des données
+ avec des règles de "visibilité". Un <emphasis>filtre Hibernate</emphasis> est un filtre
+ global, nommé, paramétré qui peut être activé ou désactivé pour une session Hibernate
+ particulière.
+ </para>
+
+ <sect1 id="objectstate-filters">
+ <title>Filtres Hibernate</title>
+
+ <para>
+ Hibernate3 ajoute la capacité de prédéfinir des critères de filtre et d'attacher ces
+ filtres à une classe ou à une collection. Un critère de filtre est la faculté de définir
+ une clause de restriction très similaire à l'attribut "where" existant disponible sur
+ une classe et divers éléments d'une collection. Mis à part que ces conditions de filtre
+ peuvent être paramétrées. L'application peut alors prendre la décision à l'exécution
+ si des filtres donnés devraient être activés et quels devraient être leurs paramètres.
+ Des filtres peuvent être utilisés comme des vues de base de données, mais paramétrées
+ dans l'application.
+ </para>
+
+ <para>
+ Afin d'utiliser des filtres, ils doivent d'abord être définis, puis attachés aux éléments
+ de mapping appropriés. Pour définir un filtre, utilisez l'élément <literal><filter-def/></literal>
+ dans un élément <literal><hibernate-mapping/></literal> :
+ </para>
+
+ <programlisting><![CDATA[<filter-def name="myFilter">
+ <filter-param name="myFilterParam" type="string"/>
+</filter-def>]]></programlisting>
+
+ <para>
+ Puis, ce filtre peut être attaché à une classe :
+ </para>
+
+ <programlisting><![CDATA[<class name="myClass" ...>
+ ...
+ <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</class>]]></programlisting>
+
+ <para>
+ ou à une collection :
+ </para>
+
+ <programlisting><![CDATA[<set ...>
+ <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</set>]]></programlisting>
+
+ <para>
+ ou même aux deux (ou à plusieurs de chaque) en même temps.
+ </para>
+
+ <para>
+ Les méthodes sur <literal>Session</literal> sont : <literal>enableFilter(String filterName)</literal>,
+ <literal>getEnabledFilter(String filterName)</literal>, et <literal>disableFilter(String filterName)</literal>.
+ Par défaut, les filtres <emphasis>ne sont pas</emphasis> activés pour une session donnée ;
+ ils doivent être explicitement activés en appelant la méthode
+ <literal>Session.enabledFilter()</literal>, laquelle retourne une instance de l'interface
+ <literal>Filter</literal>. Utiliser le simple filtre défini au-dessus ressemblerait à :
+ </para>
+
+ <programlisting><![CDATA[session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");]]></programlisting>
+
+ <para>
+ Notez que des méthodes sur l'interface org.hibernate.Filter autorisent le chaînage de beaucoup
+ de méthodes communes d'Hibernate.
+ </para>
+
+ <para>
+ Un exemple complet, utilisant des données temporelles avec une structure de date
+ d'enregistrement effectif :
+ </para>
+
+ <programlisting><![CDATA[<filter-def name="effectiveDate">
+ <filter-param name="asOfDate" type="date"/>
+</filter-def>
+
+<class name="Employee" ...>
+...
+ <many-to-one name="department" column="dept_id" class="Department"/>
+ <property name="effectiveStartDate" type="date" column="eff_start_dt"/>
+ <property name="effectiveEndDate" type="date" column="eff_end_dt"/>
+...
+ <!--
+ Note that this assumes non-terminal records have an eff_end_dt set to
+ a max db date for simplicity-sake
+ -->
+ <filter name="effectiveDate"
+ condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+</class>
+
+<class name="Department" ...>
+...
+ <set name="employees" lazy="true">
+ <key column="dept_id"/>
+ <one-to-many class="Employee"/>
+ <filter name="effectiveDate"
+ condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+ </set>
+</class>]]></programlisting>
+
+ <para>
+ Puis, afin de s'assurer que vous pouvez toujours récupérer les enregistrements actuellement
+ effectifs, activez simplement le filtre sur la session avant de récupérer des données des
+ employés :
+ </para>
+
+<programlisting><![CDATA[Session session = ...;
+session.enabledFilter("effectiveDate").setParameter("asOfDate", new Date());
+List results = session.createQuery("from Employee as e where e.salary > :targetSalary")
+ .setLong("targetSalary", new Long(1000000))
+ .list();
+]]></programlisting>
+
+ <para>
+ Dans le HQL ci-dessus, bien que nous ayons seulement mentionné une contrainte de
+ salaire sur les resultats, à cause du filtre activé, la requête retournera seulement
+ les employés actuellement actifs qui ont un salaire supérieur à un million de dollars.
+ </para>
+
+ <para>
+ A noter : si vous prévoyez d'utiliser des filtres avec des jointures externes (soit
+ à travers HQL, soit par le chargement) faites attention à la direction de l'expression
+ de condition. Il est plus sûr de la positionner pour les jointures externes à gauche ;
+ en général, placez le paramètre d'abord, suivi du(des) nom(s) de colonne après l'opérateur.
+ </para>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/inheritance_mapping.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/inheritance_mapping.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/inheritance_mapping.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,483 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="inheritance">
+ <title>Mapping d'héritage de classe</title>
+
+ <sect1 id="inheritance-strategies" revision="3">
+ <title>Les trois stratégies</title>
+
+ <para>
+ Hibernate supporte les trois stratégies d'héritage de base :
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ une table par hiérarchie de classe (table per class hierarchy)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ une table par classe fille (table per subclass)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ une table par classe concrète (table per concrete class)
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Hibernate supporte en plus une quatrièmestratégie, légèrement différente, qui supporte le polymorphisme :
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ le polymorphisme implicite
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Il est possible d'utiliser différentes stratégies de mapping pour différentes branches d'une même
+ hiérarchie d'héritage, et alors d'employer le polymorphisme implicite pour réaliser le
+ polymorphisme à travers toute la hiérarchie. Pourtant, Hibernate ne supporte pas de mélanger
+ des mappings <literal><subclass></literal> et
+ <literal><joined-subclass></literal> et <literal><union-subclass></literal>
+ pour le même élément <literal><class></literal> racine.
+ Il est possible de mélanger ensemble les stratégies d'une table par hiérarchie et d'une
+ table par sous-classe, pour le même élément <literal><class></literal>, en combinant
+ les éléments <literal><subclass></literal> et <literal><join></literal> (voir dessous).
+ </para>
+
+ <para>
+ Il est possible de définir des mappings de <literal>subclass</literal>, <literal>union-subclass</literal>,
+ et <literal>joined-subclass</literal> dans des documents de mapping séparés, directement sous
+ <literal>hibernate-mapping</literal>. Ceci vous permet d'étendre une hiérarchie de classe juste en
+ ajoutant un nouveau fichier de mapping. Vous devez spécifier un attribut <literal>extends</literal>
+ dans le mapping de la sous-classe, en nommant une super-classe précédemment mappée. Note :
+ précédemment cette foncionnalité rendait l'ordre des documents de mapping important. Depuis
+ Hibernate3, l'ordre des fichier de mapping n'importe plus lors de l'utilisation du mot-clef "extends".
+ L'ordre à l'intérieur d'un simple fichier de mapping impose encore de définir les classes mères
+ avant les classes filles.
+ </para>
+
+ <programlisting><![CDATA[
+ <hibernate-mapping>
+ <subclass name="DomesticCat" extends="Cat" discriminator-value="D">
+ <property name="name" type="string"/>
+ </subclass>
+ </hibernate-mapping>]]></programlisting>
+
+
+ <sect2 id="inheritance-tableperclass" >
+ <title>Une table par hiérarchie de classe</title>
+
+ <para>
+ Supposons que nous ayons une interface <literal>Payment</literal>, implémentée
+ par <literal>CreditCardPayment</literal>, <literal>CashPayment</literal>,
+ <literal>ChequePayment</literal>. La stratégie une table par hiérarchie serait :
+ </para>
+
+ <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+ <id name="id" type="long" column="PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <discriminator column="PAYMENT_TYPE" type="string"/>
+ <property name="amount" column="AMOUNT"/>
+ ...
+ <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+ <property name="creditCardType" column="CCTYPE"/>
+ ...
+ </subclass>
+ <subclass name="CashPayment" discriminator-value="CASH">
+ ...
+ </subclass>
+ <subclass name="ChequePayment" discriminator-value="CHEQUE">
+ ...
+ </subclass>
+</class>]]></programlisting>
+
+ <para>
+ Une seule table est requise. Une grande limitation de cette
+ stratégie est que les colonnes déclarées par les classes filles, telles que <literal>CCTYPE</literal>,
+ ne peuvent avoir de contrainte <literal>NOT NULL</literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="inheritance-tablepersubclass">
+ <title>Une table par classe fille</title>
+
+ <para>
+ La stratégie une table par classe fille serait :
+ </para>
+
+ <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+ <id name="id" type="long" column="PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <property name="amount" column="AMOUNT"/>
+ ...
+ <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ <property name="creditCardType" column="CCTYPE"/>
+ ...
+ </joined-subclass>
+ <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ ...
+ </joined-subclass>
+ <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ ...
+ </joined-subclass>
+</class>]]></programlisting>
+
+ <para>
+ Quatre tables sont requises. Les trois tables des classes filles ont
+ une clé primaire associée à la table classe mère (le modèle relationnel
+ est une association un-vers-un).
+ </para>
+
+ </sect2>
+
+ <sect2 id="inheritance-tablepersubclass-discriminator" revision="2">
+ <title>Une table par classe fille, en utilisant un discriminant</title>
+
+ <para>
+ Notez que l'implémentation Hibernate de la stratégie un table par
+ classe fille ne nécessite pas de colonne discriminante dans la table
+ classe mère. D'autres implémentations de mappers Objet/Relationnel utilisent
+ une autre implémentation de la stratégie une table par classe fille qui nécessite
+ une colonne de type discriminant dans la table de la classe mère. L'approche
+ prise par Hibernate est plus difficile à implémenter mais plus correcte
+ d'une point de vue relationnel. Si vous aimeriez utiliser
+ une colonne discriminante avec la stratégie d'une table par classe fille, vous pourriez combiner
+ l'utilisation de <literal><subclass></literal> et
+ <literal><join></literal>, comme suit :
+ </para>
+
+ <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+ <id name="id" type="long" column="PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <discriminator column="PAYMENT_TYPE" type="string"/>
+ <property name="amount" column="AMOUNT"/>
+ ...
+ <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+ <join table="CREDIT_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ <property name="creditCardType" column="CCTYPE"/>
+ ...
+ </join>
+ </subclass>
+ <subclass name="CashPayment" discriminator-value="CASH">
+ <join table="CASH_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ ...
+ </join>
+ </subclass>
+ <subclass name="ChequePayment" discriminator-value="CHEQUE">
+ <join table="CHEQUE_PAYMENT" fetch="select">
+ <key column="PAYMENT_ID"/>
+ ...
+ </join>
+ </subclass>
+</class>]]></programlisting>
+
+ <para>
+ La déclaration optionnelle <literal>fetch="select"</literal> indique à Hibernate
+ de ne pas récupérer les données de la classe fille <literal>ChequePayment</literal> par une jointure externe lors des requêtes sur la classe mère.
+ </para>
+
+ </sect2>
+
+ <sect2 id="inheritance-mixing-tableperclass-tablepersubclass">
+ <title>Mélange d'une table par hiérarchie de classe avec une table par classe fille</title>
+
+ <para>
+ Vous pouvez même mélanger les stratégies d'une table par hiérarchie de classe et d'une table par classe fille en utilisant cette approche :
+ </para>
+
+ <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+ <id name="id" type="long" column="PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <discriminator column="PAYMENT_TYPE" type="string"/>
+ <property name="amount" column="AMOUNT"/>
+ ...
+ <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+ <join table="CREDIT_PAYMENT">
+ <property name="creditCardType" column="CCTYPE"/>
+ ...
+ </join>
+ </subclass>
+ <subclass name="CashPayment" discriminator-value="CASH">
+ ...
+ </subclass>
+ <subclass name="ChequePayment" discriminator-value="CHEQUE">
+ ...
+ </subclass>
+</class>]]></programlisting>
+
+ <para>
+ Pour importe laquelle de ces stratégies, une association polymorphique vers la classe racine
+ <literal>Payment</literal> est mappée en utilisant <literal><many-to-one></literal>.
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="inheritance-tableperconcrete" revision="2">
+ <title>Une table par classe concrète</title>
+
+ <para>
+ Il y a deux manières d'utiliser la stratégie d'une table par classe concrète. La première
+ est d'employer <literal><union-subclass></literal>.
+ </para>
+
+ <programlisting><![CDATA[<class name="Payment">
+ <id name="id" type="long" column="PAYMENT_ID">
+ <generator class="sequence"/>
+ </id>
+ <property name="amount" column="AMOUNT"/>
+ ...
+ <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+ <property name="creditCardType" column="CCTYPE"/>
+ ...
+ </union-subclass>
+ <union-subclass name="CashPayment" table="CASH_PAYMENT">
+ ...
+ </union-subclass>
+ <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+ ...
+ </union-subclass>
+</class>]]></programlisting>
+
+ <para>
+ Trois tables sont nécessaires pour les classes filles. Chaque table définit des colonnes
+ pour toutes les propriétés de la classe, incluant les propriétés héritéés.
+ </para>
+
+ <para>
+ La limitation de cette approche est que si une propriété est mappée sur la classe mère, le nom
+ de la colonne doit être le même pour toutes les classes filles. (Nous pourrions être plus souple
+ dans une future version d'Hibernate).
+ La stratégie du générateur d'identifiant n'est pas permise dans l'héritage de classes filles par
+ union, en effet la valeur (NdT : seed) de la clef primaire
+ doit être partagée par toutes les classes filles "union" d'une hiérarchie.
+ </para>
+
+ <para>
+ Si votre classe mère est abstraite, mappez la avec <literal>abstract="true"</literal>.
+ Bien sûr, si elle n'est pas abstraite, une table supplémentaire (par défaut,
+ <literal>PAYMENT</literal> dans l'exemple ci-dessus) est requise pour contenir des instances
+ de la classe mère.
+ </para>
+
+ </sect2>
+
+ <sect2 id="inheritance-tableperconcreate-polymorphism">
+ <title>Une table par classe concrète, en utilisant le polymorphisme implicite</title>
+
+ <para>
+ Une approche alternative est l'emploi du polymorphisme implicite :
+ </para>
+
+ <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+ <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <property name="amount" column="CREDIT_AMOUNT"/>
+ ...
+</class>
+
+<class name="CashPayment" table="CASH_PAYMENT">
+ <id name="id" type="long" column="CASH_PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <property name="amount" column="CASH_AMOUNT"/>
+ ...
+</class>
+
+<class name="ChequePayment" table="CHEQUE_PAYMENT">
+ <id name="id" type="long" column="CHEQUE_PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <property name="amount" column="CHEQUE_AMOUNT"/>
+ ...
+</class>]]></programlisting>
+
+ <para>
+ Notez que nulle part nous ne mentionnons l'interface <literal>Payment</literal> explicitement.
+ Notez aussi que des propriétés de <literal>Payment</literal> sont mappées dans
+ chaque classe fille. Si vous voulez éviter des duplications, considérez l'utilisation des
+ entités XML (cf. <literal>[ <!ENTITY allproperties SYSTEM "allproperties.xml"> ]</literal>
+ dans la déclaration du <literal>DOCTYPE</literal> et <literal>&allproperties;</literal> dans le mapping).
+ </para>
+
+ <para>
+ L'inconvénient de cette approche est qu'Hibernate ne génère pas d'<literal>UNION</literal>s SQL
+ lors de l'exécution des requêtes polymorphiques.
+ </para>
+
+ <para>
+ Pour cette stratégie de mapping, une association polymorphique pour <literal>Payment</literal>
+ est habituellement mappée en utilisant <literal><any></literal>.
+ </para>
+
+ <programlisting><![CDATA[<any name="payment" meta-type="string" id-type="long">
+ <meta-value value="CREDIT" class="CreditCardPayment"/>
+ <meta-value value="CASH" class="CashPayment"/>
+ <meta-value value="CHEQUE" class="ChequePayment"/>
+ <column name="PAYMENT_CLASS"/>
+ <column name="PAYMENT_ID"/>
+</any>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="inheritace-mixingpolymorphism">
+ <title>Mélange du polymorphisme implicite avec d'autres mappings d'héritage</title>
+
+ <para>
+ Il y a une chose supplémentaire à noter à propos de ce mapping. Puisque les classes filles sont
+ chacune mappées avec leur propre élément <literal><class></literal> (et puisque
+ <literal>Payment</literal> est juste une interface), chaque classe fille pourrait
+ facilement faire partie d'une autre hiérarchie
+ d'héritage ! (Et vous pouvez encore faire des requêtes polymorphiques pour l'interface <literal>Payment</literal>).
+ </para>
+
+ <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+ <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <discriminator column="CREDIT_CARD" type="string"/>
+ <property name="amount" column="CREDIT_AMOUNT"/>
+ ...
+ <subclass name="MasterCardPayment" discriminator-value="MDC"/>
+ <subclass name="VisaPayment" discriminator-value="VISA"/>
+</class>
+
+<class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
+ <id name="id" type="long" column="TXN_ID">
+ <generator class="native"/>
+ </id>
+ ...
+ <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ <property name="amount" column="CASH_AMOUNT"/>
+ ...
+ </joined-subclass>
+ <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ <property name="amount" column="CHEQUE_AMOUNT"/>
+ ...
+ </joined-subclass>
+</class>]]></programlisting>
+
+ <para>
+ Encore une fois, nous ne mentionnons pas explicitement <literal>Payment</literal>.
+ Si nous exécutons une requête sur l'interface <literal>Payment</literal> - par
+ exemple, <literal>from Payment</literal> - Hibernate retournera
+ automatiquement les instances de <literal>CreditCardPayment</literal>
+ (et ses classes filles puisqu'elles implémentent aussi <literal>Payment</literal>),
+ <literal>CashPayment</literal> et <literal>ChequePayment</literal> mais pas
+ les instances de <literal>NonelectronicTransaction</literal>.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="inheritance-limitations">
+ <title>Limitations</title>
+
+ <para>
+ Il y a certaines limitations à l'approche du "polymorphisme implicite"
+ pour la stratégie de mapping d'une table par classe concrète.
+ Il y a plutôt moins de limitations restrictives aux mappings <literal><union-subclass></literal>.
+ </para>
+
+ <para>
+ La table suivante montre les limitations des mappings d'une table par classe concrète, et du polymorphisme implicite, dans Hibernate.
+ </para>
+
+ <table frame="topbot">
+ <title>Caractéristiques du mapping d'héritage</title>
+ <tgroup cols='8' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <colspec colname='c3' colwidth="1*"/>
+ <colspec colname='c4' colwidth="1*"/>
+ <colspec colname='c5' colwidth="1*"/>
+ <colspec colname='c6' colwidth="1*"/>
+ <colspec colname='c7' colwidth="1*"/>
+ <colspec colname='c8' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Stratégie d'héritage</entry>
+ <entry>many-to-one polymorphique</entry>
+ <entry>one-to-one polymorphique</entry>
+ <entry>one-to-many polymorphique</entry>
+ <entry>many-to-many polymorphique</entry>
+ <entry><literal>load()/get()</literal> polymorphique</entry>
+ <entry>Requêtes polymorphiques</entry>
+ <entry>Jointures polymorphiques</entry>
+ <entry>Récupération par jointure externe</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>une table par hiérarchie de classe</entry>
+ <entry><literal><many-to-one></literal></entry>
+ <entry><literal><one-to-one></literal></entry>
+ <entry><literal><one-to-many></literal></entry>
+ <entry><literal><many-to-many></literal></entry>
+ <entry><literal>s.get(Payment.class, id)</literal></entry>
+ <entry><literal>from Payment p</literal></entry>
+ <entry><literal>from Order o join o.payment p</literal></entry>
+ <entry><emphasis>supportée</emphasis></entry>
+ </row>
+ <row>
+ <entry>une table par classe fille</entry>
+ <entry><literal><many-to-one></literal></entry>
+ <entry><literal><one-to-one></literal></entry>
+ <entry><literal><one-to-many></literal></entry>
+ <entry><literal><many-to-many></literal></entry>
+ <entry><literal>s.get(Payment.class, id)</literal></entry>
+ <entry><literal>from Payment p</literal></entry>
+ <entry><literal>from Order o join o.payment p</literal></entry>
+ <entry><emphasis>supportée</emphasis></entry>
+ </row>
+ <row>
+ <entry>une table par classe concrète (union-subclass)</entry>
+ <entry><literal><many-to-one></literal></entry>
+ <entry><literal><one-to-one></literal></entry>
+ <entry><literal><one-to-many></literal> (pour <literal>inverse="true"</literal> seulement)</entry>
+ <entry><literal><many-to-many></literal></entry>
+ <entry><literal>s.get(Payment.class, id)</literal></entry>
+ <entry><literal>from Payment p</literal></entry>
+ <entry><literal>from Order o join o.payment p</literal></entry>
+ <entry><emphasis>supportée</emphasis></entry>
+ </row>
+ <row>
+ <entry>une table par classe concrète (polymorphisme implicite)</entry>
+ <entry><literal><any></literal></entry>
+ <entry><emphasis>non supporté</emphasis></entry>
+ <entry><emphasis>non supporté</emphasis></entry>
+ <entry><literal><many-to-any></literal></entry>
+ <entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
+ <entry><literal>from Payment p</literal></entry>
+ <entry><emphasis>non supportées</emphasis></entry>
+ <entry><emphasis>non supportée</emphasis></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/performance.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/performance.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/performance.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,1451 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="performance">
+ <title>Améliorer les performances</title>
+
+ <sect1 id="performance-fetching" revision="2">
+ <title>Stratégies de chargement</title>
+
+ <para>
+ Une <emphasis>stratégie de chargement</emphasis> est une stratégie qu'Hibernate va
+ utiliser pour récupérer des objets associés si l'application à besoin de naviguer à
+ travers une association.
+ Les stratégies de chargement peuvent être déclarées dans les méta-données de l'outil
+ de mapping objet relationnel ou surchargées par une requête de type HQL ou <literal>Criteria</literal>
+ particulière.
+ </para>
+
+ <para>
+ Hibernate3 définit les stratégies de chargement suivantes :
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Chargement par jointure</emphasis> - Hibernate récupère
+ l'instance associée ou la collection dans un même <literal>SELECT</literal>,
+ en utilisant un <literal>OUTER JOIN</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Chargement par select</emphasis> - Un second <literal>SELECT</literal>
+ est utilisé pour récupérer l'instance associée ou la collection. A moins
+ que vous ne désactiviez explicitement le chargement tardif en spécifiant
+ <literal>lazy="false"</literal>, ce second select ne sera exécuté que lorsque
+ vous accéderez réellement à l'association.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Chargement par sous-select</emphasis> - Un second <literal>SELECT</literal>
+ est utilisé pour récupérer les associations pour toutes les entités récupérées dans
+ une requête ou un chargement préalable. A moins
+ que vous ne désactiviez explicitement le chargement tardif en spécifiant
+ <literal>lazy="false"</literal>, ce second select ne sera exécuté que lorsque
+ vous accéderez réellement à l'association.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Chargement par lot</emphasis> - Il s'agit d'une stratégie d'optimisation
+ pour le chargement par select - Hibernate récupère un lot
+ d'instances ou de collections en un seul <literal>SELECT</literal> en spécifiant
+ une liste de clé primaire ou de clé étrangère.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Hibernate fait également la distinction entre :
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Chargement immédiat</emphasis> - Une association, une collection ou
+ un attribut est chargé immédiatement lorsque l'objet auquel appartient cet
+ élément est chargé.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Chargement tardif d'une collection</emphasis> - Une collection est
+ chargée lorque l'application invoque une méthode sur cette collection (il s'agit
+ du mode de chargement par défaut pour les collections).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Chargement "super tardif" d'une collection</emphasis> - les
+ éléments de la collection sont récupérés individuellement depuis la base de données
+ lorsque nécessaire.
+ Hibernate essaie de ne pas charger toute la collection en mémoire sauf si cela est
+ absolument nécessaire (bien adapté aux très grandes collections).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Chargement par proxy</emphasis> - une association vers un seul
+ objet est chargée lorsqu'une méthode autre que le getter sur l'identifiant est
+ appelée sur l'objet associé.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Chargement "sans proxy"</emphasis> - une association vers un seul objet
+ est chargée lorsque l'on accède à cet objet. Par rapport au chargement par proxy,
+ cette approche est moins tardif (l'association est quand même chargée même
+ si on n'accède qu'à l'identifiant) mais plus transparente car il n'y a pas de proxy
+ visible dans l'application. Cette approche requiert une instrumentation du bytecode
+ à la compilation et est rarement nécessaire.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Chargement tardif des attributs</emphasis> - Un attribut ou un
+ objet associé seul est chargé lorsque l'on y accède. Cette approche requiert
+ une instrumentation du bytecode à la compilation et est rarement nécessaire.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Nous avons ici deux notions orthogonales : <emphasis>quand</emphasis> l'association est
+ chargée et <emphasis>comment</emphasis> (quelle requête SQL est utilisée). Il ne faut
+ pas confondre les deux. Le mode de chargement est utilisé pour améliorer les performances.
+ On peut utiliser le mode tardif pour définir un contrat sur quelles données sont toujours
+ accessibles sur une instance détachée d'une classe particulière.
+ </para>
+
+ <sect2 id="performance-fetching-lazy">
+ <title>Travailler avec des associations chargées tardivement</title>
+
+ <para>
+ Par défaut, Hibernate3 utilise le chargement tardif par select pour les collections
+ et le chargement tardif par proxy pour les associations vers un seul objet.
+ Ces valeurs par défaut sont valables pour la plupart des associations dans la
+ plupart des applications.
+ </para>
+
+ <para>
+ <emphasis>Note :</emphasis> si vous définissez
+ <literal>hibernate.default_batch_fetch_size</literal>, Hibernate va utiliser l'optimisation
+ du chargement par lot pour le chargement tardif (cette optimisation peut aussi
+ être activée à un niveau de granularité plus fin).
+ </para>
+
+ <para>
+ Cependant, le chargement tardif pose un problème qu'il faut connaitre. L'accès à
+ une association définie comme "tardive", hors du contexte d'une session hibernate
+ ouverte, va conduire à une exception. Par exemple :
+ </para>
+
+ <programlisting><![CDATA[s = sessions.openSession();
+Transaction tx = s.beginTransaction();
+
+User u = (User) s.createQuery("from User u where u.name=:userName")
+ .setString("userName", userName).uniqueResult();
+Map permissions = u.getPermissions();
+
+tx.commit();
+s.close();
+
+Integer accessLevel = (Integer) permissions.get("accounts"); // Error!]]></programlisting>
+
+ <para>
+ Etant donné que la collection des permissions n'a pas été initialisée
+ avant que la <literal>Session</literal> soit fermée, la collection n'est
+ pas capable de se charger. <emphasis>Hibernate ne supporte pas le chargement
+ tardif pour des objets détachés</emphasis>. La solution à ce problème est de
+ déplacer le code qui lit la collection avant le "commit" de la transaction.
+ </para>
+
+ <para>
+ Une autre alternative est d'utiliser une collection ou une association non
+ "tardive" en spécifiant <literal>lazy="false"</literal> dans le mapping de
+ l'association.
+ Cependant il est prévu que le chargement tardif soit utilisé pour quasiment
+ toutes les collections ou associations. Si vous définissez trop d'associtions
+ non "tardives" dans votre modèle objet, Hibernate va finir par devoir charger
+ toute la base de données en mémoire à chaque transaction !
+ </para>
+
+ <para>
+ D'un autre côté, on veut souvent choisir un chargement par jointure (qui est par
+ défaut non tardif) à la place du chargement par select dans une transaction particulière.
+ Nous allons maintenant voir comment adapter les stratégies de chargement. Dans Hibernate3
+ les mécanismes pour choisir une stratégie de chargement sont identiques que
+ l'on ait une association vers un objet simple ou vers une collection.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-fetching-custom" revision="4">
+ <title>Personnalisation des stratégies de chargement</title>
+
+ <para>
+ Le chargement par select (mode par défaut) est très vulnérable au problème du
+ N+1 selects, du coup vous pouvez avoir envie d'activer le chargement par jointure
+ dans les fichiers de mapping :
+ </para>
+
+ <programlisting><![CDATA[<set name="permissions"
+ fetch="join">
+ <key column="userId"/>
+ <one-to-many class="Permission"/>
+</set]]></programlisting>
+
+ <programlisting><![CDATA[<many-to-one name="mother" class="Cat" fetch="join"/>]]></programlisting>
+
+ <para>
+ La stratégie de chargement définie à l'aide du mot <literal>fetch</literal> dans les fichiers
+ de mapping affecte :
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ La récupération via <literal>get()</literal> ou <literal>load()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ La récupération implicite lorsque l'on navigue à travers une association
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Les requêtes de type <literal>Criteria</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Les requêtes HQL si l'on utilise le chargement par <literal>subselect</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Quelle que soit la stratégie de chargement que vous utilisez, la partie du graphe
+ d'objets qui est définie comme non "tardive" sera chargée en mémoire. Cela peut
+ mener à l'exécution de plusieurs selects successifs pour une seule requête HQL.
+ </para>
+
+ <para>
+ On n'utilise pas souvent les documents de mapping pour adapter le chargement.
+ Au lieu de cela, on conserve le comportement par défaut et on le surcharge pour
+ une transaction particulière en utilisant <literal>left join fetch</literal>
+ dans les requêtes HQL. Cela indique à hibernate à Hibernate de charger l'association
+ de manière agressive lors du premier select en utilisant une jointure externe.
+ Dans l'API Criteria vous pouvez utiliser la méthode
+ <literal>setFetchMode(FetchMode.JOIN)</literal>
+ </para>
+
+ <para>
+ Si vous ne vous sentez pas prêt à modifier la stratégie de chargement utilisé
+ par <literal>get()</literal> ou <literal>load()</literal>, vous pouvez juste
+ utiliser une requête de type <literal>Criteria</literal> comme par exemple :
+ </para>
+
+ <programlisting><![CDATA[User user = (User) session.createCriteria(User.class)
+ .setFetchMode("permissions", FetchMode.JOIN)
+ .add( Restrictions.idEq(userId) )
+ .uniqueResult();]]></programlisting>
+
+ <para>
+ (Il s'agit de l'équivalent pour Hibernate de ce que d'autres outils de mapping
+ appellent un "fetch plan" ou "plan de chargement")
+ </para>
+
+ <para>
+ Une autre manière complètement différente d'éviter le problème des N+1 selects
+ est d'utiliser le cache de second niveau.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-fetching-proxies" revision="2">
+ <title>Proxys pour des associations vers un seul objet</title>
+
+ <para>
+ Le chargement tardif des collections est implémenté par Hibernate en utilisant
+ ses propres implémentations pour des collections persistantes. Si l'on veut un
+ chargement tardif pour des associations vers un seul objet métier il faut utiliser
+ un autre mécanisme. L'entité qui est pointée par l'association doit être masquée
+ derrière un proxy. Hibernate implémente l'initialisation tardive des proxys sur des
+ objets persistents via une mise à jour à chaud du bytecode (à l'aide de l'excellente
+ librairie CGLIB).
+ </para>
+
+ <para>
+ Par défaut, Hibernate génère des proxys (au démarrage) pour toutes les classes
+ persistantes et les utilise pour activer le chargement tardif des associations
+ <literal>many-to-one</literal> et <literal>one-to-one</literal>.
+ </para>
+
+ <para>
+ Le fichier de mapping peut déclarer une interface qui sera utilisée par le proxy
+ d'interfaçage pour cette classe à l'aide de l'attribut <literal>proxy</literal>.
+ Par défaut Hibernate utilises une sous classe de la classe persistante.
+ <emphasis>Il faut que les classes pour lesquelles on ajoute un proxy implémentent
+ un constructeur par défaut de visibilité au moins package. Ce constructeur est
+ recommandé pour toutes les classes persistantes !</emphasis>
+ </para>
+
+
+
+ <para>
+ Il y a quelques précautions à prendre lorsque l'on étend cette approche à des classes
+ polymorphiques, exemple :
+ </para>
+
+ <programlisting><![CDATA[<class name="Cat" proxy="Cat">
+ ......
+ <subclass name="DomesticCat" proxy="DomesticCat">
+ .....
+ </subclass>
+ </class>]]></programlisting>
+
+ <para>
+ Tout d'abord, les instances de <literal>Cat</literal> ne pourront jamais être "castées"
+ en <literal>DomesticCat</literal>, même si l'instance sous jacente est une instance
+ de <literal>DomesticCat</literal> :
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id); // instancie un proxy (n'interroge pas la base de données)
+if ( cat.isDomesticCat() ) { // interroge la base de données pour initialiser le proxy
+ DomesticCat dc = (DomesticCat) cat; // Erreur !
+ ....
+}]]></programlisting>
+
+ <para>
+ Deuxièmement, il est possible de casser la notion d'<literal>==</literal> des proxy.
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id); // instancie un proxy Cat
+DomesticCat dc =
+ (DomesticCat) session.load(DomesticCat.class, id); // acquiert un nouveau proxy DomesticCat
+System.out.println(cat==dc); // faux]]></programlisting>
+
+ <para>
+ Cette situation n'est pas si mauvaise qu'il n'y parait. Même si nous avons deux
+ références à deux objets proxys différents, l'instance de base sera quand même le même objet :
+ </para>
+
+ <programlisting><![CDATA[cat.setWeight(11.0); // interroge la base de données pour initialiser le proxy
+System.out.println( dc.getWeight() ); // 11.0]]></programlisting>
+
+ <para>
+ Troisièmement, vous ne pourrez pas utiliser un proxy CGLIB pour une classe <literal>final</literal>
+ ou pour une classe contenant la moindre méthode <literal>final</literal>.
+ </para>
+
+ <para>
+ Enfin, si votre objet persistant obtient une ressource à l'instanciation (par
+ example dans les initialiseurs ou dans le contructeur par défaut), alors ces ressources
+ seront aussi obtenues par le proxy. La classe proxy est vraiment une sous classe de la classe
+ persistante.
+ </para>
+
+ <para>
+ Ces problèmes sont tous dus aux limitations fondamentales du modèle d'héritage unique de Java.
+ Si vous souhaitez éviter ces problèmes, vos classes persistantes doivent chacune implémenter
+ une interface qui déclare ses méthodes métier. Vous devriez alors spécifier ces interfaces
+ dans le fichier de mapping :
+ </para>
+
+ <programlisting><![CDATA[<class name="CatImpl" proxy="Cat">
+ ......
+ <subclass name="DomesticCatImpl" proxy="DomesticCat">
+ .....
+ </subclass>
+</class>]]></programlisting>
+
+ <para>
+ où <literal>CatImpl</literal> implémente l'interface <literal>Cat</literal> et <literal>DomesticCatImpl</literal>
+ implémente l'interface <literal>DomesticCat</literal>. Ainsi, des proxys pour les instances de
+ <literal>Cat</literal> et <literal>DomesticCat</literal> pourraient être retournées par <literal>load()</literal>
+ ou <literal>iterate()</literal> (Notez que <literal>list()</literal> ne retourne généralement pas de proxy).
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) session.load(CatImpl.class, catid);
+Iterator iter = session.iterate("from CatImpl as cat where cat.name='fritz'");
+Cat fritz = (Cat) iter.next();]]></programlisting>
+
+ <para>
+ Les relations sont aussi initialisées tardivement. Ceci signifie que vous
+ devez déclarer chaque propriété comme étant de type <literal>Cat</literal>,
+ et non <literal>CatImpl</literal>.
+ </para>
+
+ <para>
+ Certaines opérations ne nécessitent pas l'initialisation du proxy
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>equals()</literal>, si la classe persistante ne surcharge pas
+ <literal>equals()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>hashCode()</literal>, si la classe persistante ne surcharge pas
+ <literal>hashCode()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Le getter de l'identifiant
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Hibernate détectera les classes qui surchargent <literal>equals()</literal> ou
+ <literal>hashCode()</literal>.
+ </para>
+
+ <para>
+ Eh choisissant <literal>lazy="no-proxy"</literal> au lieu de <literal>lazy="proxy"</literal>
+ qui est la valeur par défaut, il est possible d'éviter les problèmes liés au transtypage.
+ Il faudra alors une instrumentation du bytecode à la compilation et toutes les opérations
+ résulterons immédiatement en une initialisation du proxy.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-fetching-initialization" revision="1">
+ <title>Initialisation des collections et des proxys</title>
+
+ <para>
+ Une exception de type <literal>LazyInitializationException</literal> sera renvoyée par hibernate
+ si une collection ou un proxy non initialisé est accédé en dehors de la portée de la <literal>Session</literal>,
+ e.g. lorsque l'entité à laquelle appartient la collection ou qui a une référence vers le proxy est
+ dans l'état "détachée".
+ </para>
+
+ <para>
+ Parfois, nous devons nous assurer qu'un proxy ou une collection est initialisée avant de
+ fermer la <literal>Session</literal>. Bien sûr, nous pouvons toujours forcer l'initialisation
+ en appelant par exemple <literal>cat.getSex()</literal> ou <literal>cat.getKittens().size()</literal>.
+ Mais ceci n'est pas très lisible pour les personnes parcourant le code et n'est pas très générique.
+ </para>
+
+ <para>
+ Les méthodes statiques <literal>Hibernate.initialize()</literal> et <literal>Hibernate.isInitialized()</literal>
+ fournissent à l'application un moyen de travailler avec des proxys ou des collections initialisés.
+ <literal>Hibernate.initialize(cat)</literal> forcera l'initialisation d'un proxy de <literal>cat</literal>,
+ si tant est que sa <literal>Session</literal> est ouverte. <literal>Hibernate.initialize( cat.getKittens() )</literal>
+ a le même effet sur la collection kittens.
+ </para>
+
+ <para>
+ Une autre option est de conserver la <literal>Session</literal> ouverte jusqu'à
+ ce que toutes les collections et tous les proxys aient été chargés. Dans certaines
+ architectures applicatives, particulièrement celles ou le code d'accès aux données
+ via hiberante et le code qui utilise ces données sont dans des couches applicatives
+ différentes ou des processus physiques différents, il peut devenir problématique
+ de garantir que la <literal>Session</literal> est ouverte lorsqu'une collection
+ est initialisée. Il y a deux moyens de traiter ce problème :
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Dans une application web, un filtre de servlet peut être utilisé pour
+ fermer la <literal>Session</literal> uniquement lorsque la requête
+ a été entièrement traitée, lorsque le rendu de la vue est fini
+ (il s'agit du pattern <emphasis>Open Session in View</emphasis>).
+ Bien sûr, cela demande plus d'attention à la bonne gestion des exceptions
+ de l'application. Il est d'une importance vitale que la <literal>Session</literal>
+ soit fermée et la transaction terminée avant que l'on rende la main à l'utilisateur
+ même si une exception survient durant le traitement de la vue.
+ Voir le wiki Hibernate pour des exemples sur le pattern
+ "Open Session in View".
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Dans une application avec une couche métier séparée, la couche contenant
+ la logique métier doit "préparer" toutes les collections qui seront
+ nécessaires à la couche web avant de retourner les données. Cela signifie
+ que la couche métier doit charger toutes les données et retourner toutes
+ les données déjà initialisées à la couche de présentation/web pour un
+ cas d'utilisation donné. En général l'application appelle la méthode
+ <literal>Hibernate.initialize()</literal> pour chaque collection nécessaire
+ dans la couche web (cet appel doit être fait avant la fermeture de la session)
+ ou bien récupère les collections de manière agressive à l'aide d'une requête
+ HQL avec une clause <literal>FETCH</literal> ou à l'aide du mode
+ <literal>FetchMode.JOIN</literal> pour une requête de type <literal>Criteria</literal>.
+ Cela est en général plus facile si vous utilisez le pattern <emphasis>Command</emphasis>
+ plutôt que <emphasis>Session Facade</emphasis>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Vous pouvez également attacher à une <literal>Session</literal> un objet chargé
+ au préalable à l'aide des méthodes <literal>merge()</literal> ou <literal>lock()</literal>
+ avant d'accéder aux collections (ou aux proxys) non initialisés. Non, Hibernate ne
+ fait pas, et ne doit pas faire, cela automatiquement car cela pourrait introduire
+ une sémantique transactionnelle ad hoc.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Parfois, vous ne voulez pas initialiser une grande collection mais vous avez quand même
+ besoin d'informations sur elle (comme sa taille) ou un sous ensemble de ses données
+ </para>
+
+ <para>
+ Vous pouvez utiliser un filtre de collection pour récupérer sa taille sans l'initialiser :
+ </para>
+
+ <programlisting><![CDATA[( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()]]></programlisting>
+
+ <para>
+ La méthode <literal>createFilter()</literal> est également utilisée pour récupérer
+ de manière efficace des sous ensembles d'une collection sans avoir besoin de l'initialiser
+ dans son ensemble.
+ </para>
+
+ <programlisting><![CDATA[s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();]]></programlisting>
+
+ </sect2>
+
+
+ <sect2 id="performance-fetching-batch">
+ <title>Utiliser le chargement par lot</title>
+
+ <para>
+ Pour améliorer les performances, Hibernate peut utiliser le chargement par lot
+ ce qui veut dire qu'Hibernate peut charger plusieurs proxys (ou collections) non initialisés en une seule
+ requête lorsque l'on accède à l'un de ces proxys. Le chargement par lot est une optimisation
+ intimement liée à la stratégie de chargement tardif par select. Il y a deux moyens d'activer le
+ chargement par lot : au niveau de la classe et au niveau de la collection.
+ </para>
+
+ <para>
+ Le chargement par lot pour les classes/entités est plus simple à comprendre. Imaginez que vous ayez la
+ situation suivante à l'exécution : vous avez 25 instances de <literal>Cat</literal>
+ chargées dans une <literal>Session</literal>, chaque <literal>Cat</literal> a une référence
+ à son <literal>owner</literal>, une <literal>Person</literal>.
+ La classe <literal>Person</literal> est mappée avec un proxy, <literal>lazy="true"</literal>.
+ Si vous itérez sur tous les cats et appelez <literal>getOwner()</literal> sur chacun d'eux,
+ Hibernate exécutera par défaut 25 <literal>SELECT</literal>, pour charger les owners
+ (initialiser le proxy). Vous pouvez paramétrer ce comportement en spécifiant une
+ <literal>batch-size</literal> (taille du lot) dans le mapping de <literal>Person</literal> :
+ </para>
+
+ <programlisting><![CDATA[<class name="Person" batch-size="10">...</class>]]></programlisting>
+
+ <para>
+ Hibernate exécutera désormais trois requêtes, en chargeant respectivement 10,
+ 10, et 5 entités.
+ </para>
+
+ <para>
+ Vous pouvez aussi activer le chargement par lot pour les collections. Par exemple,
+ si chaque <literal>Person</literal> a une collection chargée tardivement de
+ <literal>Cat</literal>s, et que 10 personnes sont actuellement chargées dans la
+ <literal>Session</literal>, itérer sur toutes les persons générera 10 <literal>SELECT</literal>s,
+ un pour chaque appel de <literal>getCats()</literal>. Si vous activez le chargement par lot pour la
+ collection <literal>cats</literal> dans le mapping de <literal>Person</literal>, Hibernate pourra
+ précharger les collections :
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <set name="cats" batch-size="3">
+ ...
+ </set>
+</class>]]></programlisting>
+
+ <para>
+ Avec une taille de lot (<literal>batch-size</literal>) de 8, Hibernate chargera
+ respectivement 3, 3, 3, et 1 collections en quatre <literal>SELECT</literal>s.
+ Encore une fois, la valeur de l'attribut dépend du nombre de collections
+ non initialisées dans une <literal>Session</literal> particulière.
+ </para>
+
+ <para>
+ Le chargement par lot de collections est particulièrement utile si vous avez des
+ arborescenses récursives d'éléments (typiquement, le schéma facture de
+ matériels). (Bien qu'un <emphasis>sous ensemble</emphasis> ou un
+ <emphasis>chemin matérialisé</emphasis> est sans doute une meilleure option pour
+ des arbres principalement en lecture.)
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-fetching-subselect">
+ <title>Utilisation du chargement par sous select</title>
+
+ <para>
+ Si une collection ou un proxy vers un objet doit être chargé, Hibernate va tous les
+ charger en ré-exécutant la requête orignial dans un sous select. Cela fonctionne de la
+ même manière que le chargement par lot sans la possibilité de fragmenter le chargement.
+ </para>
+
+ <!-- TODO: Write more about this -->
+
+ </sect2>
+
+ <sect2 id="performance-fetching-lazyproperties">
+ <title>Utiliser le chargement tardif des propriétés</title>
+
+ <para>
+ Hibernate3 supporte le chargement tardif de propriétés individuelles. La technique
+ d'optimisation est également connue sous le nom de <emphasis>fetch groups</emphasis> (groupes
+ de chargement). Il faut noter qu'il s'agit principalement d'une fonctionnalité marketing
+ car en pratique l'optimisation de la lecture d'un enregistrement est beaucoup plus importante
+ que l'optimisation de la lecture d'une colonne. Cependant, la restriction du chargement à
+ certaines colonnes peut être pratique dans des cas extrèmes, lorsque des tables "legacy"
+ possèdent des centaines de colonnes et que le modèle de données ne peut pas être amélioré.
+ </para>
+
+ <para>
+ Pour activer le chargement tardif d'une propriété, il faut mettre l'attribut <literal>lazy</literal>
+ sur une propriété particulière du mapping :
+ </para>
+
+ <programlisting><![CDATA[<class name="Document">
+ <id name="id">
+ <generator class="native"/>
+ </id>
+ <property name="name" not-null="true" length="50"/>
+ <property name="summary" not-null="true" length="200" lazy="true"/>
+ <property name="text" not-null="true" length="2000" lazy="true"/>
+</class>]]></programlisting>
+
+ <para>
+ Le chargement tardif des propriétés requiert une instrumentation du bytecode lors de la
+ compilation ! Si les classes persistantes ne sont pas instrumentées, Hibernate ignorera de
+ manière silencieuse le mode tardif et retombera dans le mode de chargement immédiat.
+ </para>
+
+ <para>
+ Pour l'instrumentation du bytecode vous pouvez utiliser la tâche Ant suivante :
+ </para>
+
+ <programlisting><![CDATA[<target name="instrument" depends="compile">
+ <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
+ <classpath path="${jar.path}"/>
+ <classpath path="${classes.dir}"/>
+ <classpath refid="lib.class.path"/>
+ </taskdef>
+
+ <instrument verbose="true">
+ <fileset dir="${testclasses.dir}/org/hibernate/auction/model">
+ <include name="*.class"/>
+ </fileset>
+ </instrument>
+</target>]]></programlisting>
+
+ <para>
+ Une autre façon (meilleure ?) pour éviter de lire plus de colonnes que
+ nécessaire au moins pour des transactions en lecture seule est d'utiliser
+ les fonctionnalités de projection des requêtes HQL ou Criteria. Cela évite
+ de devoir instrumenter le bytecode à la compilation et est certainement une
+ solution préférable.
+ </para>
+
+ <para>
+ Vous pouvez forcer le mode de chargement agressif des propriétés en utilisant
+ <literal>fetch all properties</literal> dans les requêts HQL.
+ </para>
+
+ </sect2>
+ </sect1>
+
+ <sect1 id="performance-cache" revision="1">
+ <title>Le cache de second niveau</title>
+
+ <para>
+ Une <literal>Session</literal> Hibernate est un cache de niveau transactionnel
+ des données persistantes. Il est possible de configurer un cache de cluster ou de JVM
+ (de niveau <literal>SessionFactory</literal> pour être exact) défini classe par classe
+ et collection par collection. Vous pouvez même utiliser votr choix de cache
+ en implémentant le pourvoyeur (provider) associé.
+ Faites attention, les caches ne sont jamais avertis des modifications faites
+ dans la base de données par d'autres applications (ils peuvent cependant être
+ configurés pour régulièrement expirer les données en cache).
+ </para>
+
+ <para>
+ Par défaut, Hibernate utilise EHCache comme cache de niveau JVM (le support
+ de JCS est désormais déprécié et sera enlevé des futures versions d'Hibernate).
+ Vous pouvez choisir une autre implémentation en spécifiant le nom de la classe qui
+ implémente <literal>org.hibernate.cache.CacheProvider</literal> en utilisant
+ la propriété <literal>hibernate.cache.provider_class</literal>.
+ </para>
+
+ <table frame="topbot" id="cacheproviders" revision="1">
+ <title>Fournisseur de cache</title>
+ <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="3*"/>
+ <colspec colname='c3' colwidth="1*"/>
+ <colspec colname='c4' colwidth="1*"/>
+ <colspec colname='c5' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Cache</entry>
+ <entry>Classe pourvoyeuse</entry>
+ <entry>Type</entry>
+ <entry>Support en Cluster</entry>
+ <entry>Cache de requêtes supporté</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>Hashtable (ne pas utiliser en production)</entry>
+ <entry><literal>org.hibernate.cache.HashtableCacheProvider</literal></entry>
+ <entry>mémoire</entry>
+ <entry></entry>
+ <entry>oui</entry>
+ </row>
+ <row>
+ <entry>EHCache</entry>
+ <entry><literal>org.hibernate.cache.EhCacheProvider</literal></entry>
+ <entry>mémoire, disque</entry>
+ <entry></entry>
+ <entry>oui</entry>
+ </row>
+ <row>
+ <entry>OSCache</entry>
+ <entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
+ <entry>mémoire, disque</entry>
+ <entry></entry>
+ <entry>oui</entry>
+ </row>
+ <row>
+ <entry>SwarmCache</entry>
+ <entry><literal>org.hibernate.cache.SwarmCacheProvider</literal></entry>
+ <entry>en cluster (multicast ip)</entry>
+ <entry>oui (invalidation de cluster)</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>JBoss TreeCache</entry>
+ <entry><literal>org.hibernate.cache.TreeCacheProvider</literal></entry>
+ <entry>en cluster (multicast ip), transactionnel</entry>
+ <entry>oui (replication)</entry>
+ <entry>oui (horloge sync. nécessaire)</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <sect2 id="performance-cache-mapping" revision="2">
+ <title>Mapping de Cache</title>
+
+ <para>
+ L'élément <literal><cache></literal> d'une classe ou d'une collection à
+ la forme suivante :
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="cache1" coords="2 70"/>
+ <area id="cache2" coords="3 70"/>
+ <area id="cache3" coords="4 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<cache
+ usage="transactional|read-write|nonstrict-read-write|read-only"
+ region="RegionName"
+ include="all|non-lazy"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="cache1">
+ <para>
+ <literal>usage</literal> (requis) spécifie la stratégie de cache :
+ <literal>transactionel</literal>,
+ <literal>lecture-écriture</literal>,
+ <literal>lecture-écriture non stricte</literal> ou
+ <literal>lecture seule</literal>
+ </para>
+ </callout>
+ <callout arearefs="cache2">
+ <para>
+ <literal>region</literal> (optionnel, par défaut il s'agit du nom
+ de la classe ou du nom de role de la collection) spécifie le nom de la
+ région du cache de second niveau
+ </para>
+ </callout>
+ <callout arearefs="cache3">
+ <para>
+ <literal>include</literal> (optionnel, par défaut <literal>all</literal>)
+ <literal>non-lazy</literal> spécifie que les propriétés des entités mappées avec
+ <literal>lazy="true"</literal> ne doivent pas être mises en cache lorsque
+ le chargement tardif des attributs est activé.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Alternativement (voir préférentiellement), vous pouvez spécifier les éléments
+ <literal><class-cache></literal> et <literal><collection-cache></literal>
+ dans <literal>hibernate.cfg.xml</literal>.
+ </para>
+
+ <para>
+ L'attribut <literal>usage</literal> spécifie une <emphasis>stratégie de concurrence d'accès au cache</emphasis>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-cache-readonly">
+ <title>Strategie : lecture seule</title>
+
+ <para>
+ Si votre application a besoin de lire mais ne modifie jamais les instances d'une classe,
+ un cache <literal>read-only</literal> peut être utilisé. C'est la stratégie la plus simple
+ et la plus performante. Elle est même parfaitement sûre dans un cluster.
+ </para>
+
+ <programlisting><![CDATA[<class name="eg.Immutable" mutable="false">
+ <cache usage="read-only"/>
+ ....
+</class>]]></programlisting>
+
+ </sect2>
+
+
+ <sect2 id="performance-cache-readwrite">
+ <title>Stratégie : lecture/écriture</title>
+
+ <para>
+ Si l'application a besoin de mettre à jour des données, un cache <literal>read-write</literal> peut
+ être approprié. Cette stratégie ne devrait jamais être utilisée si votre application
+ nécessite un niveau d'isolation transactionnelle sérialisable. Si le cache est utilisé
+ dans un environnement JTA, vous devez spécifier
+ <literal>hibernate.transaction.manager_lookup_class</literal>, fournissant une stratégie pour obtenir
+ le <literal>TransactionManager</literal> JTA. Dans d'autres environnements, vous devriez vous assurer
+ que la transation est terminée à l'appel de <literal>Session.close()</literal>
+ ou <literal>Session.disconnect()</literal>. Si vous souhaitez utiliser cette stratégie
+ dans un cluster, vous devriez vous assurer que l'implémentation de cache utilisée supporte
+ le vérrouillage. Ce que ne font <emphasis>pas</emphasis> les pourvoyeurs caches fournis.
+ </para>
+
+ <programlisting><![CDATA[<class name="eg.Cat" .... >
+ <cache usage="read-write"/>
+ ....
+ <set name="kittens" ... >
+ <cache usage="read-write"/>
+ ....
+ </set>
+</class>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="performance-cache-nonstrict">
+ <title>Stratégie : lecture/écriture non stricte</title>
+
+ <para>
+ Si l'application besoin de mettre à jour les données de manière occasionnelle
+ (qu'il est très peu probable que deux transactions essaient de mettre à jour le même
+ élément simultanément) et qu'une isolation transactionnelle stricte n'est pas nécessaire,
+ un cache <literal>nonstrict-read-write</literal> peut être approprié. Si le cache est
+ utilisé dans un environnement JTA, vous devez spécifier
+ <literal>hibernate.transaction.manager_lookup_class</literal>. Dans d'autres
+ environnements, vous devriez vous assurer que la transation est terminée à l'appel
+ de <literal>Session.close()</literal> ou <literal>Session.disconnect()</literal>
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-cache-transactional">
+ <title>Stratégie : transactionelle</title>
+
+ <para>
+ La stratégie de cache <literal>transactional</literal> supporte un cache
+ complètement transactionnel comme, par exemple, JBoss TreeCache. Un tel cache ne
+ peut être utilisé que dans un environnement JTA et vous devez spécifier
+ <literal>hibernate.transaction.manager_lookup_class</literal>.
+ </para>
+
+ </sect2>
+
+ <para>
+ Aucun des caches livrés ne supporte toutes les stratégies de concurrence. Le tableau suivant montre
+ quels caches sont compatibles avec quelles stratégies de concurrence.
+ </para>
+
+ <table frame="topbot">
+ <title>Stratégie de concurrence du cache</title>
+ <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <colspec colname='c3' colwidth="1*"/>
+ <colspec colname='c4' colwidth="1*"/>
+ <colspec colname='c5' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Cache</entry>
+ <entry>read-only (lecture seule)</entry>
+ <entry>nonstrict-read-write (lecture-écriture non stricte)</entry>
+ <entry>read-write (lecture-ériture)</entry>
+ <entry>transactional (transactionnel)</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>Hashtable (ne pas utilser en production)</entry>
+ <entry>oui</entry>
+ <entry>oui</entry>
+ <entry>oui</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>EHCache</entry>
+ <entry>oui</entry>
+ <entry>oui</entry>
+ <entry>oui</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>OSCache</entry>
+ <entry>oui</entry>
+ <entry>oui</entry>
+ <entry>oui</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>SwarmCache</entry>
+ <entry>oui</entry>
+ <entry>oui</entry>
+ <entry></entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>JBoss TreeCache</entry>
+ <entry>oui</entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>oui</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect1>
+
+ <sect1 id="performance-sessioncache" revision="2">
+ <title>Gérer les caches</title>
+
+ <para>
+ A chaque fois que vous passez un objet à la méthode <literal>save()</literal>,
+ <literal>update()</literal> ou <literal>saveOrUpdate()</literal> et à chaque fois
+ que vous récupérez un objet avec <literal>load()</literal>, <literal>get()</literal>,
+ <literal>list()</literal>, <literal>iterate()</literal> or <literal>scroll()</literal>,
+ cet objet est ajouté au cache interne de la <literal>Session</literal>.
+ </para>
+ <para>
+ Lorsqu'il y a un appel à la méthode <literal>flush()</literal>, l'état de cet objet
+ va être synchronisé avec la base de données. Si vous ne voulez pas que cette synchronisation
+ ait lieu ou si vous traitez un grand nombre d'objets et que vous avez besoin de gérer
+ la mémoire de manière efficace, vous pouvez utiliser la méthode <literal>evict()</literal>
+ pour supprimer l'objet et ses collections dépendantes du cache de la session
+ </para>
+
+ <programlisting><![CDATA[ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
+while ( cats.next() ) {
+ Cat cat = (Cat) cats.get(0);
+ doSomethingWithACat(cat);
+ sess.evict(cat);
+}]]></programlisting>
+
+ <para>
+ La <literal>Session</literal> dispose aussi de la méthode <literal>contains()</literal> pour déterminer
+ si une instance appartient au cache de la session.
+ </para>
+
+ <para>
+ Pour retirer tous les objets du cache session, appelez <literal>Session.clear()</literal>
+ </para>
+
+ <para>
+ Pour le cache de second niveau, il existe des méthodes définies dans
+ <literal>SessionFactory</literal> pour retirer des instances du cache,
+ la classe entière, une instance de collection ou
+ le rôle entier d'une collection.
+ </para>
+
+ <programlisting><![CDATA[sessionFactory.evict(Cat.class, catId); //evict a particular Cat
+sessionFactory.evict(Cat.class); //evict all Cats
+sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
+sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections]]></programlisting>
+
+ <para>
+ Le <literal>CacheMode</literal> contrôle comme une session particulière interragit avec le
+ cache de second niveau
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>CacheMode.NORMAL</literal> - lit et écrit les items dans le cache de second niveau
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CacheMode.GET</literal> - lit les items dans le cache de second niveau mais ne
+ les écrit pas sauf dans le cache d'une mise à jour d'une donnée
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CacheMode.PUT</literal> - écrit les items dans le cache de second niveau mais ne les
+ lit pas dans le cache de second niveau
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CacheMode.REFRESH</literal> - écrit les items dans le cache de second niveau mais ne les
+ lit pas dans le cache de second niveau, outrepasse l'effet de<literal>hibernate.cache.use_minimal_puts</literal>,
+ en forçant un rafraîchissement du cache de second niveau pour chaque item lu dans la base
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Pour parcourir le contenu du cache de second niveau ou la région du cache dédiée au requêtes, vous
+ pouvez utiliser l'API <literal>Statistics</literal>
+ API:
+ </para>
+
+ <programlisting><![CDATA[Map cacheEntries = sessionFactory.getStatistics()
+ .getSecondLevelCacheStatistics(regionName)
+ .getEntries();]]></programlisting>
+
+ <para>
+ Vous devez pour cela activer les statistiques et optionnellement forcer Hibernate à conserver les entrées dans le
+ cache sous un format plus compréhensible pour l'utilisateur :
+ </para>
+
+ <programlisting><![CDATA[hibernate.generate_statistics true
+hibernate.cache.use_structured_entries true]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="performance-querycache" revision="1">
+ <title>Le cache de requêtes</title>
+
+ <para>
+ Les résultats d'une requête peuvent aussi être placés en cache. Ceci n'est utile
+ que pour les requêtes qui sont exécutées avec les mêmes paramètres. Pour utiliser
+ le cache de requêtes, vous devez d'abord l'activer :
+ </para>
+
+ <programlisting><![CDATA[hibernate.cache.use_query_cache true]]></programlisting>
+
+ <para>
+ Ce paramètre amène la création de deux nouvelles régions dans le cache, une qui va conserver
+ le résultat des requêtes mises en cache (<literal>org.hibernate.cache.StandardQueryCache</literal>)
+ et l'autre qui va conserver l'horodatage des mises à jour les plus récentes effectuées sur les
+ tables requêtables (<literal>org.hibernate.cache.UpdateTimestampsCache</literal>).
+ Il faut noter que le cache de requête ne conserve pas l'état des entités, il met en cache
+ uniquement les valeurs de l'identifiant et les valeurs de types de base (?). Le cache
+ de requête doit toujours être utilisé avec le cache de second niveau pour être efficace.
+ </para>
+
+ <para>
+ La plupart des requêtes ne retirent pas de bénéfice pas du cache,
+ donc par défaut les requêtes ne sont pas mises en cache. Pour activer le cache,
+ appelez <literal>Query.setCacheable(true)</literal>.
+ Cet appel permet de vérifier si les résultats sont en cache ou non, voire
+ d'ajouter ces résultats si la requête est exécutée.
+ </para>
+
+ <para>
+ Si vous avez besoin de contrôler finement les délais d'expiration du cache, vous
+ pouvez spécifier une région de cache nommée pour une requête particulière en
+ appelant <literal>Query.setCacheRegion()</literal>.
+ </para>
+
+ <programlisting><![CDATA[List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
+ .setEntity("blogger", blogger)
+ .setMaxResults(15)
+ .setCacheable(true)
+ .setCacheRegion("frontpages")
+ .list();]]></programlisting>
+
+ <para>
+ Si une requête doit forcer le rafraîchissement de sa région de cache, vous devez
+ appeler <literal>Query.setCacheMode(CacheMode.REFRESH)</literal>. C'est particulièrement
+ utile lorsque les données peuvent avoir été mises à jour par un processus séparé (e.g. elles
+ n'ont pas été modifiées par Hibernate). Cela permet à l'application de rafraîchir de
+ manière sélective les résultats d'une requête particulière. Il s'agit d'une alternative plus
+ efficace à l'éviction d'une région du cache à l'aide de la méthode
+ <literal>SessionFactory.evictQueries()</literal>.
+ </para>
+
+ </sect1>
+ <sect1 id="performance-collections">
+ <title>Comprendre les performances des Collections</title>
+
+ <para>
+ Nous avons déjà passé du temps à discuter des collections.
+ Dans cette section, nous allons traiter du comportement des
+ collections à l'exécution.
+ </para>
+
+ <sect2 id="performance-collections-taxonomy">
+ <title>Classification</title>
+
+ <para>Hibernate définit trois types de collections :</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>les collections de valeurs</para>
+ </listitem>
+ <listitem>
+ <para>les associations un-vers-plusieurs</para>
+ </listitem>
+ <listitem>
+ <para>les associations plusieurs-vers-plusieurs</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Cette classification distingue les différentes relations entre les tables
+ et les clés étrangères mais ne nous apprend rien de ce que nous devons savoir
+ sur le modèle relationnel. Pour comprendre parfaitement la structure relationnelle
+ et les caractéristiques des performances, nous devons considérer la structure
+ de la clé primaire qui est utilisée par Hibernate pour mettre à jour ou supprimer
+ les éléments des collections. Celà nous amène aux classifications suivantes :
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>collections indexées</para>
+ </listitem>
+ <listitem>
+ <para>sets</para>
+ </listitem>
+ <listitem>
+ <para>bags</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Toutes les collections indexées (maps, lists, arrays) ont une clé primaire constituée
+ des colonnes clé (<literal><key></literal>) et <literal><index></literal>.
+ Avec ce type de clé primaire, la mise à jour de collection est en général très performante - la clé
+ primaire peut être indexées efficacement et un élément particulier peut être
+ localisé efficacement lorsqu'Hibernate essaie de le mettre à jour ou de le supprimer.
+ </para>
+
+ <para>
+ Les Sets ont une clé primaire composée de <literal><key></literal> et des
+ colonnes représentant l'élément. Elle est donc moins efficace pour certains
+ types de collections d'éléments, en particulier les éléments composites,
+ les textes volumineux ou les champs binaires ; la base de données
+ peut ne pas être capable d'indexer aussi efficacement une clé primaire
+ aussi complexe. Cependant, pour les associations un-vers-plusieurs
+ ou plusieurs-vers-plusieurs, spécialement lorsque l'on utilise des entités
+ ayant des identifiants techniques, il est probable que cela soit aussi efficace
+ (note : si vous voulez que <literal>SchemaExport</literal> créé effectivement
+ la clé primaire d'un <literal><set></literal> pour vous, vous devez
+ déclarer toutes les colonnes avec <literal>not-null="true"</literal>).
+ </para>
+
+ <para>
+ Le mapping à l'aide d'<literal><idbag></literal> définit une clé
+ de substitution ce qui leur permet d'être très efficaces lors de la
+ mise à jour. En fait il s'agit du meilleur cas de mise à jour d'une collection
+ </para>
+
+ <para>
+ Le pire cas intervient pour les Bags. Dans la mesure où un bag permet
+ la duplications des éléments et n'a pas de colonne d'index, aucune clé primaire
+ ne peut être définie. Hibernate n'a aucun moyen de distinguer des enregistrements
+ dupliqués. Hibernate résout ce problème en supprimant complètement les
+ enregistrements (via un simple <literal>DELETE</literal>), puis en recréant
+ la collection chaque fois qu'elle change. Ce qui peut être très inefficace.
+ </para>
+
+ <para>
+ Notez que pour une relation un-vers-plusieurs, la "clé primaire"
+ peut ne pas être la clé primaire de la table en base de données -
+ mais même dans ce cas, la classification ci-dessus reste utile
+ (Elle explique comment Hibernate "localise" chaque enregistrement
+ de la collection).
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-collections-mostefficientupdate">
+ <title>Les lists, les maps, les idbags et les sets sont les collections les plus efficaces pour la mise à jour</title>
+
+ <para>
+ La discussion précédente montre clairement que les collections indexées
+ et (la plupart du temps) les sets, permettent de réaliser le plus efficacement
+ les opérations d'ajout, de suppression ou de modification d'éléments.
+ </para>
+
+ <para>
+ Il existe un autre avantage qu'ont les collections indexées sur les Sets
+ dans le cadre d'une association plusieurs vers plusieurs ou d'une collection de valeurs.
+ A cause de la structure inhérente d'un <literal>Set</literal>, Hibernate n'effectue jamais
+ d'<literal>UPDATE</literal> quand un enregistrement est modifié. Les modifications
+ apportées à un <literal>Set</literal> se font via un <literal>INSERT</literal> et <literal>DELETE</literal>
+ (de chaque enregistrement). Une fois de plus, ce cas ne s'applique pas aux associations
+ un vers plusieurs.
+ </para>
+
+ <para>
+ Après s'être rappelé que les tableaux ne peuvent pas être chargés tardivement,
+ nous pouvons conclure que les lists, les maps et les idbags sont les types de collections
+ (non inversées) les plus performants, avec les sets pas loin derrières.
+ Les sets son le type de collection le plus courant dans les applications Hibernate. Cela
+ est du au fait que la sémantique des "set" est la plus naturelle dans le modèle
+ relationnel.
+ </para>
+
+ <para>
+ Cependant, dans des modèles objet bien conçus avec Hibernate, on voit souvent que
+ la plupart des collections sont en fait des associations "un-vers-plusieurs" avec
+ <literal>inverse="true"</literal>. Pour ces associations, les mises à jour sont gérées
+ au niveau de l'association "plusieurs-vers-un" et les considérations de performance de
+ mise à jour des collections ne s'appliquent tout simplement pas dans ces cas là.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-collections-mostefficentinverse">
+ <title>Les Bags et les lists sont les plus efficaces pour les collections inverse</title>
+
+ <para>
+ Avant que vous n'oubliez les bags pour toujours, il y a un cas précis où les bags
+ (et les lists) sont bien plus performants que les sets. Pour une collection marquée
+ comme <literal>inverse="true"</literal> (le choix le plus courant pour un relation
+ un vers plusieurs bidirectionnelle), nous pouvons ajouter des éléments à un bag
+ ou une list sans avoir besoin de l'initialiser (fetch) les éléments du sac!
+ Ceci parce que <literal>Collection.add()</literal> ou <literal>Collection.addAll()</literal>
+ doit toujours retourner vrai pour un bag ou une <literal>List</literal>
+ (contrairement au <literal>Set</literal>).
+ Cela peut rendre le code suivant beaucoup plus rapide.
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) sess.load(Parent.class, id);
+ Child c = new Child();
+ c.setParent(p);
+ p.getChildren().add(c); //pas besoin de charger la collection !
+ sess.flush();]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="performance-collections-oneshotdelete">
+ <title>Suppression en un coup</title>
+
+ <para>
+ Parfois, effacer les éléments d'une collection un par un peut être extrêmement inefficace.
+ Hibernate n'est pas totalement stupide, il sait qu'il ne faut pas le faire dans le cas d'une
+ collection complètement vidée (lorsque vous appellez <literal>list.clear()</literal>, par exemple).
+ Dans ce cas, Hibernate fera un simple <literal>DELETE</literal> et le travail est fait !
+ </para>
+
+ <para>
+ Supposons que nous ajoutions un élément dans une collection de taille vingt et que nous
+ enlevions ensuite deux éléments. Hibernate effectuera un <literal>INSERT</literal> puis
+ deux <literal>DELETE</literal> (à moins que la collection ne soit un bag). Ce qui est
+ souhaitable.
+ </para>
+
+ <para>
+ Cependant, supposons que nous enlevions dix huit éléments, laissant ainsi deux éléments, puis
+ que nous ajoutions trois nouveaux éléments. Il y a deux moyens de procéder.
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>effacer dix huit enregistrements un à un puis en insérer trois</para>
+ </listitem>
+ <listitem>
+ <para>effacer la totalité de la collection (en un <literal>DELETE</literal> SQL) puis insérer
+ les cinq éléments restant un à un</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Hibernate n'est pas assez intelligent pour savoir que, dans ce cas, la seconde méthode est plus
+ rapide (Il plutôt heureux qu'Hibernate ne soit pas trop intelligent ; un tel comportement
+ pourrait rendre l'utilisation de triggers de bases de données plutôt aléatoire, etc...).
+ </para>
+
+ <para>
+ Heureusement, vous pouvez forcer ce comportement lorsque vous le souhaitez, en liberant
+ (c'est-à-dire en déréférençant) la collection initiale et en retournant une collection
+ nouvellement instanciée avec les éléments restants. Ceci peut être très pratique et
+ très puissant de temps en temps.
+ </para>
+
+ <para>
+ Bien sûr, la suppression en un coup ne s'applique pas pour les collections qui sont mappées
+ avec <literal>inverse="true"</literal>.
+ </para>
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="performance-monitoring" revision="1">
+ <title>Moniteur de performance</title>
+
+ <para>
+ L'optimisation n'est pas d'un grand intérêt sans le suivi et l'accès aux données de
+ performance. Hibernate fournit toute une panoplie de rapport sur ses opérations internes.
+ Les statistiques dans Hibernate sont fournies par <literal>SessionFactory</literal>.
+ </para>
+
+ <sect2 id="performance-monitoring-sf" revision="2">
+ <title>Suivi d'une SessionFactory</title>
+
+ <para>
+ Vous pouvez accéder au métriques d'une <literal>SessionFactory</literal> de deux
+ manières. La première option est d'appeler <literal>sessionFactory.getStatistics()</literal>
+ et de lire ou d'afficher les <literal>Statistics</literal> vous même.
+ </para>
+
+ <para>
+ Hibernate peut également utiliser JMX pour publier les métriques si vous activez
+ le MBean <literal>StatisticsService</literal>. Vous pouvez activer un seul MBean
+ pour toutes vos <literal>SessionFactory</literal> ou un par factory. Voici un code
+ qui montre un exemple de configuration minimaliste :
+ </para>
+
+ <programlisting><![CDATA[// MBean service registration for a specific SessionFactory
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "myFinancialApp");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+stats.setSessionFactory(sessionFactory); // Bind the stats to a SessionFactory
+server.registerMBean(stats, on); // Register the Mbean on the server]]></programlisting>
+
+
+<programlisting><![CDATA[// MBean service registration for all SessionFactory's
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "all");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+server.registerMBean(stats, on); // Register the MBean on the server]]></programlisting>
+
+ <para>
+ TODO: Cela n'a pas de sens : dans le premier cs on récupère et on utilise le MBean directement.
+ Dans le second, on doit fournir le nom JNDI sous lequel est retenu la fabrique de session avant de
+ l'utiliser. Pour cela il faut utiliser
+ <literal>hibernateStatsBean.setSessionFactoryJNDIName("my/JNDI/Name")</literal>
+ </para>
+ <para>
+ Vous pouvez (dés)activer le suivi pour une <literal>SessionFactory</literal>
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ au moment de la configuration en mettant <literal>hibernate.generate_statistics</literal> à <literal>false</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+ <itemizedlist>
+ <listitem>
+ <para>
+ à chaud avec <literal>sf.getStatistics().setStatisticsEnabled(true)</literal>
+ ou <literal>hibernateStatsBean.setStatisticsEnabled(true)</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Les statistiques peuvent être remises à zéro de manière programmatique à l'aide de la méthode
+ <literal>clear()</literal>
+ Un résumé peut être envoyé à un logger (niveau info) à l'aide de la méthode <literal>logSummary()</literal>
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-monitoring-metrics" revision="1">
+ <title>Métriques</title>
+
+ <para>
+ Hibernate fournit un certain nombre de métriques, qui vont des informations très basiques
+ aux informations très spécialisées qui ne sont appropriées que dans certains scenarii.
+ Tous les compteurs accessibles sont décrits dans l'API de l'interface
+ <literal>Statistics</literal> dans trois catégories :
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Les métriques relatives à l'usage général de la <literal>Session</literal>
+ comme le nombre de sessions ouvertes, le nombre de connexions JDBC récupérées, etc...
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Les métriques relatives aux entités, collections, requêtes et caches dans
+ leur ensemble (métriques globales),
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Les métriques détaillées relatives à une entité, une collection, une requête
+ ou une région de cache particulière.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Par exemple, vous pouvez vérifier l'accès au cache ainsi que le taux d'éléments manquants et
+ de mise à jour des entités, collections et requêtes et le temps moyen que met une requête.
+ Il faut faire attention au fait que le nombre de millisecondes est sujet à approximation en
+ Java. Hibernate est lié à la précision de la machine virtuelle, sur certaines plateformes,
+ cela n'offre qu'une précision de l'ordre de 10 secondes.
+ </para>
+
+ <para>
+ Des accesseurs simples sont utilisés pour accéder aux métriques globales (e.g. celles qui ne
+ sont pas liées à une entité, collection ou région de cache particulière). Vous pouvez accéder
+ aux métriques d'une entité, collection, région de cache particulière à l'aide de son nom et à l'aide
+ de sa représentation HQL ou SQL pour une requête. Référez vous à la javadoc des APIS
+ <literal>Statistics</literal>, <literal>EntityStatistics</literal>,
+ <literal>CollectionStatistics</literal>, <literal>SecondLevelCacheStatistics</literal>,
+ and <literal>QueryStatistics</literal> pour plus d'informations. Le code ci-dessous montre
+ un exemple simple :
+ </para>
+
+ <programlisting><![CDATA[Statistics stats = HibernateUtil.sessionFactory.getStatistics();
+
+double queryCacheHitCount = stats.getQueryCacheHitCount();
+double queryCacheMissCount = stats.getQueryCacheMissCount();
+double queryCacheHitRatio =
+ queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);
+
+log.info("Query Hit ratio:" + queryCacheHitRatio);
+
+EntityStatistics entityStats =
+ stats.getEntityStatistics( Cat.class.getName() );
+long changes =
+ entityStats.getInsertCount()
+ + entityStats.getUpdateCount()
+ + entityStats.getDeleteCount();
+log.info(Cat.class.getName() + " changed " + changes + "times" );]]></programlisting>
+
+ <para>
+ Pour travailler sur toutes les entités, collections, requêtes et régions de cache, vous pouvez
+ récupérer la liste des noms des entités, collections, requêtes et régions de cache avec les
+ méthodes : <literal>getQueries()</literal>, <literal>getEntityNames()</literal>,
+ <literal>getCollectionRoleNames()</literal>, et
+ <literal>getSecondLevelCacheRegionNames()</literal>.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/persistent_classes.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/persistent_classes.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/persistent_classes.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,536 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+<chapter id="persistent-classes" revision="2">
+ <title>Classes persistantes</title>
+
+ <para>
+ Les classes persistantes sont les classes d'une application qui implémentent
+ les entités d'un problème métier (ex. Client et Commande dans une application
+ de commerce électronique).
+ Toutes les instances d'une classe persistante ne sont pas forcément
+ dans l'état persistant - au lieu de cela, une instance peut être éphémère (NdT : transient) ou détachée.
+ </para>
+
+ <para>
+ Hibernate fonctionne de manière optimale lorsque ces classes suivent quelques règles
+ simples, aussi connues comme le modèle de programmation Plain Old Java Object
+ (POJO). Cependant, aucune de ces règles ne sont des besoins absolus. En effet, Hibernate3 suppose très peu de choses à propos
+ de la nature de vos objets persistants. Vous pouvez exprimer un modèle de domaine par d'autres moyens : utiliser des arbres
+ d'instances de <literal>Map</literal>, par exemple.
+ </para>
+
+ <sect1 id="persistent-classes-pojo">
+ <title>Un exemple simple de POJO</title>
+
+ <para>
+ Toute bonne application Java nécessite une classe persistante
+ représentant les félins.
+ </para>
+
+ <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+public class Cat {
+ private Long id; // identifier
+
+ private Date birthdate;
+ private Color color;
+ private char sex;
+ private float weight;
+ private int litterId;
+
+ private Cat mother;
+ private Set kittens = new HashSet();
+
+ private void setId(Long id) {
+ this.id=id;
+ }
+ public Long getId() {
+ return id;
+ }
+
+ void setBirthdate(Date date) {
+ birthdate = date;
+ }
+ public Date getBirthdate() {
+ return birthdate;
+ }
+
+ void setWeight(float weight) {
+ this.weight = weight;
+ }
+ public float getWeight() {
+ return weight;
+ }
+
+ public Color getColor() {
+ return color;
+ }
+ void setColor(Color color) {
+ this.color = color;
+ }
+
+ void setSex(char sex) {
+ this.sex=sex;
+ }
+ public char getSex() {
+ return sex;
+ }
+
+ void setLitterId(int id) {
+ this.litterId = id;
+ }
+ public int getLitterId() {
+ return litterId;
+ }
+
+ void setMother(Cat mother) {
+ this.mother = mother;
+ }
+ public Cat getMother() {
+ return mother;
+ }
+ void setKittens(Set kittens) {
+ this.kittens = kittens;
+ }
+ public Set getKittens() {
+ return kittens;
+ }
+
+ // addKitten not needed by Hibernate
+ public void addKitten(Cat kitten) {
+ kitten.setMother(this);
+ kitten.setLitterId( kittens.size() );
+ kittens.add(kitten);
+ }
+}]]></programlisting>
+
+ <para>
+ Il y a quatre règles à suivre ici :
+ </para>
+
+
+ <sect2 id="persistent-classes-pojo-constructor" revision="1">
+ <title>Implémenter un constructeur sans argument</title>
+
+ <para>
+ <literal>Cat</literal> a un constructeur sans argument. Toutes les classes persistantes doivent avoir un
+ constructeur par défaut (lequel peut ne pas être public) pour qu'Hibernate puissent les instancier en utilisant
+ <literal>Constructor.newInstance()</literal>. Nous recommandons fortement d'avoir un constructeur par défaut avec
+ au moins une visibilité <emphasis>paquet</emphasis> pour la génération du proxy à l'exécution dans Hibernate.
+ </para>
+ </sect2>
+
+ <sect2 id="persistent-classes-pojo-identifier" revision="2">
+ <title>Fournir une propriété d'indentifiant (optionnel)</title>
+
+ <para>
+ <literal>Cat</literal> possède une propriété appelée <literal>id</literal>.
+ Cette propriété mappe la valeur de la colonne de clé primaire de la table
+ d'une base de données.La propriété aurait pu s'appeler complètement autrement,
+ et son type aurait pu être n'importe quel type primitif, n'importe quel "encapsuleur"
+ de type primitif, <literal>java.lang.String</literal> ou <literal>java.util.Date</literal>.
+ (Si votre base de données héritée possède des clés composites, elles peuvent être mappées
+ en utilisant une classe définie par l'utilisateur et possédant les propriétés associées aux
+ types de la clé composite - voir la section concernant les identifiants composites plus tard).
+ </para>
+
+ <para>
+ La propriété d'identifiant est strictement optionnelle. Vous pouver l'oublier et laisser Hibernate
+ s'occuper des identifiants de l'objet en interne. Toutefois, nous ne le recommandons pas.
+ </para>
+
+ <para>
+ En fait, quelques fonctionnalités ne sont disponibles que pour les classes
+ déclarant un identifiant de propriété :
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Les réattachements transitifs pour les objets détachés (mise à jour en cascade ou fusion en cascade) -
+ voir <xref linkend="objectstate-transitive"/>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>Session.saveOrUpdate()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>Session.merge()</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Nous recommandons que vous déclariez les propriétés d'identifiant de manière
+ uniforme. Nous recommandons également que vous utilisiez un type nullable
+ (ie. non primitif).
+ </para>
+ </sect2>
+
+ <sect2 id="persistent-classes-pojo-final">
+ <title>Favoriser les classes non finales (optionnel)</title>
+ <para>
+ Une fonctionnalité clef d'Hibernate, les <emphasis>proxies</emphasis>, nécessitent
+ que la classe persistente soit non finale ou qu'elle soit l'implémentation d'une
+ interface qui déclare toutes les méthodes publiques.
+ </para>
+ <para>
+ Vous pouvez persister, grâce à Hibernate, les classes <literal>final</literal>
+ qui n'implémentent pas d'interface, mais vous ne pourrez pas utiliser les proxies pour les chargements d'associations paresseuses
+ - ce qui limitera vos possibilités d'ajustement des performances.
+ </para>
+ <para>
+ Vous devriez aussi éviter de déclarer des méthodes <literal>public final</literal> sur des classes
+ non-finales. Si vous voulez utiliser une classe avec une méthode <literal>public final</literal>, vous devez
+ explicitement désactiver les proxies en paramétrant
+ <literal>lazy="false"</literal>.
+ </para>
+ </sect2>
+
+ <sect2 id="persistent-classes-pojo-accessors" revision="2">
+ <title>Déclarer les accesseurs et mutateurs des attributs persistants (optionnel)</title>
+
+ <para>
+ <literal>Cat</literal> déclare des mutateurs pour toutes ses champs persistants. Beaucoup d'autres
+ solutions de mapping Objet/relationnel persistent directement les variables d'instance. Nous pensons
+ qu'il est bien mieux de fournir une indirection entre le schéma relationnel et les structures de données internes de la classe.
+ Par défaut, Hibernate persiste les propriétés suivant le style JavaBean, et reconnaît les noms de méthodes de la forme <literal>
+ getFoo</literal>, <literal>isFoo</literal> et
+ <literal>setFoo</literal>. Nous pouvons changer pour un accès direct aux champs pour des propriétés particulières, si besoin est.
+ </para>
+
+ <para>
+ Les propriétés <emphasis>n'ont pas</emphasis> à être déclarées publiques -
+ Hibernate peut persister une propriété avec un paire de getter/setter de
+ visibilité par défault, <literal>protected</literal> ou <literal>
+ private</literal>.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="persistent-classes-inheritance">
+ <title>Implémenter l'héritage</title>
+
+ <para>
+ Une sous-classe doit également suivre la première et la seconde règle.
+ Elle hérite sa propriété d'identifiant de <literal>Cat</literal>.
+ </para>
+
+ <programlisting><![CDATA[package eg;
+
+public class DomesticCat extends Cat {
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+ protected void setName(String name) {
+ this.name=name;
+ }
+}]]></programlisting>
+ </sect1>
+
+ <sect1 id="persistent-classes-equalshashcode" revision="1">
+ <title>Implémenter <literal>equals()</literal> et <literal>hashCode()</literal></title>
+
+ <para>
+ Vous devez surcharger les méthodes <literal>equals()</literal> et
+ <literal>hashCode()</literal> si vous
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ avez l'intention de mettre des instances de classes persistantes dans un <literal>Set</literal>
+ (la manière recommandée pour représenter des associations pluri-valuées)
+ <emphasis>et</emphasis>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ avez l'intention d'utiliser le réattachement d'instances détachées
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Hibernate garantit l'équivalence de l'identité persistante (ligne de base de données) et l'identité Java seulement
+ à l'intérieur de la portée d'une session particulière. Donc dès que nous mélangeons des instances venant de différentes
+ sessions, nous devons implémenter <literal>equals()</literal> et
+ <literal>hashCode()</literal> si nous souhaitons avoir une sémantique correcte pour les <literal>Set</literal>s.
+ </para>
+
+ <para>
+ La manière la plus évidente est d'implémenter <literal>equals()</literal>/<literal>hashCode()</literal>
+ en comparant la valeur de l'identifiant des deux objets. Si cette valeur est identique, les deux
+ doivent représenter la même ligne de base de données, ils sont donc égaux (si les deux sont
+ ajoutés à un <literal>Set</literal>, nous n'aurons qu'un seul élément dans le
+ <literal>Set</literal>). Malheureusement, nous ne pouvons pas utiliser cette approche avec
+ des identifiants générés ! Hibernate n'assignera de
+ valeur d'identifiant qu'aux objets qui sont persistants, une instance nouvellement créée n'aura
+ donc pas de valeur d'identifiant ! De plus, si une instance est non sauvegardée et actuellement dans un <literal>Set</literal>,
+ le sauvegarder assignera une valeur d'identifiant à l'objet. Si <literal>equals()</literal> et <literal>hashCode()</literal>
+ sont basées sur la valeur de l'identifiant, le code de hachage devrait changer, rompant le contrat du <literal>Set</literal>.
+ Regardez sur le site web d'Hibernate pour une discussion complète de ce problème.
+ Notez que ceci n'est pas un problème d'Hibernate, mais la sémantique normale de Java pour l'identité d'un objet et l'égalité.
+ </para>
+
+ <para>
+ Nous recommandons donc d'implémenter
+ <literal>equals()</literal> et <literal>hashCode()</literal> en utilisant <emphasis>
+ l'égalité par clé métier</emphasis>.L'égalité par clé métier signifie que la méthode <literal>equals()</literal>
+ compare uniquement les propriétés qui forment une clé métier, une clé qui
+ identifierait notre instance dans le monde réel (une clé candidate
+ <emphasis>naturelle</emphasis>) :
+ </para>
+
+ <programlisting><![CDATA[public class Cat {
+
+ ...
+ public boolean equals(Object other) {
+ if (this == other) return true;
+ if ( !(other instanceof Cat) ) return false;
+
+ final Cat cat = (Cat) other;
+
+ if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
+ if ( !cat.getMother().equals( getMother() ) ) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = getMother().hashCode();
+ result = 29 * result + getLitterId();
+ return result;
+ }
+
+}]]></programlisting>
+
+ <para>
+ Notez qu'une clef métier ne doit pas être solide comme une clef primaire de base de données
+ (voir <xref linkend="transactions-basics-identity"/>). Les propriétés
+ immuables ou uniques sont généralement de bonnes candidates pour une clef métier.
+ </para>
+
+ </sect1>
+
+ <sect1 id="persistent-classes-dynamicmodels">
+ <title>Modèles dynamiques</title>
+
+ <para>
+ <emphasis>Notez que la fonctionnalités suivantes sont actuellement considérées
+ comme expérimentales et peuvent changer dans un futur proche.</emphasis>
+ </para>
+
+ <para>
+ Les entités persistantes ne doivent pas nécessairement être représentées comme
+ des classes POJO ou des objets JavaBean à l'exécution. Hibernate supporte aussi les
+ modèles dynamiques (en utilisant des <literal>Map</literal>s de <literal>Map</literal>s
+ à l'exécution) et la représentation des entités comme des arbres DOM4J. Avec cette
+ approche, vous n'écrivez pas de classes persistantes, seulement des fichiers de mapping.
+ </para>
+
+ <para>
+ Par défaut, Hibernate fonctionne en mode POJO normal. Vous pouvez paramétrer
+ un mode de représentation d'entité par défaut pour une <literal>SessionFactory</literal>
+ particulière en utilisant l'option de configuration <literal>default_entity_mode</literal>
+ (voir <xref linkend="configuration-optional-properties"/>).
+ </para>
+
+ <para>
+ Les exemples suivants démontrent la représentation utilisant des <literal>Map</literal>s.
+ D'abord, dans le fichier de mapping, un <literal>entity-name</literal> doit être déclaré
+ au lieu (ou en plus) d'un nom de classe :
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class entity-name="Customer">
+
+ <id name="id"
+ type="long"
+ column="ID">
+ <generator class="sequence"/>
+ </id>
+
+ <property name="name"
+ column="NAME"
+ type="string"/>
+
+ <property name="address"
+ column="ADDRESS"
+ type="string"/>
+
+ <many-to-one name="organization"
+ column="ORGANIZATION_ID"
+ class="Organization"/>
+
+ <bag name="orders"
+ inverse="true"
+ lazy="false"
+ cascade="all">
+ <key column="CUSTOMER_ID"/>
+ <one-to-many class="Order"/>
+ </bag>
+
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Notez que même si des associations sont déclarées en utilisant des noms de classe cible,
+ le type de cible d'une association peut aussi être une entité dynamique au lieu d'un POJO.
+ </para>
+
+ <para>
+ Après avoir configuré le mode d'entité par défaut à <literal>dynamic-map</literal>
+ pour la <literal>SessionFactory</literal>, nous pouvons lors de l'exécution fonctionner
+ avec des <literal>Map</literal>s de <literal>Map</literal>s :
+ </para>
+
+ <programlisting><![CDATA[Session s = openSession();
+Transaction tx = s.beginTransaction();
+Session s = openSession();
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+
+// Create an organization
+Map foobar = new HashMap();
+foobar.put("name", "Foobar Inc.");
+
+// Link both
+david.put("organization", foobar);
+
+// Save both
+s.save("Customer", david);
+s.save("Organization", foobar);
+
+tx.commit();
+s.close();]]></programlisting>
+
+ <para>
+ Les avantages d'un mapping dynamique sont un gain de temps pour le prototypage
+ sans la nécessité d'implémenter les classes d'entité. Pourtant, vous perdez la
+ vérification du typage au moment de la compilation et aurez plus d'exceptions à
+ gérer lors de l'exécution. Grâce au mapping d'Hibernate, le schéma de la base de
+ données peut facilement être normalisé et solidifié, permettant de rajouter une
+ implémentation propre du modèle de domaine plus tard.
+ </para>
+
+ <para>
+ Les modes de représentation d'une entité peut aussi être configuré par <literal>Session</literal> :
+ </para>
+
+ <programlisting><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+dynamicSession.save("Customer", david);
+...
+dynamicSession.flush();
+dynamicSession.close()
+...
+// Continue on pojoSession
+]]></programlisting>
+
+
+ <para>
+ Veuillez noter que l'appel à <literal>getSession()</literal> en utilisant un
+ <literal>EntityMode</literal> se fait sur l'API <literal>Session</literal>, pas
+ <literal>SessionFactory</literal>. De cette manière, la nouvelle <literal>Session</literal>
+ partage les connexions JDBC, transactions et autres informations de contexte sous-jacentes.
+ Cela signifie que vous n'avez pas à appeler <literal>flush()</literal> et <literal>close()</literal>
+ sur la <literal>Session</literal> secondaire, et laissez aussi la gestion de la transaction
+ et de la connexion à l'unité de travail primaire.
+ </para>
+
+ <para>
+ Plus d'informations à propos de la représentation XML peuvent être trouvées dans
+ <xref linkend="xml"/>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="persistent-classes-tuplizers" revision="0">
+ <title>Tuplizers</title>
+
+ <para>
+ <literal>org.hibernate.tuple.Tuplizer</literal>, et ses sous-interfaces, sont responsables
+ de la gestion d'une représentation particulière d'un morceau de données, en fonction du
+ <literal>org.hibernate.EntityMode</literal> de réprésentation. Si un morceau donné de données
+ est pensé comme une structure de données, alors un tuplizer est la chose qui sait comment
+ créer une telle structure de données, comment extraire des valeurs et injecter des valeurs dans
+ une telle structure de données. Par exemple, pour le mode d'entité POJO, le tuplizer correspondant
+ sait comment créer le POJO à travers son constructeur et comment accéder aux propriétés du POJO
+ utilisant les accesseurs de la propriété définie. Il y a deux types de Tuplizers haut niveau,
+ représenté par les interfaces <literal>org.hibernate.tuple.EntityTuplizer</literal> et
+ <literal>org.hibernate.tuple.ComponentTuplizer</literal>. Les <literal>EntityTuplizer</literal>s
+ sont responsables de la gestion des contrats mentionnés ci-dessus pour les entités, alors que
+ les <literal>ComponentTuplizer</literal>s s'occupent des composants.
+ </para>
+
+ <para>
+ Les utilisateurs peuvent aussi brancher leurs propres tuplizers. Peut-être vous est-il nécessaire qu'une
+ implémentation de <literal>java.util.Map</literal> autre que <literal>java.util.HashMap</literal>
+ soit utilisée dans le mode d'entité dynamic-map ; ou peut-être avez-vous besoin de définir une
+ statégie de génération de proxy différente de celle utilisée par défaut. Les deux devraient être
+ effectuées en définissant une implémentation de tuplizer utilisateur. Les définitions de tuplizers
+ sont attachées au mapping de l'entité ou du composant qu'ils sont censés gérer. Retour à l'exemple de
+ notre entité utilisateur :
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+ <class entity-name="Customer">
+ <!--
+ Override the dynamic-map entity-mode
+ tuplizer for the customer entity
+ -->
+ <tuplizer entity-mode="dynamic-map"
+ class="CustomMapTuplizerImpl"/>
+
+ <id name="id" type="long" column="ID">
+ <generator class="sequence"/>
+ </id>
+
+ <!-- other properties -->
+ ...
+ </class>
+</hibernate-mapping>
+
+
+public class CustomMapTuplizerImpl
+ extends org.hibernate.tuple.DynamicMapEntityTuplizer {
+ // override the buildInstantiator() method to plug in our custom map...
+ protected final Instantiator buildInstantiator(
+ org.hibernate.mapping.PersistentClass mappingInfo) {
+ return new CustomMapInstantiator( mappingInfo );
+ }
+
+ private static final class CustomMapInstantiator
+ extends org.hibernate.tuple.DynamicMapInstantitor {
+ // override the generateMap() method to return our custom map...
+ protected final Map generateMap() {
+ return new CustomMap();
+ }
+ }
+}]]></programlisting>
+
+
+ </sect1>
+
+ <para>
+ TODO: Document user-extension framework in the property and proxy packages
+ </para>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/query_criteria.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/query_criteria.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/query_criteria.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,443 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="querycriteria">
+ <title>Requêtes par critères</title>
+
+ <para>
+ Hibernate offre une API d'interrogation par critères intuitive et extensible.
+ </para>
+
+ <sect1 id="querycriteria-creating">
+ <title>Créer une instance de <literal>Criteria</literal></title>
+
+ <para>
+ L'interface <literal>net.sf.hibernate.Criteria</literal> représente une requête sur une
+ classe persistente donnée. La <literal>Session</literal> fournit les instances de
+ <literal>Criteria</literal>.
+ </para>
+
+ <programlisting><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
+crit.setMaxResults(50);
+List cats = crit.list();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-narrowing">
+ <title>Restriction du résultat</title>
+
+ <para>
+ Un criterion (critère de recherche) est une instance de l'interface
+ <literal>org.hibernate.criterion.Criterion</literal>. La classe
+ <literal>org.hibernate.criterion.Restrictions</literal> définit
+ des méthodes pour obtenir des types de <literal>Criterion</literal>
+ pré-définis.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.like("name", "Fritz%") )
+ .add( Restrictions.between("weight", minWeight, maxWeight) )
+ .list();]]></programlisting>
+
+ <para>
+ Les restrictions peuvent être goupées de manière logique.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.like("name", "Fritz%") )
+ .add( Restrictions.or(
+ Restrictions.eq( "age", new Integer(0) ),
+ Restrictions.isNull("age")
+ ) )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
+ .add( Restrictions.disjunction()
+ .add( Restrictions.isNull("age") )
+ .add( Restrictions.eq("age", new Integer(0) ) )
+ .add( Restrictions.eq("age", new Integer(1) ) )
+ .add( Restrictions.eq("age", new Integer(2) ) )
+ ) )
+ .list();]]></programlisting>
+
+ <para>
+ Il y a plusieurs types de criterion pré-définis (sous classes de <literal>Restriction</literal>),
+ mais l'une d'entre elle particulièrement utile vous permet de spécifier directement
+ du SQL.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.sql("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
+ .list();]]></programlisting>
+
+ <para>
+ La zone <literal>{alias}</literal> sera remplacée par l'alias de colonne de l'entité
+ que l'on souhaite intérroger.
+ </para>
+
+ <para>
+ Une autre approche pour obtenir un criterion est de le récupérer d'une instance de <literal>Property</literal>.
+ Vous pouvez créer une <literal>Property</literal> en appelant <literal>Property.forName()</literal>.
+ </para>
+
+ <programlisting><![CDATA[
+Property age = Property.forName("age");
+List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.disjunction()
+ .add( age.isNull() )
+ .add( age.eq( new Integer(0) ) )
+ .add( age.eq( new Integer(1) ) )
+ .add( age.eq( new Integer(2) ) )
+ ) )
+ .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
+ .list();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-ordering">
+ <title>Trier les résultats</title>
+
+ <para>
+ Vous pouvez trier les résultats en utilisant <literal>org.hibernate.criterion.Order</literal>.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.like("name", "F%")
+ .addOrder( Order.asc("name") )
+ .addOrder( Order.desc("age") )
+ .setMaxResults(50)
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Property.forName("name").like("F%") )
+ .addOrder( Property.forName("name").asc() )
+ .addOrder( Property.forName("age").desc() )
+ .setMaxResults(50)
+ .list();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-associations" revision="2">
+ <title>Associations</title>
+
+ <para>
+ Vous pouvez facilement spécifier des contraintes sur des entités liées,
+ par des associations en utilisant <literal>createCriteria()</literal>.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.like("name", "F%")
+ .createCriteria("kittens")
+ .add( Restrictions.like("name", "F%")
+ .list();]]></programlisting>
+
+ <para>
+ Notez que la seconde <literal>createCriteria()</literal> retourne une nouvelle
+ instance de <literal>Criteria</literal>, qui se rapporte aux éléments de la
+ collection <literal>kittens</literal>.
+ </para>
+
+ <para>
+ La forme alternative suivante est utile dans certains cas.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .createAlias("kittens", "kt")
+ .createAlias("mate", "mt")
+ .add( Restrictions.eqProperty("kt.name", "mt.name") )
+ .list();]]></programlisting>
+
+ <para>
+ (<literal>createAlias()</literal> ne crée pas de nouvelle instance de
+ <literal>Criteria</literal>.)
+ </para>
+
+ <para>
+ Notez que les collections kittens contenues dans les instances de <literal>Cat</literal>
+ retournées par les deux précédentes requêtes ne sont <emphasis>pas</emphasis> pré-filtrées
+ par les critères ! Si vous souhaitez récupérer uniquement les kittens qui correspondent à la
+ criteria, vous devez utiliser <literal>ResultTransformer</literal>.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .createCriteria("kittens", "kt")
+ .add( Restrictions.eq("name", "F%") )
+ .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
+ .list();
+Iterator iter = cats.iterator();
+while ( iter.hasNext() ) {
+ Map map = (Map) iter.next();
+ Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
+ Cat kitten = (Cat) map.get("kt");
+}]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-dynamicfetching" revision="1">
+ <title>Peuplement d'associations de manière dynamique</title>
+
+ <para>
+ Vous pouvez spéficier au moment de l'exécution le peuplement d'une association en utilisant
+ <literal>setFetchMode()</literal> (c'est-à-dire le chargement de celle-ci).
+ Cela permet de surcharger les valeurs
+ "lazy" et "outer-join" du mapping.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.like("name", "Fritz%") )
+ .setFetchMode("mate", FetchMode.EAGER)
+ .setFetchMode("kittens", FetchMode.EAGER)
+ .list();]]></programlisting>
+
+ <para>
+ Cette requête recherchera <literal>mate</literal> et <literal>kittens</literal>
+ via les jointures externes. Voir <xref linkend="performance-fetching"/> pour plus d'informations.
+ </para>
+
+ </sect1>
+
+ <sect1 id="querycriteria-examples">
+ <title>Requêtes par l'exemple</title>
+
+ <para>
+ La classe <literal>org.hibernate.criterion.Example</literal> vous permet de
+ construire un critère suivant une instance d'objet donnée.
+ </para>
+
+ <programlisting><![CDATA[Cat cat = new Cat();
+cat.setSex('F');
+cat.setColor(Color.BLACK);
+List results = session.createCriteria(Cat.class)
+ .add( Example.create(cat) )
+ .list();]]></programlisting>
+
+ <para>
+ Les propriétés de type version, identifiant et association sont ignorées.
+ Par défaut, les valeurs null sont exclues.
+ </para>
+
+ <para>
+ Vous pouvez ajuster la stratégie d'utilisation de valeurs de
+ l'<literal>Exemple</literal>.
+ </para>
+
+ <programlisting><![CDATA[Example example = Example.create(cat)
+ .excludeZeroes() //exclude zero valued properties
+ .excludeProperty("color") //exclude the property named "color"
+ .ignoreCase() //perform case insensitive string comparisons
+ .enableLike(); //use like for string comparisons
+List results = session.createCriteria(Cat.class)
+ .add(example)
+ .list();]]></programlisting>
+
+ <para>
+ Vous pouvez utiliser les "exemples" pour des critères sur les objets associés.
+ </para>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .add( Example.create(cat) )
+ .createCriteria("mate")
+ .add( Example.create( cat.getMate() ) )
+ .list();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-projection">
+ <title>Projections, agrégation et regroupement</title>
+ <para>
+ La classe <literal>org.hibernate.criterion.Projections</literal> est une
+ fabrique d'instances de <literal>Projection</literal>. Nous appliquons une
+ projection sur une requête en appelant <literal>setProjection()</literal>.
+ </para>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.rowCount() )
+ .add( Restrictions.eq("color", Color.BLACK) )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.projectionList()
+ .add( Projections.rowCount() )
+ .add( Projections.avg("weight") )
+ .add( Projections.max("weight") )
+ .add( Projections.groupProperty("color") )
+ )
+ .list();]]></programlisting>
+
+ <para>
+ Il n'y a pas besoin de "group by" explicite dans une requête par critère.
+ Certains types de projection sont définis pour être des <emphasis>projections
+ de regroupement</emphasis>, lesquels apparaissent aussi dans la clause
+ <literal>group by</literal> SQL.
+ </para>
+
+ <para>
+ Un alias peut optionnellement être assigné à une projection, ainsi la valeur
+ projetée peut être référencée dans des restrictions ou des tris. Voici deux façons
+ différentes de faire ça :
+ </para>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
+ .addOrder( Order.asc("colr") )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.groupProperty("color").as("colr") )
+ .addOrder( Order.asc("colr") )
+ .list();]]></programlisting>
+
+ <para>
+ Les méthodes <literal>alias()</literal> et <literal>as()</literal> enveloppe simplement
+ une instance de projection dans une autre instance (aliasée) de <literal>Projection</literal>.
+ Comme un raccourci, vous pouvez assignez un alias lorsque vous ajoutez la projection à la
+ liste de projections :
+ </para>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.projectionList()
+ .add( Projections.rowCount(), "catCountByColor" )
+ .add( Projections.avg("weight"), "avgWeight" )
+ .add( Projections.max("weight"), "maxWeight" )
+ .add( Projections.groupProperty("color"), "color" )
+ )
+ .addOrder( Order.desc("catCountByColor") )
+ .addOrder( Order.desc("avgWeight") )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Domestic.class, "cat")
+ .createAlias("kittens", "kit")
+ .setProjection( Projections.projectionList()
+ .add( Projections.property("cat.name"), "catName" )
+ .add( Projections.property("kit.name"), "kitName" )
+ )
+ .addOrder( Order.asc("catName") )
+ .addOrder( Order.asc("kitName") )
+ .list();]]></programlisting>
+
+ <para>
+ Vous pouvez aussi utiliser <literal>Property.forName()</literal> pour formuler des projections :
+ </para>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Property.forName("name") )
+ .add( Property.forName("color").eq(Color.BLACK) )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.projectionList()
+ .add( Projections.rowCount().as("catCountByColor") )
+ .add( Property.forName("weight").avg().as("avgWeight") )
+ .add( Property.forName("weight").max().as("maxWeight") )
+ .add( Property.forName("color").group().as("color" )
+ )
+ .addOrder( Order.desc("catCountByColor") )
+ .addOrder( Order.desc("avgWeight") )
+ .list();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-detachedqueries">
+ <title>Requêtes et sous-requêtes détachées</title>
+ <para>
+ La classe <literal>DetachedCriteria</literal> vous laisse créer une requête en dehors de la
+ portée de la session, et puis l'exécuter plus tard en utilisant n'importe quelle <literal>Session</literal>
+ arbitraire.
+ </para>
+
+ <programlisting><![CDATA[DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
+ .add( Property.forName("sex").eq('F') );
+
+Session session = ....;
+Transaction txn = session.beginTransaction();
+List results = query.getExecutableCriteria(session).setMaxResults(100).list();
+txn.commit();
+session.close();]]></programlisting>
+
+ <para>
+ Une <literal>DetachedCriteria</literal> peut aussi être utilisée pour exprimer une
+ sous-requête. Des instances de criterion impliquant des sous-requêtes peuvent être
+ obtenues via <literal>Subqueries</literal> ou <literal>Property</literal>.
+ </para>
+
+ <programlisting><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
+ .setProjection( Property.forName("weight").avg() );
+session.createCriteria(Cat.class)
+ .add( Property.forName("weight).gt(avgWeight) )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
+ .setProjection( Property.forName("weight") );
+session.createCriteria(Cat.class)
+ .add( Subqueries.geAll("weight", weights) )
+ .list();]]></programlisting>
+
+ <para>
+ Même des requêtes corrélées sont possibles :
+ </para>
+
+ <programlisting><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
+ .setProjection( Property.forName("weight").avg() )
+ .add( Property.forName("cat2.sex").eqProperty("cat.sex") );
+session.createCriteria(Cat.class, "cat")
+ .add( Property.forName("weight).gt(avgWeightForSex) )
+ .list();]]></programlisting>
+
+ </sect1>
+
+ <!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer allow returning arbitrary
+ user objects - similar to setResultClass in JDO2. General use of ResultTransformer
+ could also be explained. -->
+
+ <sect1 id="query-criteria-naturalid">
+ <title>Requêtes par identifiant naturel</title>
+
+ <para>
+ Pour la plupart des requêtes, incluant les requêtes par critère, le cache de requêtes
+ n'est pas très efficace, parce que l'invalidation du cache de requêtes arrive trop
+ souvent. Cependant, il y a une sorte spéciale de requête où nous pouvons optimiser
+ l'algorithme d'invalidation du cache : les recherches sur une clef naturelle constante.
+ Dans certaines applications, cette sorte de requête se produit fréquemment. L'API de
+ critère fournit une provision spéciale pour ce cas d'utilisation.
+ </para>
+
+ <para>
+ D'abord vous devriez mapper la clef naturelle de votre entité en utilisant
+ <literal><natural-id></literal>, et activer l'utilisation du cache de second niveau.
+ </para>
+
+ <programlisting><![CDATA[<class name="User">
+ <cache usage="read-write"/>
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <natural-id>
+ <property name="name"/>
+ <property name="org"/>
+ </natural-id>
+ <property name="password"/>
+</class>]]></programlisting>
+
+ <para>
+ Notez que cette fonctionnalité n'est pas prévue pour l'utilisation avec des
+ entités avec des clefs naturelles <emphasis>mutables</emphasis>.
+ </para>
+
+ <para>
+ Ensuite, activez le cache de requête d'Hibernate.
+ </para>
+
+ <para>
+ Maintenant <literal>Restrictions.naturalId()</literal> nous permet de rendre
+ l'utilisation de l'algorithme de cache plus efficace.
+ </para>
+
+ <programlisting><![CDATA[session.createCriteria(User.class)
+ .add( Restrictions.naturalId()
+ .set("name", "gavin")
+ .set("org", "hb")
+ ).setCacheable(true)
+ .uniqueResult();]]></programlisting>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/query_hql.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/query_hql.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/query_hql.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,1149 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="queryhql">
+ <title>HQL: Langage de requêtage d'Hibernate</title>
+
+ <para>
+ Hibernate fourni un langage d'interrogation extrêmement puissant qui
+ ressemble (et c'est voulu) au SQL. Mais ne soyez pas distraits par la syntaxe ;
+ HQL est totalement orienté objet, comprenant des notions d'héritage, de
+ polymorphisme et d'association.
+ </para>
+
+ <sect1 id="queryhql-casesensitivity">
+ <title>Sensibilité à la casse</title>
+
+ <para>
+ Les requêtes sont insensibles à la casse, à l'exception des noms des classes Java
+ et des propriétés.
+ Ainsi, <literal>SeLeCT</literal> est identique à
+ <literal>sELEct</literal> et à
+ <literal>SELECT</literal> mais
+ <literal>net.sf.hibernate.eg.FOO</literal> n'est pas identique
+ <literal>net.sf.hibernate.eg.Foo</literal> et
+ <literal>foo.barSet</literal> n'est pas identique à
+ <literal>foo.BARSET</literal>.
+ </para>
+
+ <para>
+ Ce guide utilise les mots clés HQL en minuscule. Certains utilisateurs trouvent les
+ requêtes écrites avec les mots clés en majuscule plus lisibles, mais nous trouvons
+ cette convention pénible lorsqu'elle est lue dans du code Java.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-from">
+ <title>La clause from</title>
+
+ <para>
+ La requête Hibernate la plus simple est de la forme :
+ </para>
+
+ <programlisting><![CDATA[from eg.Cat]]></programlisting>
+
+ <para>
+ qui retourne simplement toutes les instances de la classe <literal>eg.Cat</literal>.
+ Nous n'avons pas besoin d'habitude de qualifier le nom de la classe,
+ puisque <literal>auto-import</literal> est la valeur par défaut. Donc nous écrivons presque toujours :
+ </para>
+
+ <programlisting><![CDATA[from Cat]]></programlisting>
+
+ <para>
+ La plupart du temps, vous devrez assigner un <emphasis>alias</emphasis> puisque vous
+ voudrez faire référence à <literal>Cat</literal> dans d'autres parties de la requête.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+ <para>
+ Cette requête assigne l'alias <literal>cat</literal> à l'instance <literal>Cat</literal>,
+ nous pouvons donc utiliser cet alias ailleurs dans la requête. Le mot clé <literal>as</literal>
+ est optionnel ; nous aurions pu écrire :
+ </para>
+
+ <programlisting><![CDATA[from Cat cat]]></programlisting>
+
+ <para>
+ Plusieurs classes peuvent apparaître, ce qui conduira à un produit
+ cartésien (encore appelé jointures croisées).
+ </para>
+
+ <programlisting><![CDATA[from Formula, Parameter]]></programlisting>
+ <programlisting><![CDATA[from Formula as form, Parameter as param]]></programlisting>
+
+ <para>
+ C'est une bonne pratique que de nommer les alias dans les requêtes en utilisant l'initiale
+ en miniscule, ce qui a le mérite d'être en phase avec les standards de
+ nommage Java pour les variables locales (<literal>domesticCat</literal>).
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-joins" revision="1">
+ <title>Associations et jointures</title>
+
+ <para>
+ On peut aussi assigner des alias à des entités associées, ou même aux éléments d'une collection
+ de valeurs, en utilisant un <literal>join</literal> (jointure).
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ inner join cat.mate as mate
+ left outer join cat.kittens as kitten]]></programlisting>
+
+ <programlisting><![CDATA[from Cat as cat left join cat.mate.kittens as kittens]]></programlisting>
+
+ <programlisting><![CDATA[from Formula form full join form.parameter param]]></programlisting>
+
+ <para>
+ Les types de jointures supportées sont celles de ANSI SQL
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>inner join</literal> (jointure fermée)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>left outer join</literal> (jointure ouverte par la gauche)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>right outer join</literal> (jointure ouverte par la droite)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>full join</literal> (jointure ouverte totalement - généralement inutile)
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Les constructions des jointures <literal>inner join</literal>, <literal>left outer join</literal>
+ et <literal>right outer join</literal> peuvent être abbrégées.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ join cat.mate as mate
+ left join cat.kittens as kitten]]></programlisting>
+
+ <para>
+ Nous pouvons soumettre des conditions de jointure supplémentaires en utilisant le mot-clef HQL <literal>with</literal>.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ left join cat.kittens as kitten
+ with kitten.bodyWeight > 10.0]]></programlisting>
+
+ <para>
+ Par ailleurs, une jointure "fetchée" (rapportée) permet d'initialiser
+ les associations ou collections de valeurs en même temps que leur objet parent,
+ le tout n'utilisant qu'un seul Select.
+ Ceci est particulièrement utile dans le cas des collections. Ce système permet de surcharger
+ les déclarations "lazy" et "outer-join" des fichiers de mapping pour les associations et
+ collections. Voir
+ <xref linkend="performance-fetching"/> pour plus d'informations.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ inner join fetch cat.mate
+ left join fetch cat.kittens]]></programlisting>
+
+ <para>
+ Une jointure "fetchée" (rapportée) n'a généralement pas besoin de se voir assigner
+ un alias puisque les objets associés n'ont pas à être utilisés dans les autres clauses.
+ Notez aussi que les objets associés ne sont pas retournés directement dans le résultat de
+ la requête mais l'on peut y accéder via l'objet parent. La seule raison pour laquelle nous
+ pourrions avoir besoin d'un alias est si nous récupérions récursivement une collection supplémentaire :
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ inner join fetch cat.mate
+ left join fetch cat.kittens child
+ left join fetch child.kittens]]></programlisting>
+
+ <para>
+ Notez que la construction de <literal>fetch</literal> ne peut pas être utilisée dans les requêtes appelées par
+ <literal>scroll()</literal> ou <literal>iterate()</literal>.
+ <literal>fetch</literal> ne devrait pas non plus être utilisé avec <literal>setMaxResults()</literal> ou
+ <literal>setFirstResult()</literal>. <literal>fetch</literal> ne peut pas non plus être utilisé avec une
+ condition <literal>with</literal> ad hoc. Il est
+ possible de créer un produit cartésien par jointure en récupérant plus d'une collection dans une requête,
+ donc faites attention dans ce cas. Récupérer par jointure de multiples collections donne aussi parfois
+ des résultats inattendus pour des mappings de bag, donc soyez prudent lorsque vous formulez vos requêtes dans de tels cas.
+ Finalement, notez que <literal>full join fetch</literal> et <literal>right join fetch</literal> ne sont pas utiles en général.
+ </para>
+
+ <para>
+ Si vous utilisez un chargement retardé pour les propriétés (avec une instrumentation par bytecode), il est possible
+ de forcer Hibernate à récupérer les propriétés non encore chargées immédiatement (dans la première requête)
+ en utilisant <literal>fetch all properties</literal>.
+ </para>
+
+ <programlisting><![CDATA[from Document fetch all properties order by name]]></programlisting>
+ <programlisting><![CDATA[from Document doc fetch all properties where lower(doc.name) like '%cats%']]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-joins-forms">
+ <title>Formes de syntaxes pour les jointures</title>
+
+ <para>
+ HQL supporte deux formes pour joindre les associations: <literal>implicite</literal> et <literal>explicite</literal>.
+ </para>
+
+ <para>
+ Les requêtes présentes dans la section précédente utilisent la forme <literal>explicite</literal>
+ où le mode clé join est explicitement utilisé dans la clause from. C'est la forme recommandée.
+ </para>
+
+ <para>
+ La forme <literal>implicite</literal> n'utilise pas le mot clé join.
+ A la place, les associations sont "déréférencées" en utilisant le notation '.'. Ces
+ jointures peuvent apparaitre dans toutes les clauses. Les jointures <literal>implicites</literal>
+ résultent en des inner join dans le SQL généré.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat where cat.mate.name like '%s%']]></programlisting>
+ </sect1>
+
+ <sect1 id="queryhql-select">
+ <title>La clause select</title>
+
+ <para>
+ La clause <literal>select</literal> sélectionne les objets et propriétés
+ qui doivent être retournés dans le résultat de la requête.
+ Soit :
+ </para>
+
+ <programlisting><![CDATA[select mate
+from Cat as cat
+ inner join cat.mate as mate]]></programlisting>
+
+ <para>
+ La requête recherchera les <literal>mate</literal>s liés aux <literal>Cat</literal>s.
+ Vous pouvez explimer la requête d'une manière plus compacte :
+ </para>
+
+ <programlisting><![CDATA[select cat.mate from Cat cat]]></programlisting>
+
+ <para>
+ Les requêtes peuvent retourner des propriétés de n'importe quel type, même celles de type
+ composant (component) :
+ </para>
+
+ <programlisting><![CDATA[select cat.name from DomesticCat cat
+where cat.name like 'fri%']]></programlisting>
+
+ <programlisting><![CDATA[select cust.name.firstName from Customer as cust]]></programlisting>
+
+ <para>
+ Les requêtes peuvent retourner plusieurs objets et/ou propriétés sous la forme
+ d'un tableau du type <literal>Object[]</literal>,
+ </para>
+
+ <programlisting><![CDATA[select mother, offspr, mate.name
+from DomesticCat as mother
+ inner join mother.mate as mate
+ left outer join mother.kittens as offspr]]></programlisting>
+
+ <para>
+ ou sous la forme d'une <literal>List</literal>,
+ </para>
+
+ <programlisting><![CDATA[select new list(mother, offspr, mate.name)
+from DomesticCat as mother
+ inner join mother.mate as mate
+ left outer join mother.kittens as offspr]]></programlisting>
+
+ <para>
+ ou sous la forme d'un objet Java typé,
+ </para>
+
+ <programlisting><![CDATA[select new Family(mother, mate, offspr)
+from DomesticCat as mother
+ join mother.mate as mate
+ left join mother.kittens as offspr]]></programlisting>
+
+ <para>
+ à condition que la classe <literal>Family</literal> possède le constructeur approprié.
+ </para>
+
+ <para>
+ Vous pouvez assigner des alias aux expressions sélectionnées en utilisant <literal>as</literal> :
+ </para>
+
+ <programlisting><![CDATA[select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n
+from Cat cat]]></programlisting>
+
+ <para>
+ C'est surtout utile lorsque c'est utilisé avec
+ <literal>select new map</literal> :
+ </para>
+
+ <programlisting><![CDATA[select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
+from Cat cat]]></programlisting>
+
+ <para>
+ Cette requête retourne une <literal>Map</literal> à partir des alias vers les valeurs sélectionnées.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-aggregation">
+ <title>Fonctions d'aggrégation</title>
+
+ <para>
+ Les requêtes HQL peuvent aussi retourner le résultat de fonctions d'aggrégation
+ sur les propriétés :
+ </para>
+
+ <programlisting><![CDATA[select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
+from Cat cat]]></programlisting>
+
+<!-- NO LONGER SUPPORTED
+ <para>
+ Collections may also appear inside aggregate functions in the <literal>select</literal>
+ clause.
+ </para>
+
+ <programlisting><![CDATA[select cat, count( elements(cat.kittens) )
+from Cat cat group by cat]]></programlisting>
+-->
+
+ <para>
+ Les fonctions supportées sont
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>avg(...), sum(...), min(...), max(...)</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>count(*)</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>count(...), count(distinct ...), count(all...)</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Vous pouvez utiliser des opérateurs arithmétiques, la concaténation, et des fonctions SQL reconnues dans la clause select :
+ </para>
+
+ <programlisting><![CDATA[select cat.weight + sum(kitten.weight)
+from Cat cat
+ join cat.kittens kitten
+group by cat.id, cat.weight]]></programlisting>
+
+ <programlisting><![CDATA[select firstName||' '||initial||' '||upper(lastName) from Person]]></programlisting>
+
+ <para>
+ Les mots clé <literal>distinct</literal> et <literal>all</literal> peuvent être utilisés et ont
+ la même signification qu'en SQL.
+ </para>
+
+ <programlisting><![CDATA[select distinct cat.name from Cat cat
+
+select count(distinct cat.name), count(cat) from Cat cat]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-polymorphism">
+ <title>Requêtes polymorphiques</title>
+
+ <para>
+ Une requête comme:
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+ <para>
+ retourne non seuleument les instances de <literal>Cat</literal>, mais aussi celles des
+ sous classes comme <literal>DomesticCat</literal>. Les requêtes Hibernate peuvent nommer n'importe
+ quelle classe ou interface Java dans la clause <literal>from</literal>. La requête retournera les
+ instances de toutes les classes persistantes qui étendent cette classe ou implémente cette interface.
+ La requête suivante retournera tous les objets persistants :
+ </para>
+
+ <programlisting><![CDATA[from java.lang.Object o]]></programlisting>
+
+ <para>
+ L'interface <literal>Named</literal> peut être implémentée par plusieurs classes persistantes :
+ </para>
+
+ <programlisting><![CDATA[from Named n, Named m where n.name = m.name]]></programlisting>
+
+ <para>
+ Notez que ces deux dernières requêtes nécessitent plus d'un <literal>SELECT</literal> SQL.
+ Ce qui signifie que la clause <literal>order by</literal> ne trie pas correctement la totalité
+ des résultats (cela signifie aussi que vous ne pouvez exécuter ces requêtes en appelant
+ <literal>Query.scroll()</literal>).
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-where">
+ <title>La clause where</title>
+
+ <para>
+ La clause <literal>where</literal> vous permet de réduire la liste des instances retournées.
+ Si aucun alias n'existe, vous pouvez vous référer aux propriétés par leur nom :
+ </para>
+
+ <programlisting><![CDATA[from Cat where name='Fritz']]></programlisting>
+
+ <para>
+ S'il y a un alias, utilisez un nom de propriété qualifié :
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat where cat.name='Fritz']]></programlisting>
+
+ <para>
+ retourne les instances de <literal>Cat</literal> dont name est égale à 'Fritz'.
+ </para>
+
+ <programlisting><![CDATA[select foo
+from Foo foo, Bar bar
+where foo.startDate = bar.date]]></programlisting>
+
+ <para>
+ retournera les instances de <literal>Foo</literal> pour lesquelles
+ il existe une instance de <literal>bar</literal> avec la
+ propriété <literal>date</literal> est égale à la
+ propriété <literal>startDate</literal> de <literal>Foo</literal>.
+ Les expressions utilisant la navigation rendent la clause <literal>where</literal>
+ extrêmement puissante. Soit :
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.mate.name is not null]]></programlisting>
+
+ <para>
+ Cette requête se traduit en SQL par une jointure interne à une table.
+ Si vous souhaitez écrire quelque chose comme :
+ </para>
+
+ <programlisting><![CDATA[from Foo foo
+where foo.bar.baz.customer.address.city is not null]]></programlisting>
+
+ <para>
+ vous finiriez avec une requête qui nécessiterait quatre jointures en SQL.
+ </para>
+
+ <para>
+ L'opérateur <literal>=</literal> peut être utilisé pour comparer aussi bien des propriétés que des instances :
+ </para>
+
+ <programlisting><![CDATA[from Cat cat, Cat rival where cat.mate = rival.mate]]></programlisting>
+
+ <programlisting><![CDATA[select cat, mate
+from Cat cat, Cat mate
+where cat.mate = mate]]></programlisting>
+
+ <para>
+ La propriété spéciale (en minuscule) <literal>id</literal> peut être utilisée
+ pour faire référence à l'identifiant d'un objet (vous pouvez aussi utiliser
+ le nom de cette propriété).
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat where cat.id = 123
+
+from Cat as cat where cat.mate.id = 69]]></programlisting>
+
+ <para>
+ La seconde requête est particulièrement efficace. Aucune jointure n'est nécessaire !
+ </para>
+
+ <para>
+ Les propriétés d'un identifiant composé peuvent aussi être utilisées. Supposez que
+ <literal>Person</literal> ait un identifiant composé de <literal>country</literal> et
+ <literal>medicareNumber</literal>.
+ </para>
+
+ <programlisting><![CDATA[from bank.Person person
+where person.id.country = 'AU'
+ and person.id.medicareNumber = 123456]]></programlisting>
+
+ <programlisting><![CDATA[from bank.Account account
+where account.owner.id.country = 'AU'
+ and account.owner.id.medicareNumber = 123456]]></programlisting>
+
+ <para>
+ Une fois de plus, la seconde requête ne nécessite pas de jointure.
+ </para>
+
+ <para>
+ De même, la propriété spéciale <literal>class</literal> interroge la valeur discriminante
+ d'une instance dans le cas d'une persistance polymorphique. Le nom d'une classe Java incorporée
+ dans la clause where sera traduite par sa valeur discriminante.
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.class = DomesticCat]]></programlisting>
+
+ <para>
+ Vous pouvez aussi spécifier les propriétés des composants ou types utilisateurs composés
+ (components, composite user types etc). N'essayez jamais d'utiliser un expression de navigation
+ qui se terminerait par une propriété de type composant (qui est différent d'une propriété d'un
+ composant). Par exemple, si <literal>store.owner</literal> est une entité avec un composant
+ <literal>address</literal>
+ </para>
+
+ <programlisting><![CDATA[store.owner.address.city // okay
+store.owner.address // error!]]></programlisting>
+
+ <para>
+ Un type "any" possède les propriétés spéciales <literal>id</literal> et <literal>class</literal>,
+ qui nous permettent d'exprimer une jointure de la manière suivante (où <literal>AuditLog.item</literal>
+ est une propriété mappée avec <literal><any></literal>).
+ </para>
+
+ <programlisting><![CDATA[from AuditLog log, Payment payment
+where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting>
+
+ <para>
+ Dans la requête précédente, notez que <literal>log.item.class</literal> et <literal>payment.class</literal>
+ feraient référence à des valeurs de colonnes de la base de données complètement différentes.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-expressions">
+ <title>Expressions</title>
+
+ <para>
+ Les expressions permises dans la clause <literal>where</literal> incluent
+ la plupart des choses que vous pouvez utiliser en SQL :
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ opérateurs mathématiques <literal>+, -, *, /</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ opérateur de comparaison binaire <literal>=, >=, <=, <>, !=, like</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ opérateurs logiques <literal>and, or, not</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Parenthèses <literal>( )</literal>, indiquant un regroupement
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>in</literal>,
+ <literal>not in</literal>,
+ <literal>between</literal>,
+ <literal>is null</literal>,
+ <literal>is not null</literal>,
+ <literal>is empty</literal>,
+ <literal>is not empty</literal>,
+ <literal>member of</literal> and
+ <literal>not member of</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ "Simple" case, <literal>case ... when ... then ... else ... end</literal>, and
+ "searched" case, <literal>case when ... then ... else ... end</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ concatenation de chaîne de caractères <literal>...||...</literal> ou <literal>concat(...,...)</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>current_date()</literal>, <literal>current_time()</literal>,
+ <literal>current_timestamp()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>second(...)</literal>, <literal>minute(...)</literal>,
+ <literal>hour(...)</literal>, <literal>day(...)</literal>,
+ <literal>month(...)</literal>, <literal>year(...)</literal>,
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ N'importe quel fonction ou opérateur défini par EJB-QL 3.0 : <literal>substring(), trim(),
+ lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(), mod()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>coalesce()</literal> et <literal>nullif()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>str()</literal> pour convertir des valeurs numériques ou temporelles vers une chaîne de caractères lisible
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>cast(... as ...)</literal>, où le second argument est le nom d'un type Hibernate, et <literal>extract(... from ...)</literal> si le
+ <literal>cast()</literal> ANSI et <literal>extract()</literal> sont supportés par la base de données sous-jacente
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ La fonction HQL <literal>index()</literal>, qui s'applique aux alias d'une collection indexée jointe
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Les fonctions HQL qui s'appliquent expressions représentant des collections : <literal>size(),
+ minelement(), maxelement(), minindex(), maxindex()</literal>, ainsi que les fonctions spéciales <literal>elements()</literal>
+ et <literal>indices</literal> qui peuvent être quantifiées en utilisant <literal>some, all, exists, any, in</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ N'importe quelle fonction scalaire supportée par la base de données comme
+ <literal>sign()</literal>,
+ <literal>trunc()</literal>, <literal>rtrim()</literal>, <literal>sin()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Les paramètres positionnels de JDBC
+ <literal>?</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ paramètres nommés <literal>:name</literal>, <literal>:start_date</literal>, <literal>:x1</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ littéral SQL <literal>'foo'</literal>, <literal>69</literal>, <literal>'1970-01-01 10:00:01.0'</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Constantes Java <literal>public static final</literal> <literal>eg.Color.TABBY</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ <literal>in</literal> et <literal>between</literal> peuvent être utilisés comme suit :
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name between 'A' and 'B']]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+ <para>
+ et la forme négative peut être écrite
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name not between 'A' and 'B']]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+ <para>
+ De même, <literal>is null</literal> et <literal>is not null</literal> peuvent être utilisés pour tester
+ les valeurs nulle.
+ </para>
+
+ <para>
+ Les booléens peuvent être facilement utilisés en déclarant les substitutions de requêtes dans la
+ configuration Hibernate :
+ </para>
+
+ <programlisting><![CDATA[<property name="hibernate.query.substitutions">true 1, false 0</property>]]></programlisting>
+
+ <para>
+ Ce qui remplacera les mots clés <literal>true</literal> et <literal>false</literal> par
+ <literal>1</literal> et <literal>0</literal> dans la traduction SQL du HQL suivant :
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.alive = true]]></programlisting>
+
+ <para>
+ Vous pouvez tester la taille d'une collection par la propriété spéciale <literal>size</literal>, ou
+ la fonction spéciale <literal>size()</literal>.
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.kittens.size > 0]]></programlisting>
+
+ <programlisting><![CDATA[from Cat cat where size(cat.kittens) > 0]]></programlisting>
+
+ <para>
+ Pour les collections indexées, vous pouvez faire référence aux indices minimum et maximum en
+ utilisant les fonctions <literal>minindex</literal> and <literal>maxindex</literal>. De manière similaire,
+ vous pouvez faire référence aux éléments minimum et maximum d'une collection de type basiques
+ en utilisant les fonctions <literal>minelement</literal> et <literal>maxelement</literal>.
+ </para>
+
+ <programlisting><![CDATA[from Calendar cal where maxelement(cal.holidays) > current date]]></programlisting>
+
+ <programlisting><![CDATA[from Order order where maxindex(order.items) > 100]]></programlisting>
+
+ <programlisting><![CDATA[from Order order where minelement(order.items) > 10000]]></programlisting>
+
+ <para>
+ Les fonctions SQL <literal>any, some, all, exists, in</literal> supportent que leur soient passées
+ l'élément, l'index d'une collection (fonctions <literal>elements</literal> et <literal>indices</literal>)
+ ou le résultat d'une sous requête (voir ci dessous).
+ </para>
+
+ <programlisting><![CDATA[select mother from Cat as mother, Cat as kit
+where kit in elements(foo.kittens)]]></programlisting>
+
+ <programlisting><![CDATA[select p from NameList list, Person p
+where p.name = some elements(list.names)]]></programlisting>
+
+ <programlisting><![CDATA[from Cat cat where exists elements(cat.kittens)]]></programlisting>
+
+ <programlisting><![CDATA[from Player p where 3 > all elements(p.scores)]]></programlisting>
+
+ <programlisting><![CDATA[from Show show where 'fizard' in indices(show.acts)]]></programlisting>
+
+ <para>
+ Notez que l'écriture de - <literal>size</literal>, <literal>elements</literal>,
+ <literal>indices</literal>, <literal>minindex</literal>, <literal>maxindex</literal>,
+ <literal>minelement</literal>, <literal>maxelement</literal> - peuvent seulement être utilisée dans la clause where dans Hibernate3.
+ </para>
+
+ <para>
+ Les éléments de collections indexées (arrays, lists, maps) peuvent être référencés via index
+ (dans une clause where seulement) :
+ </para>
+
+ <programlisting><![CDATA[from Order order where order.items[0].id = 1234]]></programlisting>
+
+ <programlisting><![CDATA[select person from Person person, Calendar calendar
+where calendar.holidays['national day'] = person.birthDay
+ and person.nationality.calendar = calendar]]></programlisting>
+
+ <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11]]></programlisting>
+
+ <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ maxindex(order.items) ] = item and order.id = 11]]></programlisting>
+
+ <para>
+ L'expression entre <literal>[]</literal> peut même être une expression arithmétique.
+ </para>
+
+ <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ size(order.items) - 1 ] = item]]></programlisting>
+
+ <para>
+ HQL propose aussi une fonction <literal>index()</literal> interne, pour les éléments
+ d'une association one-to-many ou d'une collections de valeurs.
+ </para>
+
+ <programlisting><![CDATA[select item, index(item) from Order order
+ join order.items item
+where index(item) < 5]]></programlisting>
+
+ <para>
+ Les fonctions SQL scalaires supportées par la base de données utilisée peuvent être utilisées
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat where upper(cat.name) like 'FRI%']]></programlisting>
+
+ <para>
+ Si vous n'êtes pas encore convaincu par tout cela, imaginez la taille et l'illisibilité qui caractériseraient
+ la transformation SQL de la requête HQL suivante :
+ </para>
+
+ <programlisting><![CDATA[select cust
+from Product prod,
+ Store store
+ inner join store.customers cust
+where prod.name = 'widget'
+ and store.location.name in ( 'Melbourne', 'Sydney' )
+ and prod = all elements(cust.currentOrder.lineItems)]]></programlisting>
+
+ <para>
+ <emphasis>Un indice :</emphasis> cela donnerait quelque chose comme
+ </para>
+
+ <programlisting><![CDATA[SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
+FROM customers cust,
+ stores store,
+ locations loc,
+ store_customers sc,
+ product prod
+WHERE prod.name = 'widget'
+ AND store.loc_id = loc.id
+ AND loc.name IN ( 'Melbourne', 'Sydney' )
+ AND sc.store_id = store.id
+ AND sc.cust_id = cust.id
+ AND prod.id = ALL(
+ SELECT item.prod_id
+ FROM line_items item, orders o
+ WHERE item.order_id = o.id
+ AND cust.current_order = o.id
+ )]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-ordering">
+ <title>La clause order by</title>
+
+ <para>
+ La liste retounée par la requête peut être triée par n'importe quelle propriété de la classe ou
+ du composant retourné :
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat
+order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
+
+ <para>
+ Le mot optionnel <literal>asc</literal> ou <literal>desc</literal> indique respectivement si le tri
+ doit être croissant ou décroissant.
+ </para>
+ </sect1>
+
+ <sect1 id="queryhql-grouping">
+ <title>La clause group by</title>
+
+ <para>
+ Si la requête retourne des valeurs aggrégées, celles ci peuvent être groupées par propriété ou composant :
+ </para>
+
+ <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
+from Cat cat
+group by cat.color]]></programlisting>
+
+ <programlisting><![CDATA[select foo.id, avg(name), max(name)
+from Foo foo join foo.names name
+group by foo.id]]></programlisting>
+
+ <para>
+ Une clause <literal>having</literal> est aussi permise.
+ </para>
+
+ <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
+from Cat cat
+group by cat.color
+having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting>
+
+ <para>
+ Les fonctions SQL et les fonctions d'aggrégations sont permises dans les clauses <literal>having</literal>
+ et <literal>order by</literal>, si elles sont supportées par la base de données (ce que ne fait pas MySQL par exemple).
+ </para>
+
+ <programlisting><![CDATA[select cat
+from Cat cat
+ join cat.kittens kitten
+group by cat
+having avg(kitten.weight) > 100
+order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
+
+ <para>
+ Notez que ni la clause <literal>group by</literal> ni la clause
+ <literal>order by</literal> ne peuvent contenir d'expressions arithmétiques.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-subqueries" revision="2">
+ <title>Sous-requêtes</title>
+
+ <para>
+ Pour les bases de données le supportant, Hibernate supporte les sous requêtes dans les requêtes.
+ Une sous requête doit être entre parenthèses (souvent pour un appel à une fonction d'agrégation SQL)
+ Même les sous requêtes corrélées (celles qui font référence à un alias de la requête principale) sont
+ supportées.
+ </para>
+
+ <programlisting><![CDATA[from Cat as fatcat
+where fatcat.weight > (
+ select avg(cat.weight) from DomesticCat cat
+)]]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat as cat
+where cat.name = some (
+ select name.nickName from Name as name
+)]]></programlisting>
+
+ <programlisting><![CDATA[from Cat as cat
+where not exists (
+ from Cat as mate where mate.mate = cat
+)]]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat as cat
+where cat.name not in (
+ select name.nickName from Name as name
+)]]></programlisting>
+
+ <programlisting><![CDATA[select cat.id, (select max(kit.weight) from cat.kitten kit)
+from Cat as cat]]></programlisting>
+
+ <para>
+ 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>
+
+ <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">
+ <title>Exemples HQL</title>
+
+ <para>
+ Les requêtes Hibernate peuvent être relativement puissantes et complexes. En fait, la puissance
+ du langage de requêtage est l'un des avantages principaux d'Hibernate. Voici quelques exemples
+ très similaires aux requêtes que nous avons utilisées lors d'un récent projet. Notez que la plupart
+ des requêtes que vous écrirez seront plus simples que les exemples suivantes !
+ </para>
+
+ <para>
+ La requête suivante retourne l'id de commande (order), le nombre d'articles (items) et la valeur
+ totale de la commande (order) pour toutes les commandes non payées d'un client (customer) particulier
+ pour un total minimum donné, le tout trié par la valeur totale. La requête SQL générée sur les tables
+ <literal>ORDER</literal>, <literal>ORDER_LINE</literal>, <literal>PRODUCT</literal>,
+ <literal>CATALOG</literal> et <literal>PRICE</literal> est composée de quatre jointures interne ainsi que
+ d'une sous-requête (non corrélée).
+ </para>
+
+ <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+ join order.lineItems as item
+ join item.product as product,
+ Catalog as catalog
+ join catalog.prices as price
+where order.paid = false
+ and order.customer = :customer
+ and price.product = product
+ and catalog.effectiveDate < sysdate
+ and catalog.effectiveDate >= all (
+ select cat.effectiveDate
+ from Catalog as cat
+ where cat.effectiveDate < sysdate
+ )
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+
+ <para>
+ Quel monstre !
+ En principe, nous ne sommes pas très fan des sous-requêtes, la requête ressemblait donc plutôt
+ à cela :
+ </para>
+
+ <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+ join order.lineItems as item
+ join item.product as product,
+ Catalog as catalog
+ join catalog.prices as price
+where order.paid = false
+ and order.customer = :customer
+ and price.product = product
+ and catalog = :currentCatalog
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+
+ <para>
+ La requête suivante compte le nombre de paiements (payments) pour chaque status, en excluant
+ les paiements dans le status <literal>AWAITING_APPROVAL</literal> où le changement de status
+ le plus récent à été fait par l'utilisateur courant. En SQL, cette requête effectue deux
+ jointures internes et des sous requêtes corrélées sur les tables <literal>PAYMENT</literal>,
+ <literal>PAYMENT_STATUS</literal> et <literal>PAYMENT_STATUS_CHANGE</literal>.
+ </para>
+
+ <programlisting><![CDATA[select count(payment), status.name
+from Payment as payment
+ join payment.currentStatus as status
+ join payment.statusChanges as statusChange
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+ or (
+ statusChange.timeStamp = (
+ select max(change.timeStamp)
+ from PaymentStatusChange change
+ where change.payment = payment
+ )
+ and statusChange.user <> :currentUser
+ )
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+ <para>
+ Si nous avions mappé la collection <literal>statusChanges</literal> comme une liste, au lieu d'un ensemble,
+ la requête aurait été plus facile à écrire.
+ </para>
+
+ <programlisting><![CDATA[select count(payment), status.name
+from Payment as payment
+ join payment.currentStatus as status
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+ or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+ <para>
+ La requête qui suit utilise la fonction de MS SQL <literal>isNull()</literal> pour retourner
+ tous les comptes (accounts) et paiements (payments) impayés pour l'organisation à laquelle
+ l'uilisateur (user) courant appartient. Elle est traduite en SQL par trois jointures internes,
+ une jointure externe ainsi qu'une sous requête sur les tables <literal>ACCOUNT</literal>, <literal>PAYMENT</literal>,
+ <literal>PAYMENT_STATUS</literal>, <literal>ACCOUNT_TYPE</literal>, <literal>ORGANIZATION</literal> et
+ <literal>ORG_USER</literal>.
+ </para>
+
+ <programlisting><![CDATA[select account, payment
+from Account as account
+ left outer join account.payments as payment
+where :currentUser in elements(account.holder.users)
+ and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+ <para>
+ Pour d'autres base de données, nous aurions dû faire sans la sous-requête (corrélée).
+ </para>
+
+ <programlisting><![CDATA[select account, payment
+from Account as account
+ join account.holder.users as user
+ left outer join account.payments as payment
+where :currentUser = user
+ and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-bulk" revision="2">
+ <title>Mise à jour et suppression</title>
+
+ <para>
+ HQL supporte maintenant les expressions <literal>update</literal>, <literal>delete</literal> et
+ <literal>insert ... select ...</literal>.
+ Voir <xref linkend="batch-direct"/> pour les détails.
+ </para>
+ </sect1>
+
+ <sect1 id="queryhql-tipstricks">
+ <title>Trucs & Astuces</title>
+
+ <para>
+ Vous pouvez compter le nombre de résultats d'une requête sans les retourner :
+ </para>
+
+ <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue()]]></programlisting>
+
+ <para>
+ Pour trier les résultats par la taille d'une collection, utilisez la requête suivante :
+ </para>
+
+ <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+ left join usr.messages as msg
+group by usr.id, usr.name
+order by count(msg)]]></programlisting>
+
+ <para>
+ Si votre base de données supporte les sous-requêtes, vous pouvez placer des
+ conditions sur la taille de la sélection dans la clause where de votre requête:
+ </para>
+
+ <programlisting><![CDATA[from User usr where size(usr.messages) >= 1]]></programlisting>
+
+ <para>
+ Si votre base de données ne supporte pas les sous-requêtes, utilisez la requête suivante :
+ </para>
+
+ <programlisting><![CDATA[select usr.id, usr.name
+from User usr.name
+ join usr.messages msg
+group by usr.id, usr.name
+having count(msg) >= 1]]></programlisting>
+
+ <para>
+ Cette solution ne peut pas retourner un <literal>User</literal> avec zéro message
+ à cause de la jointure interne, la forme suivante peut donc être utile :
+ </para>
+
+ <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+ left join usr.messages as msg
+group by usr.id, usr.name
+having count(msg) = 0]]></programlisting>
+
+ <para>
+ Les propriétés d'un JavaBean peuvent être injectées dans les paramètres nommés d'un requête :
+ </para>
+
+ <programlisting><![CDATA[Query q = s.createQuery("from foo Foo as foo where foo.name=:name and foo.size=:size");
+q.setProperties(fooBean); // fooBean has getName() and getSize()
+List foos = q.list();]]></programlisting>
+
+ <para>
+ Les collections sont paginables via l'utilisation de l'interface <literal>Query</literal> avec un filtre :
+ </para>
+
+ <programlisting><![CDATA[Query q = s.createFilter( collection, "" ); // the trivial filter
+q.setMaxResults(PAGE_SIZE);
+q.setFirstResult(PAGE_SIZE * pageNumber);
+List page = q.list();]]></programlisting>
+
+ <para>
+ Les éléments d'une collection peuvent être triés ou groupés en utilisant un filtre de requête :
+ </para>
+
+ <programlisting><![CDATA[Collection orderedCollection = s.filter( collection, "order by this.amount" );
+Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );]]></programlisting>
+
+ <para>
+ Vous pouvez récupérer la taille d'une collection sans l'initialiser :
+ </para>
+
+ <programlisting><![CDATA[( (Integer) session.iterate("select count(*) from ....").next() ).intValue();]]></programlisting>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/query_sql.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/query_sql.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/query_sql.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,606 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<chapter id="querysql" revision="2">
+ <title>SQL natif</title>
+
+ <para>
+ Vous pouvez aussi écrire vos requêtes dans le dialecte SQL natif de votre base de données.
+ Ceci est utile si vous souhaitez utiliser les fonctionnalités spécifiques de votre base de
+ données comme le mot clé <literal>CONNECT</literal> d'Oracle. Cette fonctionnalité offre par ailleurs un moyen
+ de migration plus propre et doux d'une application basée sur SQL/JDBC vers
+ une application Hibernate.
+ </para>
+
+ <para>Hibernate3 vous permet de spécifier du SQL écrit à la main (incluant les procédures stockées)
+ pour toutes les opérations de création, mise à jour, suppression et chargement.</para>
+
+ <sect1 id="querysql-creating" revision="3">
+ <title>Utiliser une <literal>SQLQuery</literal></title>
+
+ <para>L'exécution des requêtes en SQL natif est contrôlée par l'interface <literal>SQLQuery</literal>,
+ laquelle est obtenue en appelant <literal>Session.createSQLQuery()</literal>.
+ Dans des cas extrêmement simples, nous pouvons utiliser la forme suivante :
+ </para>
+
+ <programlisting>List cats = sess.createSQLQuery("select * from cats")
+ .addEntity(Cat.class)
+ .list();</programlisting>
+
+ <para>Cette requête a spécifié :</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>la requête SQL</para>
+ </listitem>
+
+ <listitem>
+ <para>l'entité retournée par la requête</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ 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
+ document de mapping. Cela peut être problématique pour des requêtes SQL qui joignent de multiple tables, puisque
+ les mêmes noms de colonne peuvent apparaître dans plus d'une table. La forme suivante n'est pas vulnérable à la
+ duplication des noms de colonne :
+ </para>
+
+ <programlisting>List cats = sess.createSQLQuery("select {cat.*} from cats cat")
+ .addEntity("cat", Cat.class)
+ .list();</programlisting>
+
+ <para>Cette requête a spécifié :</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>la requête SQL, avec un paramètre fictif pour Hibernate pour injecter les alias de colonne</para>
+ </listitem>
+
+ <listitem>
+ <para>l'entité retournée par la requête, et son alias de table SQL</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ La méthode <literal>addEntity()</literal> associe l'alias de la table SQL
+ avec la classe de l'entité retournée, et détermine la forme de l'ensemble des résultats de la requête.
+ </para>
+
+ <para>
+ La méthode <literal>addJoin()</literal> peut être utilisée pour charger des associations vers d'autres
+ entités et collections.
+ </para>
+
+ <programlisting>List cats = sess.createSQLQuery(
+ "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
+ )
+ .addEntity("cat", Cat.class)
+ .addJoin("kitten", "cat.kittens")
+ .list();</programlisting>
+
+ <para>
+ Une requête SQL native pourrait retourner une simple valeur scalaire ou une combinaison de scalaires et d'entités.
+ </para>
+
+ <programlisting>Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")
+ .addScalar("maxWeight", Hibernate.DOUBLE);
+ .uniqueResult();</programlisting>
+
+ <para>Vous pouvez alternativement décrire les informations de mapping des résultats dans vos fichiers hbm
+ et les utiliser pour vos requêtes.</para>
+
+ <programlisting>List cats = sess.createSQLQuery(
+ "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
+ )
+ .setResultSetMapping("catAndKitten")
+ .list();</programlisting>
+ </sect1>
+
+ <sect1 id="querysql-aliasreferences">
+ <title>Alias et références de propriété</title>
+
+ <para>
+ La notation <literal>{cat.*}</literal> utilisée au-dessus est un raccourci pour "toutes les propriétés".
+ Alternativement, vous pouvez lister explicitement les colonnes, mais même ce cas que nous laissons à Hibernate
+ 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>
+ 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}, " +
+ "cat.mateid as {cat.mate}, cat.sex as {cat.sex}, " +
+ "cat.weight*10 as {cat.weight}, cat.name as {cat.name} " +
+ "from cat_log cat where {cat.mate} = :catId"
+
+List loggedCats = sess.createSQLQuery(sql)
+ .addEntity("cat", Cat.class)
+ .setLong("catId", catId)
+ .list();</programlisting>
+
+ <para>
+ <emphasis>À noter :</emphasis> si vous listez chaque propriété explicitement, vous devez inclure
+ toutes les propriétés de la classe <emphasis>et ses sous-classes</emphasis> !
+ </para>
+
+ <para>
+ La table suivante montre les différentes possibilités d'utilisation de l'injection d'alias. À noter : les noms
+ des alias dans le résultat sont des exemples, chaque alias aura un nom unique et probablement différent lors de l'utilisation.
+ </para>
+
+ <table frame="topbot" id="aliasinjection-summary">
+ <title>Noms d'injection d'alias</title>
+
+ <tgroup cols="4">
+ <colspec colwidth="1*" />
+
+ <colspec colwidth="1*" />
+
+ <colspec colwidth="2.5*" />
+
+ <thead>
+ <row>
+ <entry>Description</entry>
+
+ <entry>Syntaxe</entry>
+
+ <entry>Exemple</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>Une simple propriété</entry>
+
+ <entry><literal>{[aliasname].[propertyname]}</literal></entry>
+
+ <entry><literal>A_NAME as {item.name}</literal></entry>
+ </row>
+
+ <row>
+ <entry>Une propriété composée</entry>
+
+ <entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
+
+ <entry><literal>CURRENCY as {item.amount.currency}, VALUE as
+ {item.amount.value}</literal></entry>
+ </row>
+
+ <row>
+ <entry>Discriminant d'une entité</entry>
+
+ <entry><literal>{[aliasname].class}</literal></entry>
+
+ <entry><literal>DISC as {item.class}</literal></entry>
+ </row>
+
+ <row>
+ <entry>Toutes les propriétés d'une entité</entry>
+
+ <entry><literal>{[aliasname].*}</literal></entry>
+
+ <entry><literal>{item.*}</literal></entry>
+ </row>
+
+ <row>
+ <entry>Une clef de collection</entry>
+
+ <entry><literal>{[aliasname].key}</literal></entry>
+
+ <entry><literal>ORGID as {coll.key}</literal></entry>
+ </row>
+
+ <row>
+ <entry>L'identifiant d'une collection</entry>
+
+ <entry><literal>{[aliasname].id}</literal></entry>
+
+ <entry><literal>EMPID as {coll.id}</literal></entry>
+ </row>
+
+ <row>
+ <entry>L'élément d'une collection</entry>
+
+ <entry><literal>{[aliasname].element}</literal></entry>
+
+ <entry><literal>XID as {coll.element}</literal></entry>
+
+ <entry></entry>
+ </row>
+
+ <row>
+ <entry>Propriété de l'élément dans la collection</entry>
+
+ <entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
+
+ <entry><literal>NAME as {coll.element.name}</literal></entry>
+ </row>
+
+ <row>
+ <entry>Toutes les propriétés de l'élément dans la collection</entry>
+
+ <entry><literal>{[aliasname].element.*}</literal></entry>
+
+ <entry><literal>{coll.element.*}</literal></entry>
+ </row>
+
+ <row>
+ <entry>Toutes les propriétés de la collection</entry>
+
+ <entry><literal>{[aliasname].*}</literal></entry>
+
+ <entry><literal>{coll.*}</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
+
+ <sect1 id="querysql-namedqueries" revision="3">
+ <title>Requêtes SQL nommées</title>
+
+ <para>
+ Les requêtes SQL nommées peuvent être définies dans le document de mapping
+ et appelées exactement de la même manière qu'un requête HQL nommée. Dans ce
+ cas, nous <emphasis>n'avons pas besoin</emphasis> d'appeler <literal>addEntity()</literal>.
+ </para>
+
+ <programlisting><sql-query name="persons">
+ <return alias="person" class="eg.Person"/>
+ SELECT person.NAME AS {person.name},
+ person.AGE AS {person.age},
+ person.SEX AS {person.sex}
+ FROM PERSON person
+ WHERE person.NAME LIKE :namePattern
+</sql-query></programlisting>
+
+ <programlisting>List people = sess.getNamedQuery("persons")
+ .setString("namePattern", namePattern)
+ .setMaxResults(50)
+ .list();</programlisting>
+
+ <para>
+ Les éléments <literal><return-join></literal> et
+ <literal><load-collection></literal> sont respectivement utilisés pour lier
+ des associations et définir des requêtes qui initialisent des collections.
+ </para>
+
+ <programlisting><sql-query name="personsWith">
+ <return alias="person" class="eg.Person"/>
+ <return-join alias="address" property="person.mailingAddress"/>
+ SELECT person.NAME AS {person.name},
+ person.AGE AS {person.age},
+ person.SEX AS {person.sex},
+ adddress.STREET AS {address.street},
+ adddress.CITY AS {address.city},
+ adddress.STATE AS {address.state},
+ adddress.ZIP AS {address.zip}
+ FROM PERSON person
+ JOIN ADDRESS adddress
+ ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+ WHERE person.NAME LIKE :namePattern
+</sql-query></programlisting>
+
+ <para>
+ Une requê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
+ <literal><return-scalar></literal> :</para>
+
+ <programlisting><sql-query name="mySqlQuery">
+ <return-scalar column="name" type="string"/>
+ <return-scalar column="age" type="long"/>
+ SELECT p.NAME AS name,
+ p.AGE AS age,
+ FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
+</sql-query></programlisting>
+
+ <para>
+ Vous pouvez externaliser les informations de mapping des résultats dans un
+ élément <literal><resultset></literal> pour soit les réutiliser
+ dans différentes requêtes nommées, soit à travers l'API
+ <literal>setResultSetMapping()</literal>.
+ </para>
+
+ <programlisting><resultset name="personAddress">
+ <return alias="person" class="eg.Person"/>
+ <return-join alias="address" property="person.mailingAddress"/>
+</resultset>
+
+<sql-query name="personsWith" resultset-ref="personAddress">
+ SELECT person.NAME AS {person.name},
+ person.AGE AS {person.age},
+ person.SEX AS {person.sex},
+ adddress.STREET AS {address.street},
+ adddress.CITY AS {address.city},
+ adddress.STATE AS {address.state},
+ adddress.ZIP AS {address.zip}
+ FROM PERSON person
+ JOIN ADDRESS adddress
+ ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+ WHERE person.NAME LIKE :namePattern
+</sql-query></programlisting>
+
+ <sect2 id="propertyresults">
+ <title>Utilisation de return-property pour spécifier explicitement les noms des colonnes/alias</title>
+
+ <para>
+ Avec <literal><return-property></literal> vous pouvez explicitement dire
+ à Hibernate quels alias de colonne utiliser, plutot que d'employer la syntaxe
+ <literal>{}</literal> pour laisser Hibernate injecter ses propres alias.
+ </para>
+
+ <programlisting><sql-query name="mySqlQuery">
+ <return alias="person" class="eg.Person">
+ <return-property name="name" column="myName"/>
+ <return-property name="age" column="myAge"/>
+ <return-property name="sex" column="mySex"/>
+ </return>
+ SELECT person.NAME AS myName,
+ person.AGE AS myAge,
+ person.SEX AS mySex,
+ FROM PERSON person WHERE person.NAME LIKE :name
+</sql-query>
+</programlisting>
+
+ <para>
+ <literal><return-property></literal> fonctionne aussi avec de
+ multiple colonnes. Cela résout une limitation de la syntaxe <literal>{}</literal>
+ qui ne peut pas permettre une bonne granularité des propriétés multi-colonnes.
+ </para>
+
+ <programlisting><sql-query name="organizationCurrentEmployments">
+ <return alias="emp" class="Employment">
+ <return-property name="salary">
+ <return-column name="VALUE"/>
+ <return-column name="CURRENCY"/>
+ </return-property>
+ <return-property name="endDate" column="myEndDate"/>
+ </return>
+ SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
+ STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+ REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
+ FROM EMPLOYMENT
+ WHERE EMPLOYER = :id AND ENDDATE IS NULL
+ ORDER BY STARTDATE ASC
+</sql-query></programlisting>
+
+ <para>
+ Notez que dans cet exemple nous avons utilisé <literal><return-property></literal>
+ en combinaison avec la syntaxe <literal>{}</literal> pour l'injection. Cela autorise les
+ utilisateurs à choisir comment ils veulent référencer les colonnes et les propriétés.
+ </para>
+
+ <para>
+ Si votre mapping a un discriminant vous devez utiliser
+ <literal><return-discriminator></literal> pour spécifier la colonne
+ discriminante.
+ </para>
+ </sect2>
+
+ <sect2 id="sp_query" revision="1">
+ <title>Utilisation de procédures stockées pour les requêtes</title>
+
+ <para>
+ Hibernate 3 introduit le support des requêtes via procédures stockées et les fonctions.
+ La documentation suivante est valable pour les deux.
+ Les procédures stockées/fonctions doivent retourner l'ensemble de résultats en tant que
+ premier paramètre sortant (NdT: "out-parameter") pour être capable de fonctionner
+ avec Hibernate. Un exemple d'une telle procédure stockée en Oracle 9 et
+ version supérieure :
+ </para>
+
+ <programlisting>CREATE OR REPLACE FUNCTION selectAllEmployments
+ RETURN SYS_REFCURSOR
+AS
+ st_cursor SYS_REFCURSOR;
+BEGIN
+ OPEN st_cursor FOR
+ SELECT EMPLOYEE, EMPLOYER,
+ STARTDATE, ENDDATE,
+ REGIONCODE, EID, VALUE, CURRENCY
+ FROM EMPLOYMENT;
+ RETURN st_cursor;
+ END;</programlisting>
+
+ <para>Pour utiliser cette requête dans Hibernate vous avez besoin de la mapper via une requête nommée.</para>
+
+ <programlisting><sql-query name="selectAllEmployees_SP" callable="true">
+ <return alias="emp" class="Employment">
+ <return-property name="employee" column="EMPLOYEE"/>
+ <return-property name="employer" column="EMPLOYER"/>
+ <return-property name="startDate" column="STARTDATE"/>
+ <return-property name="endDate" column="ENDDATE"/>
+ <return-property name="regionCode" column="REGIONCODE"/>
+ <return-property name="id" column="EID"/>
+ <return-property name="salary">
+ <return-column name="VALUE"/>
+ <return-column name="CURRENCY"/>
+ </return-property>
+ </return>
+ { ? = call selectAllEmployments() }
+</sql-query></programlisting>
+
+ <para>
+ Notez que les procédures stockées retournent, pour le moment, seulement des
+ scalaires et des entités. <literal><return-join></literal> et
+ <literal><load-collection></literal> ne sont pas supportés.
+ </para>
+
+ <sect3 id="querysql-limits-storedprocedures" revision="1">
+ <title>Règles/limitations lors de l'utilisation des procédures stockées</title>
+
+ <para>
+ Pur utiliser des procédures stockées avec Hibernate, les procédures doivent
+ suivre certaines règles. Si elles ne suivent pas ces règles, elles ne sont pas
+ utilisables avec Hibernate. Si vous voulez encore utiliser ces procédures vous
+ devez les exécuter via <literal>session.connection()</literal>. Les règles
+ sont différentes pour chaque base de données, puisque les vendeurs de base
+ de données ont des sémantiques/syntaxes différentes pour les procédures stockées.
+ </para>
+
+ <para>Les requêtes de procédures stockées ne peuvent pas être paginées avec
+ <literal>setFirstResult()/setMaxResults()</literal>.</para>
+
+ <para>Pour Oracle les règles suivantes s'appliquent :</para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ La procédure doit retourner un ensemble de résultats. Le
+ prmeier paramètre d'une procédure doit être un <literal>OUT</literal>
+ qui retourne un ensemble de résultats. Ceci est fait en
+ retournant un <literal>SYS_REFCURSOR</literal> dans Oracle 9 ou 10. Dans
+ Oracle vous avez besoin de définir un type <literal>REF CURSOR</literal>.</para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>Pour Sybase ou MS SQL server les règles suivantes s'appliquent :</para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>La procédure doit retourner un ensemble de résultats. Notez que comme
+ ces serveurs peuvent retourner de multiples ensembles de résultats et mettre à jour
+ des compteurs, Hibernate itérera les résultats et prendra le premier résultat qui est
+ un ensemble de résultat comme valeur de retour. Tout le reste sera ignoré.</para>
+ </listitem>
+
+ <listitem>
+ <para>Si vous pouvez activer <literal>SET NOCOUNT ON</literal> dans votre procédure,
+ elle sera probablement plus efficace, mais ce n'est pas une obligation.</para>
+ </listitem>
+ </itemizedlist>
+ </sect3>
+ </sect2>
+ </sect1>
+
+ <sect1 id="querysql-cud">
+ <title>SQL personnalisé pour créer, mettre à jour et effacer</title>
+
+ <para>
+ Hibernate3 peut utiliser des expression SQL personnalisées pour des opérations de création,
+ de mise à jour, et de suppression. Les objets persistants les classes et les collections
+ dans Hibernate contiennent déjà un ensemble de chaînes de caractères générées lors de la
+ configuration (insertsql, deletesql, updatesql, etc). Les tages de mapping
+ <literal><sql-insert></literal>,
+ <literal><sql-delete></literal>, et
+ <literal><sql-update></literal> surchargent ces chaînes de caractères :</para>
+
+ <programlisting><class name="Person">
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <property name="name" not-null="true"/>
+ <sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
+ <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
+ <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
+</class></programlisting>
+
+ <para>Le SQL est directement exé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
+ utilisez du SQL spécifique à votre base de données.</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">
+ <generator class="increment"/>
+ </id>
+ <property name="name" not-null="true"/>
+ <sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
+ <sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
+ <sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
+</class></programlisting>
+
+ <para>L'ordre des paramètres positionnels est actuellement vital, car ils doivent être dans la
+ même séquence qu'Hibernate les attend.</para>
+
+ <para>
+ Vous pouvez voir l'ordre attendu en activant les journaux de debug pour le
+ niveau <literal>org.hibernate.persister.entity</literal> level. Avec ce niveau activé,
+ Hibernate imprimera le SQL statique qui est utilisé pour créer, mettre à jour,
+ supprimer, etc. des entités. (Pour voir la séquence attendue, rappelez-vous de ne pas
+ inclure votre SQL personnalisé dans les fichiers de mapping de manière à surcharger le
+ SQL statique généré par Hibernate.)</para>
+
+ <para>Les procédures stockées sont dans la plupart des cas (lire : il vaut mieux le faire)
+ requises pour retourner le nombre de lignes insérées/mises à jour/supprimées, puisque
+ Hibernate fait quelques vérifications de succès lors de l'exécution de l'expression.
+ Hibernate inscrit toujours la première expression comme un paramètre de sortie numérique pour les
+ opérations CUD :</para>
+
+ <programlisting>CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
+ RETURN NUMBER IS
+BEGIN
+
+ update PERSON
+ set
+ NAME = uname,
+ where
+ ID = uid;
+
+ return SQL%ROWCOUNT;
+
+END updatePerson;</programlisting>
+ </sect1>
+
+ <sect1 id="querysql-load">
+ <title>SQL personnalisé pour le chargement</title>
+
+ <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"/>
+ SELECT NAME AS {pers.name}, ID AS {pers.id}
+ FROM PERSON
+ WHERE ID=?
+ FOR UPDATE
+</sql-query></programlisting>
+
+ <para>Ceci est juste une déclaration de requête nommée, comme vu plus tôt. Vous pouvez référencer
+ cette requête nommée dans un mapping de classe :</para>
+
+ <programlisting><class name="Person">
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <property name="name" not-null="true"/>
+ <loader query-ref="person"/>
+</class></programlisting>
+
+ <para>Ceci fonctionne même avec des procédures stockées.</para>
+
+ <para>Vous pouvez même définir une requête pour le chargement d'une collection :</para>
+
+ <programlisting><set name="employments" inverse="true">
+ <key/>
+ <one-to-many class="Employment"/>
+ <loader query-ref="employments"/>
+</set></programlisting>
+
+ <programlisting><sql-query name="employments">
+ <load-collection alias="emp" role="Person.employments"/>
+ SELECT {emp.*}
+ FROM EMPLOYMENT emp
+ WHERE EMPLOYER = :id
+ ORDER BY STARTDATE ASC, EMPLOYEE ASC
+</sql-query></programlisting>
+
+ <para>Vous pourriez même définir un chargeur d'entité qui charge une collection par jointure :</para>
+
+ <programlisting><sql-query name="person">
+ <return alias="pers" class="Person"/>
+ <return-join alias="emp" property="pers.employments"/>
+ SELECT NAME AS {pers.*}, {emp.*}
+ FROM PERSON pers
+ LEFT OUTER JOIN EMPLOYMENT emp
+ ON pers.ID = emp.PERSON_ID
+ WHERE ID=?
+</sql-query></programlisting>
+ </sect1>
+</chapter>
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/session_api.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/session_api.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/session_api.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,1229 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<chapter id="objectstate">
+ <title>Travailler avec des objets</title>
+ <para>
+ Hibernate est une solution de mapping objet/relationnel complète qui ne masque pas
+ seulement au développpeur les détails du système de gestion de base de données sous-jacent,
+ mais offre aussi <emphasis>la gestion d'état</emphasis> des objets. C'est, contrairement
+ à la gestion de <literal>statements</literal> SQL dans les couches de persistance
+ habituelles JDBC/SQL, une vue orientée objet très naturelle de la persistance dans les
+ applications Java.
+ </para>
+
+ <para>
+ En d'autres mots, les développeurs d'applications Hibernate devrait toujours
+ réfléchir à <emphasis>l'état</emphasis> de leurs objets, et pas nécessairement à
+ l'exécution des expressions SQL. Cette part est prise en charge pas Hibernate et
+ seulement importante pour les développeurs d'applications lors du réglage de la
+ performance de leur système.
+ </para>
+
+ <sect1 id="objectstate-overview">
+ <title>États des objets Hibernate</title>
+
+ <para>
+ Hibernate définit et comprend les états suivants :
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Éphémère</emphasis> (NdT : transient) - un objet est éphémère s'il a juste
+ été instancié en utilisant l'opérateur <literal>new</literal>. Il n'a aucune
+ représentation persistante dans la base de données et aucune valeur d'identifiant
+ n'a été assignée. Les instances éphémères seront détruites par le ramasse-miettes
+ si l'application n'en conserve aucune référence. Utilisez la <literal>Session</literal>
+ d'Hibernate pour rendre un objet persistant (et laisser Hibernate s'occuper des
+ expressions SQL qui ont besoin d'être exécutées pour cette transistion).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Persistant</emphasis> - une instance persistante a une représentation dans la
+ base de données et une valeur d'identifiant. Elle pourrait avoir juste été sauvegardée
+ ou chargée, pourtant, elle est par définition dans la portée d'une <literal>Session</literal>.
+ Hibernate détectera n'importe quels changements effectués sur un objet dans l'état
+ persistant et synchronisera l'état avec la base de données lors de la fin l'unité de travail.
+ Les développeurs n'exécutent pas d'expressions <literal>UPDATE</literal> ou
+ <literal>DELETE</literal> manuelles lorsqu'un objet devrait être rendu éphémère.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Détaché</emphasis> - une instance détachée est un objet qui a été persistant,
+ mais dont sa <literal>Session</literal> a été fermée. La référence à l'objet est
+ encore valide, bien sûr, et l'instance détachée pourrait même être modifiée dans cet
+ état. Une instance détachée peut être réattachée à une nouvelle <literal>Session</literal>
+ plus tard dans le temps, la rendant (et toutes les modifications avec) de nouveau persistante.
+ Cette fonctionnalité rend possible un modèle de programmation pour de longues unités de travail
+ qui requièrent un temps de réflexion de l'utilisateur. Nous les appelons des <emphasis>conversations</emphasis>,
+ c'est-à-dire une unité de travail du point de vue de l'utilisateur.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Nous alons maintenant dicuster des états et des transitions d'état (et des méthodes
+ d'Hibernate qui déclenchent une transition) plus en détails.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-makingpersistent" revision="1">
+ <title>Rendre des objets persistants</title>
+
+ <para>
+ Les instances nouvellement instanciées d'une classe persistante sont considérées
+ <emphasis>éphémères</emphasis> par Hibernate. Nous pouvons rendre une instance
+ éphémère <emphasis>persistante</emphasis> en l'associant avec une session :
+ </para>
+
+ <programlisting><![CDATA[DomesticCat fritz = new DomesticCat();
+fritz.setColor(Color.GINGER);
+fritz.setSex('M');
+fritz.setName("Fritz");
+Long generatedId = (Long) sess.save(fritz);]]></programlisting>
+
+ <para>
+ Si <literal>Cat</literal> a un identifiant généré, l'identifiant est généré et assigné
+ au <literal>cat</literal> lorsque <literal>save()</literal> est appelée. Si <literal>Cat</literal>
+ a un identifiant <literal>assigned</literal>, ou une clef composée, l'identifiant
+ devrait être assigné à l'instance de <literal>cat</literal> avant d'appeler <literal>save()</literal>.
+ 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>
+
+ <para>
+ Alternativement, vous pouvez assigner l'identifiant en utilisant une version
+ surchargée de <literal>save()</literal>.
+ </para>
+
+<programlisting><![CDATA[DomesticCat pk = new DomesticCat();
+pk.setColor(Color.TABBY);
+pk.setSex('F');
+pk.setName("PK");
+pk.setKittens( new HashSet() );
+pk.addKitten(fritz);
+sess.save( pk, new Long(1234) );]]></programlisting>
+
+ <para>
+ Si l'objet que vous rendez persistant a des objets associés (par exemple,
+ la collection <literal>kittens</literal> dans l'exemple précédent), ces objets
+ peuvent être rendus persistants dans n'importe quel ordre que vous souhaitez
+ à moins que vous ayez une contrainte <literal>NOT NULL</literal> sur la
+ colonne de la clef étrangère. Il n'y a jamais de risque de violer une
+ contrainte de clef étrangère. Cependant, vous pourriez violer une contrainte
+ <literal>NOT NULL</literal> si vous appeliez <literal>save()</literal> sur
+ les objets dans le mauvais ordre.
+ </para>
+
+ <para>
+ Habituellement, vous ne vous préoccupez pas de ce détail, puisque vous
+ utiliserez très probablement la fonctionnalité de <emphasis>persistance
+ transitive</emphasis> d'Hibernate pour sauvegarder les objets associés
+ automatiquement. Alors, même les violations de contrainte <literal>NOT NULL</literal>
+ n'ont plus lieu - Hibernate prendra soin de tout. La persistance transitive est
+ traitée plus loin dans ce chapitre.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-loading">
+ <title>Chargement d'un objet</title>
+
+ <para>
+ Les méthodes <literal>load()</literal> de <literal>Session</literal> vous donnent
+ un moyen de récupérer une instance persistante si vous connaissez déjà son identifiant.
+ <literal>load()</literal> prend un objet de classe et chargera l'état dans une instance
+ nouvellement instanciée de cette classe, dans un état persistant.
+ </para>
+
+ <programlisting><![CDATA[Cat fritz = (Cat) sess.load(Cat.class, generatedId);]]></programlisting>
+
+<programlisting><![CDATA[// vous avez besoin d'envelopper les identiants primitifs
+long pkId = 1234;
+DomesticCat pk = (DomesticCat) sess.load( Cat.class, new Long(pkId) );]]></programlisting>
+
+ <para>
+ Alternativement, vous pouvez charger un état dans une instance donnée :
+ </para>
+
+<programlisting><![CDATA[Cat cat = new DomesticCat();
+// load pk's state into cat
+sess.load( cat, new Long(pkId) );
+Set kittens = cat.getKittens();]]></programlisting>
+
+ <para>
+ Notez que <literal>load()</literal> lèvera une exception irrécupérable s'il
+ n'y a pas de ligne correspondante dans la base de données. Si la classe est mappée
+ avec un proxy, <literal>load()</literal> retourne juste un proxy non initialisé et
+ n'accède en fait pas à la base de données jusqu'à ce que vous invoquiez une
+ méthode du proxy. Ce comportement est très utile si vous souhaitez créer
+ une association vers un objet sans réellement le charger à partir de la base de
+ données. Cela permet aussi à de multiples instances d'être chargées comme un lot
+ si <literal>batch-size</literal> est défini pour le mapping de la classe.
+ </para>
+
+ <para>
+ Si vous n'êtes pas certain qu'une ligne correspondante existe, vous devriez
+ utiliser la méthode <literal>get()</literal>, laquelle accède à la base de
+ données immédiatement et retourne null s'il n'y a pas de ligne correspondante.
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id);
+if (cat==null) {
+ cat = new Cat();
+ sess.save(cat, id);
+}
+return cat;]]></programlisting>
+
+ <para>
+ Vous pouvez même charger un objet en employant un <literal>SELECT ... FOR UPDATE</literal> SQL,
+ en utilisant un <literal>LockMode</literal>. Voir la documentation de l'API pour plus d'informations.
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);]]></programlisting>
+
+ <para>
+ Notez que n'importe quelles instances associées ou collections contenues
+ <emphasis>ne sont pas</emphasis> sélectionnées par <literal>FOR UPDATE</literal>,
+ à moins que vous ne décidiez de spécifier <literal>lock</literal> ou <literal>all</literal>
+ en tant que style de cascade pour l'association.
+ </para>
+
+ <para>
+ Il est possible de re-charger un objet et toutes ses collections à n'importe quel moment,
+ en utilisant la méthode <literal>refresh()</literal>. C'est utile lorsque des "triggers" de
+ base de données sont utilisés pour initiliser certains propriétés de l'objet.
+ </para>
+
+ <programlisting><![CDATA[sess.save(cat);
+sess.flush(); //force the SQL INSERT
+sess.refresh(cat); //re-read the state (after the trigger executes)]]></programlisting>
+
+ <para>
+ Une question importante apparaît généralement à ce point : combien (NdT : de données) Hibernate
+ charge-t-il de la base de données et combient de <literal>SELECT</literal>s utilisera-t-il ?
+ Cela dépent de la <emphasis>stratégie de récupération</emphasis> et cela est expliqué dans
+ <xref linkend="performance-fetching"/>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-querying" revision="1">
+ <title>Requêtage</title>
+
+ <para>
+ Si vous ne connaissez par les identifiants des objets que vous recherchez, vous
+ avez besoin d'une requête. Hibernate supporte un langage de requêtes orientées objet
+ facile à utiliser mais puissant. Pour la création de requêtes par programmation,
+ Hibernate supporte une fonction de requêtage sophistiqué Criteria et Example (QBC et QBE).
+ Vous pouvez aussi exprimez votre requête dans le SQL natif de votre base de données,
+ avec un support optionnel d'Hibernate pour la conversion des ensembles de résultats en
+ objets.
+ </para>
+
+ <sect2 id="objectstate-querying-executing">
+ <title>Exécution de requêtes</title>
+
+ <para>
+ Les requêtes HQL et SQL natives sont représentées avec une instance de <literal>org.hibernate.Query</literal>.
+ L'interface offre des méthodes pour la liaison des paramètres, la gestion des ensembles de resultats, et pour
+ l'exécution de la requête réelle. Vous obtenez toujours une <literal>Query</literal> en utilisant la
+ <literal>Session</literal> courante :
+ </para>
+
+ <programlisting><![CDATA[List cats = session.createQuery(
+ "from Cat as cat where cat.birthdate < ?")
+ .setDate(0, date)
+ .list();
+
+List mothers = session.createQuery(
+ "select mother from Cat as cat join cat.mother as mother where cat.name = ?")
+ .setString(0, name)
+ .list();
+
+List kittens = session.createQuery(
+ "from Cat as cat where cat.mother = ?")
+ .setEntity(0, pk)
+ .list();
+
+Cat mother = (Cat) session.createQuery(
+ "select cat.mother from Cat as cat where cat = ?")
+ .setEntity(0, izi)
+ .uniqueResult();]]></programlisting>
+
+ <para>
+ Une requête est généralement exécutée en invoquant <literal>list()</literal>,
+ le résultat de la requête sera chargée complètement dans une collection en mémoire.
+ Les intances d'entités recupérées par une requête sont dans un état persistant.
+ La méthode <literal>uniqueResult()</literal> offre un raccourci si vous
+ savez que votre requête retournera seulement un seul objet.
+ </para>
+
+ <sect3 id="objectstate-querying-executing-iterate">
+ <title>Itération de résultats</title>
+
+ <para>
+ Occasionnellement, vous pourriez être capable d'obtenir de meilleures
+ performances en exécutant la requête avec la méthode <literal>iterate()</literal>.
+ Ce sera généralement seulement le cas si vous espérez que les intances réelles
+ d'entité retournées par la requête soient déjà chargées dans la session ou le
+ cache de second niveau. Si elles ne sont pas cachées, <literal>iterate()</literal>
+ sera plus lent que <literal>list()</literal> et pourrait nécessiter plusieurs
+ accès à la base de données pour une simple requête, généralement <emphasis>1</emphasis>
+ pour le select initial qui retourne seulement les identifiants, et <emphasis>n</emphasis>
+ selects supplémentaires pour initialiser les instances réelles.
+ </para>
+
+ <programlisting><![CDATA[// fetch ids
+Iterator iter = sess.createQuery("from eg.Qux q order by q.likeliness").iterate();
+while ( iter.hasNext() ) {
+ Qux qux = (Qux) iter.next(); // fetch the object
+ // something we couldnt express in the query
+ if ( qux.calculateComplicatedAlgorithm() ) {
+ // delete the current instance
+ iter.remove();
+ // dont need to process the rest
+ break;
+ }
+}]]></programlisting>
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-tuples">
+ <title>Requêtes qui retournent des tuples</title>
+
+ <para>
+ Les requêtes d'Hibernate retournent parfois des tuples d'objets, auquel cas chaque tuple
+ est retourné comme un tableau :
+ </para>
+
+ <programlisting><![CDATA[Iterator kittensAndMothers = sess.createQuery(
+ "select kitten, mother from Cat kitten join kitten.mother mother")
+ .list()
+ .iterator();
+
+while ( kittensAndMothers.hasNext() ) {
+ Object[] tuple = (Object[]) kittensAndMothers.next();
+ Cat kitten = tuple[0];
+ Cat mother = tuple[1];
+ ....
+}]]></programlisting>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-scalar" revision="1">
+ <title>Résultats scalaires</title>
+
+ <para>
+ Des requêtes peuvent spécifier une propriété d'une classe dans la clause <literal>select</literal>.
+ Elles peuvent même appeler des fonctions d'aggrégat SQL. Les propriétés ou les aggrégats sont
+ considérés comme des résultats "scalaires" (et pas des entités dans un état persistant).
+ </para>
+
+ <programlisting><![CDATA[Iterator results = sess.createQuery(
+ "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
+ "group by cat.color")
+ .list()
+ .iterator();
+
+while ( results.hasNext() ) {
+ Object[] row = (Object[]) results.next();
+ Color type = (Color) row[0];
+ Date oldest = (Date) row[1];
+ Integer count = (Integer) row[2];
+ .....
+}]]></programlisting>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-parameters">
+ <title>Lier des paramètres</title>
+
+ <para>
+ Des méthodes de <literal>Query</literal> sont fournies pour lier des
+ valeurs à des paramètres nommés ou à des paramètres de style JDBC <literal>?</literal>.
+ <emphasis>Contrairement à JDBC, les numéros des paramètres d'Hibernate commencent à zéro.</emphasis>
+ Les paramètres nommés sont des identifiants de la forme <literal>:nom</literal> dans la chaîne de
+ caractères de la requête. Les avantages des paramètres nommés sont :
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ les paramètres nommés sont insensibles à l'ordre de leur place dans la chaîne
+ de la requête
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ ils peuvent apparaître plusieurs fois dans la même requête
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ ils sont auto-documentés
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <programlisting><![CDATA[//paramètre nomme (préféré)
+Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
+q.setString("name", "Fritz");
+Iterator cats = q.iterate();]]></programlisting>
+
+ <programlisting><![CDATA[//paramètre positionnel
+Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
+q.setString(0, "Izi");
+Iterator cats = q.iterate();]]></programlisting>
+
+ <programlisting><![CDATA[//liste de paramètres nommés
+List names = new ArrayList();
+names.add("Izi");
+names.add("Fritz");
+Query q = sess.createQuery("from DomesticCat cat where cat.name in (:namesList)");
+q.setParameterList("namesList", names);
+List cats = q.list();]]></programlisting>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-pagination">
+ <title>Pagination</title>
+
+ <para>
+ Si vous avez besoin de spécifier des liens sur votre ensemble de résultats (le nombre
+ maximum de lignes que vous voulez récupérez et/ou la première ligne que vous voulez récupérer)
+ vous devriez utiliser des méthodes de l'interface <literal>Query</literal> :
+ </para>
+
+ <programlisting><![CDATA[Query q = sess.createQuery("from DomesticCat cat");
+q.setFirstResult(20);
+q.setMaxResults(10);
+List cats = q.list();]]></programlisting>
+
+ <para>
+ Hibernate sait comment traduite cette requête de limite en SQL natif pour votre SGBD.
+ </para>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-scrolling">
+ <title>Itération "scrollable"</title>
+
+ <para>
+ Si votre connecteur JDBC supporte les <literal>ResultSet</literal>s "scrollables",
+ l'interface <literal>Query</literal> peut être utilisée pour obtenir un objet
+ <literal>ScrollableResults</literal>, lequel permet une navigation flexible dans les
+ résultats de la requête.
+ </para>
+
+ <programlisting><![CDATA[Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " +
+ "order by cat.name");
+ScrollableResults cats = q.scroll();
+if ( cats.first() ) {
+
+ // trouve le premier nom sur chaque page d'une liste alphabétique de noms de chats
+ firstNamesOfPages = new ArrayList();
+ do {
+ String name = cats.getString(0);
+ firstNamesOfPages.add(name);
+ }
+ while ( cats.scroll(PAGE_SIZE) );
+
+ // Maintenant, obtiens la première page de chats
+ pageOfCats = new ArrayList();
+ cats.beforeFirst();
+ int i=0;
+ while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) );
+
+}
+cats.close()]]></programlisting>
+
+ <para>
+ Notez qu'une connexion ouverte (et un curseur) est requise pour cette fonctionnalité,
+ utilisez <literal>setMaxResult()</literal>/<literal>setFirstResult()</literal> si vous
+ avez besoin d'une fonctionnalité de pagination hors ligne.
+ </para>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-named">
+ <title>Externaliser des requêtes nommées</title>
+
+ <para>
+ Vous pouvez aussi définir des requêtes nommées dans le document de mapping.
+ (Souvenez-vous d'utiliser une section <literal>CDATA</literal> si votre requête
+ contient des caractères qui pourraient être interprétés comme des éléments XML.)
+ </para>
+
+ <programlisting><![CDATA[<query name="eg.DomesticCat.by.name.and.minimum.weight"><![CDATA[
+ from eg.DomesticCat as cat
+ where cat.name = ?
+ and cat.weight > ?
+] ]></query>]]></programlisting>
+
+ <para>
+ La liaison de paramètres et l'exécution sont fait par programmation :
+ </para>
+
+ <programlisting><![CDATA[Query q = sess.getNamedQuery("eg.DomesticCat.by.name.and.minimum.weight");
+q.setString(0, name);
+q.setInt(1, minWeight);
+List cats = q.list();]]></programlisting>
+
+ <para>
+ Notez que le code réel du programme est indépendant du langage de requête qui est
+ 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>
+
+ </sect3>
+
+ </sect2>
+
+ <sect2 id="objectstate-filtering" revision="1">
+ <title>Filtrer des collections</title>
+ <para>
+ Un <emphasis>filtre</emphasis> de collection est un type spécial de requête qui peut être
+ appliqué à une collection persistante ou à un tableau. La chaîne de requête peut se référer à
+ <literal>this</literal>, correspondant à l'élément de la collection courant.
+ </para>
+
+ <programlisting><![CDATA[Collection blackKittens = session.createFilter(
+ pk.getKittens(),
+ "where this.color = ?")
+ .setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) )
+ .list()
+);]]></programlisting>
+
+ <para>
+ La collection retournée est considérée comme un bag, et c'est une copie de la
+ collection donnée. La collection originale n'est pas modifiée (c'est contraire
+ à l'implication du nom "filtre"; mais cohérent avec le comportement attendu).
+ </para>
+
+ <para>
+ Observez que les filtres ne nécessitent pas une clause <literal>from</literal> (bien qu'ils
+ puissent en avoir une si besoin est). Les filtres ne sont pas limités à retourner des
+ éléments de la collection eux-mêmes.
+ </para>
+
+ <programlisting><![CDATA[Collection blackKittenMates = session.createFilter(
+ pk.getKittens(),
+ "select this.mate where this.color = eg.Color.BLACK.intValue")
+ .list();]]></programlisting>
+
+ <para>
+ Même une requête de filtre vide est utile, par exemple pour charger un sous-ensemble
+ d'éléments dans une énorme collection :
+ </para>
+
+ <programlisting><![CDATA[Collection tenKittens = session.createFilter(
+ mother.getKittens(), "")
+ .setFirstResult(0).setMaxResults(10)
+ .list();]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="objecstate-querying-criteria" revision="1">
+ <title>Requêtes Criteria</title>
+
+ <para>
+ HQL est extrêmement puissant mais certains développeurs préfèrent construire des
+ requêtes dynamiquement, en utilisant l'API orientée objet, plutôt que construire
+ des chaînes de requêtes. Hibernate fournit une API intuitive de requête <literal>Criteria</literal>
+ pour ces cas :
+ </para>
+
+ <programlisting><![CDATA[Criteria crit = session.createCriteria(Cat.class);
+crit.add( Expression.eq( "color", eg.Color.BLACK ) );
+crit.setMaxResults(10);
+List cats = crit.list();]]></programlisting>
+
+ <para>
+ Les APIs <literal>Criteria</literal> et <literal>Example</literal> associé sont
+ traitées plus en détail dans <xref linkend="querycriteria"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="objectstate-querying-nativesql" revision="2">
+ <title>Requêtes en SQL natif</title>
+
+ <para>
+ Vous pouvez exprimer une requête en SQL, en utilisant <literal>createSQLQuery()</literal>
+ et laisser Hibernate s'occuper du mapping des résultats vers des objets. Notez que vous
+ pouvez n'importe quand appeler <literal>session.connection()</literal> et utiliser
+ directement la <literal>Connection</literal> JDBC. Si vous choisissez d'utiliser
+ 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",
+ "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",
+ "cat",
+ Cat.class
+).list()]]></programlisting>
+
+ <para>
+ Les requêtes SQL peuvent contenir des paramètres nommés et positionnels, comme des
+ requêtes Hibernate. Plus d'informations à propos des requêtes SQL natives dans Hibernate
+ peuvent être trouvées dans <xref linkend="querysql"/>.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="objectstate-modifying" revision="1">
+ <title>Modifier des objets persistants</title>
+
+ <para>
+ Les <emphasis>instances persistantes transactionnelles</emphasis> (c'est-à-dire des objets
+ chargés, sauvegardés, créés ou requêtés par la <literal>Session</literal>) peuvent être
+ manipulées par l'application et n'importe quel changement vers l'état persistant sera
+ persisté lorsque la <literal>Session</literal> est <emphasis>"flushée"</emphasis> (traité
+ plus tard dans ce chapitre). Il n'y a pas besoin d'appeler une méthode particulière
+ (comme <literal>update()</literal>, qui a un but différent) pour rendre vos modifications
+ persistantes. Donc la manière la plus directe de mettre à jour l'état d'un objet est de
+ le charger avec <literal>load()</literal>, et puis le manipuler directement, tant que la
+ <literal>Session</literal> est ouverte :
+ </para>
+
+ <programlisting><![CDATA[DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );
+cat.setName("PK");
+sess.flush(); // changes to cat are automatically detected and persisted]]></programlisting>
+
+ <para>
+ Parfois ce modèle de programmation est inefficace puisqu'il nécessiterait un
+ <literal>SELECT</literal> SQL (pour charger l'objet) et un <literal>UPDATE</literal>
+ SQL (pour persister son état mis à jour) dans la même session. Aussi Hibernate offre
+ une autre approche, en utilisant des instances détachées.
+ </para>
+
+ <para>
+ <emphasis>Notez que Hibernate n'offre par sa propre API pour l'exécution directe
+ d'expressions <literal>UPDATE</literal> ou <literal>DELETE</literal>. Hibernate
+ est un service de <emphasis>gestion d'état</emphasis>, vous n'avez pas à penser
+ aux <emphasis>expressions</emphasis> pour l'utiliser. JDBC est une API parfaite
+ pour exécuter des expressions SQL, vous pouvez obtenir une <literal>Connection</literal>
+ JDBC n'importe quand en appelant <literal>session.connection()</literal>. En outre,
+ la notion d'opérations de masse entre en conflit avec le mapping objet/relationnel
+ pour les applications orientées processus de transactions en ligne. Les futures
+ versions d'Hibernate peuvent cependant fournir des fonctions d'opération de masse.
+ Voir <xref linkend="batch"/> pour les astuces possibles d'opérations groupées.</emphasis>
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-detached" revision="2">
+ <title>Modifier des objets détachés</title>
+
+ <para>
+ Beaucoup d'applications ont besoin de récupérer un objet dans une transaction,
+ l'envoyer à la couche interfacée avec l'utilisateur pour les manipulations, puis
+ sauvegarder les changements dans une nouvelle transaction. Les applications
+ qui utilisent cette approche dans un environnement à haute concurrence utilisent
+ généralement des données versionnées pour assurer l'isolation pour les "longues"
+ unités de travail.
+ </para>
+
+ <para>
+ Hibernate supporte ce modèle en permettant pour le réattachement d'instances détachées
+ l'utilisation des méthodes <literal>Session.update()</literal> ou <literal>Session.merge()</literal> :
+ </para>
+
+ <programlisting><![CDATA[// dans la première session
+Cat cat = (Cat) firstSession.load(Cat.class, catId);
+Cat potentialMate = new Cat();
+firstSession.save(potentialMate);
+
+// dans une couche plus haute de l'application
+cat.setMate(potentialMate);
+
+// plus tard, dans une nouvelle session
+secondSession.update(cat); // update cat
+secondSession.update(mate); // update mate]]></programlisting>
+
+ <para>
+ Si le <literal>Cat</literal> avec l'identifiant <literal>catId</literal> avait déjà
+ été chargé par <literal>secondSession</literal> lorsque l'application a essayé de le
+ réattacher, une exception aurait été levée.
+ </para>
+
+ <para>
+ Utilisez <literal>update()</literal> si vous êtes sure que la session ne contient pas
+ déjà une instance persistante avec le même identifiant, et <literal>merge()</literal>
+ si vous voulez fusionner vos modifications n'importe quand sans considérer l'état de
+ la session. En d'autres mots, <literal>update()</literal> est généralement la première méthode
+ que vous devriez appeler dans une session fraîche, pour s'assurer que le réattachement
+ de vos instances détachées est la première opération qui est exécutée.
+ </para>
+
+ <para>
+ L'application devrait individuellement <literal>update()</literal> (NdT : mettre à jour)
+ les instances détachées accessibles depuis l'instance détachée donnée si et
+ <emphasis>seulement</emphasis> si elle veut que leur état soit aussi mis à jour. Ceci
+ peut être automatisé bien sûr, en utilisant la <emphasis>persistance transitive</emphasis>,
+ voir <xref linkend="objectstate-transitive"/>.
+ </para>
+
+ <para>
+ La méthode <literal>lock()</literal> permet aussi à une application de réassocier un
+ objet avec une nouvelle session. Pourtant, l'instance détachée doit être non modifiée !
+ </para>
+
+ <programlisting><![CDATA[//réassocie :
+sess.lock(fritz, LockMode.NONE);
+//fait une vérification de version, puis réassocie :
+sess.lock(izi, LockMode.READ);
+//fait une vérification de version, en utilisant SELECT ... FOR UPDATE, puis réassocie :
+sess.lock(pk, LockMode.UPGRADE);]]></programlisting>
+
+ <para>
+ Notez que <literal>lock()</literal> peut être utilisé avec différents
+ <literal>LockMode</literal>s, voir la documentation de l'API documentation et le chapitre
+ sur la gestion des transactions pour plus d'informations. Le réattachement n'est pas le seul
+ cas d'utilisation pour <literal>lock()</literal>.
+ </para>
+
+ <para>
+ D'autres modèles pour de longues unités de travail sont traités dans <xref linkend="transactions-optimistic"/>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-saveorupdate">
+ <title>Détection automatique d'un état</title>
+
+ <para>
+ Les utilisateurs d'Hibernate ont demandé une méthode dont l'intention générale
+ serait soit de sauvegarder une instance éphémère en générant un nouvel identifiant,
+ soit mettre à jour/réattacher les instances détachées associées à l'identifiant courant.
+ La méthode <literal>saveOrUpdate()</literal> implémente cette fonctionnalité.
+ </para>
+
+ <programlisting><![CDATA[// dans la première session
+Cat cat = (Cat) firstSession.load(Cat.class, catID);
+
+// dans une partie plus haute de l'application
+Cat mate = new Cat();
+cat.setMate(mate);
+
+// plus tard, dans une nouvelle session
+secondSession.saveOrUpdate(cat); // met à jour un état existant (cat a un identifiant non-null)
+secondSession.saveOrUpdate(mate); // sauvegarde les nouvelles instances (mate a un identiant null)]]></programlisting>
+
+ <para>
+ L'usage et la sémantique de <literal>saveOrUpdate()</literal> semble être confuse pour les
+ nouveaux utilisateurs. Premièrement, aussi longtemps que vous n'essayez pas d'utiliser des
+ instances d'une session dans une autre, vous ne devriez pas avoir besoin d'utiliser <literal>update()</literal>,
+ <literal>saveOrUpdate()</literal>, ou <literal>merge()</literal>. Certaines applications
+ n'utiliseront jamais ces méthodes.
+ </para>
+
+ <para>
+ Généralement <literal>update()</literal> ou <literal>saveOrUpdate()</literal> sont utilisées dans
+ le scénario suivant :
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ l'application charge un objet dans la première session
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ l'objet est passé à la couche utilisateur
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ certaines modifications sont effectuées sur l'objet
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ l'objet est retourné à la couche logique métier
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ l'application persiste ces modifications en appelant
+ <literal>update()</literal> dans une seconde sessin
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ <literal>saveOrUpdate()</literal> s'utilise dans le cas suivant :
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ si l'objet est déjà persistant dans cette session, ne rien faire
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ si un autre objet associé à la session a le même identifiant, lever une exception
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ si l'objet n'a pas de propriété d'identifiant, appeler <literal>save()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ si l'identifiant de l'objet a une valeur assignée à un objet nouvellement instancié,
+ appeler <literal>save()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ si l'objet est versionné (par <literal><version></literal> ou
+ <literal><timestamp></literal>), et la valeur de la propriété de version
+ est la même valeur que celle assignée à un objet nouvellement instancié, appeler
+ <literal>save()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ sinon mettre à jour l'objet avec <literal>update()</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ et <literal>merge()</literal> est très différent :
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ s'il y a une instance persistante avec le même identifiant couramment
+ associée à la session, copier l'état de l'objet donné dans l'instance persistante
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ s'il n'y a pas d'instance persistante associée à cette session, essayer de le charger
+ à partir de la base de données, ou créer une nouvelle instance persistante
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ l'instance persistante est retournée
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ l'instance donnée ne devient pas associée à la session, elle reste détachée
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect1>
+
+ <sect1 id="objectstate-deleting" revision="1">
+ <title>Suppression d'objets persistants</title>
+
+ <para>
+ <literal>Session.delete()</literal> supprimera l'état d'un objet de la base de données.
+ Bien sûr, votre application pourrait encore conserver une référence vers un objet effacé.
+ Il est mieux de penser à <literal>delete()</literal> comme rendant une instance persistante
+ éphémère.
+ </para>
+
+ <programlisting><![CDATA[sess.delete(cat);]]></programlisting>
+
+ <para>
+ Vous pouvez effacer des objets dans l'ordre que vous voulez, sans risque de violations
+ de contrainte de clef étrangère. Il est encore possible de violer une contrainte <literal>NOT
+ NULL</literal> sur une colonne de clef étrangère en effaçant des objets dans le
+ mauvais ordre, par exemple si vous effacer le parent, mais oubliez d'effacer les enfants.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-replicating" revision="1">
+ <title>Réplication d'objets entre deux entrepôts de données</title>
+
+ <para>
+ Il est occasionnellement utile de pouvoir prendre un graphe d'instances persistantes
+ et de les rendre persistantes dans un entrepôt différent, sans regénérer les valeurs
+ des identifiants.
+ </para>
+
+ <programlisting><![CDATA[//récupère un cat de la base de données
+Session session1 = factory1.openSession();
+Transaction tx1 = session1.beginTransaction();
+Cat cat = session1.get(Cat.class, catId);
+tx1.commit();
+session1.close();
+
+// réconcilie la seconde base de données
+Session session2 = factory2.openSession();
+Transaction tx2 = session2.beginTransaction();
+session2.replicate(cat, ReplicationMode.LATEST_VERSION);
+tx2.commit();
+session2.close();]]></programlisting>
+
+ <para>
+ Le <literal>ReplicationMode</literal> détermine comment <literal>replicate()</literal>
+ traitera les conflits avec les lignes existantes dans la base de données.
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>ReplicationMode.IGNORE</literal> - ignore l'objet s'il y a une ligne
+ existante dans la base de données avec le même identifiant
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ReplicationMode.OVERWRITE</literal> - écrase n'importe quelle ligne existante
+ dans la base de données avec le même identifiant
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ReplicationMode.EXCEPTION</literal> - lève une exception s'il y une ligne dans
+ la base de données avec le même identifiant
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ReplicationMode.LATEST_VERSION</literal> - écrase la ligne si son numéro de version
+ est plus petit que le numéro de version de l'objet, ou ignore l'objet sinon
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Les cas d'utilisation de cette fonctionnalité incluent la réconciliation de données
+ entrées dans différentes base de données, l'extension des informations de configuration
+ du système durant une mise à jour du produit, retour en arrière sur les changements effectués
+ durant des transactions non-ACID, et plus.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-flushing">
+ <title>Flush de la session</title>
+
+ <para>
+ De temps en temps la <literal>Session</literal> exécutera les expressions SQL
+ requises pour syncrhoniser l'état de la connexion JDBC avec l'état des objets
+ retenus en mémoire. Ce processus, <emphasis>flush</emphasis>, arrive par défaut aux
+ points suivants :
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ lors de certaines exécutions de requête
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ lors d'un appel à <literal>org.hibernate.Transaction.commit()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ lors d'un appel à <literal>Session.flush()</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Les expressions SQL sont effectuées dans l'ordre suivant :
+ </para>
+
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ insertion des entités, dans le même ordre que celui des
+ objets correspondants sauvegardés par l'appel à <literal>Session.save()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ mise à jours des entités
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ suppression des collections
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ suppression, mise à jour et insertion des éléments des collections
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ insertion des collections
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ suppression des entités, dans le même ordre que celui des objets
+ correspondants qui ont été supprimés par l'appel à <literal>Session.delete()</literal>
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ (Une exception est que des objets utilisant la génération <literal>native</literal>
+ d'identifiants sont insérés lorsqu'ils sont sauvegardés.)
+ </para>
+
+ <para>
+ Excepté lorsque vous appelez <literal>flush()</literal> explicitement, il n'y
+ absolument aucune garantie à propos de <emphasis>quand</emphasis> la <literal>Session</literal>
+ exécute les appels JDBC, seulement sur l'<emphasis>ordre</emphasis> dans lequel ils sont
+ exécutés. Cependant, Hibernate garantit que <literal>Query.list(..)</literal> ne
+ retournera jamais de données périmées, ni des données fausses.
+ </para>
+
+ <para>
+ Il est possible de changer le comportement par défaut, donc que le flush se produise
+ moins fréquemment. La classe <literal>FlushMode</literal> définit trois modes différents :
+ flush seulement lors du commit (et seulement quand l'API <literal>Transaction</literal>
+ d'Hibernate est utilisée), flush automatiquement en utilisant la procédure expliquée, ou
+ jamais de flush à moins que <literal>flush()</literal> soit appelée explicitement.
+ Le dernier mode est utile pour l'exécution de longues unités de travail, où une
+ <literal>Session</literal> est gardée ouverte et déconnectée pour un long moment
+ (voir <xref linkend="transactions-optimistic-longsession"/>).
+ </para>
+
+ <programlisting><![CDATA[sess = sf.openSession();
+Transaction tx = sess.beginTransaction();
+sess.setFlushMode(FlushMode.COMMIT); // permet aux requêtes de retourner un état périmé
+
+Cat izi = (Cat) sess.load(Cat.class, id);
+izi.setName(iznizi);
+
+// pourrait retourner des données périmées
+sess.find("from Cat as cat left outer join cat.kittens kitten");
+
+// le changement pour izi n'est pas flushé !
+...
+tx.commit(); // le flush se produit]]></programlisting>
+
+ <para>
+ Durant le flush, une exception peut se produire (par exemple, si une opération de la
+ DML viole une contrainte). Puisque les exceptions de gestion impliquent une certaine
+ compréhension du comportement transactionnel d'Hibernate, nous le traitons dans
+ <xref linkend="transactions"/>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-transitive" revision="1">
+ <title>Persistance transitive</title>
+
+ <para>
+ Il est assez pénible de sauvegarder, supprimer, ou réattacher des objets
+ un par un, surtout si vous traitez un graphe d'objets associés. Un cas habituel
+ est une relation parent/enfant. Considérez l'exemple suivant :
+ </para>
+
+ <para>
+ Si les enfants de la relation parent/enfant étaient des types de valeur (par exemple,
+ une collection d'adresses ou de chaînes de caractères), leur cycle de vie dépendraient
+ du parent et aucune action ne serait requise pour "cascader" facilement les
+ changements d'état. Si le parent est sauvegardé, les objets enfants de type de valeur sont
+ sauvegardés également, si le parent est supprimé, les enfants sont supprimés, etc. Ceci
+ fonctionne même pour des opérations telles que la suppression d'un enfant de la collection ;
+ Hibernate détectera cela et, puisque les objets de type de valeur ne peuvent pas avoir
+ des références partagées, supprimera l'enfant de la base de données.
+ </para>
+
+ <para>
+ Maintenant considérez le même scénario avec un parent et dont les objets enfants
+ sont des entités, et non des types de valeur (par exemple, des catégories et des
+ objets, ou un parent et des chatons). Les entités ont leur propre cycle de vie,
+ supportent les références partagées (donc supprimer une entité de la collection
+ ne signifie pas qu'elle peut être supprimée), et il n'y a par défaut pas de
+ cascade d'état d'une entité vers n'importe quelle entité associée. Hibernate
+ n'implémente pas la <emphasis>persistance par accessibilité</emphasis> par défaut.
+ </para>
+
+ <para>
+ Pour chaque opération basique de la session d'Hibernate - incluant <literal>persist(), merge(),
+ saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate()</literal> - il y a un
+ style de cascade correspondant. Respectivement, les styles de cascade s'appellent <literal>persist,
+ merge, save-update, delete, lock, refresh, evict, replicate</literal>. Si vous voulez qu'une
+ opération soit cascadée le long d'une association, vous devez l'indiquer dans le document de
+ mapping. Par exemple :
+ </para>
+
+ <programlisting><![CDATA[<one-to-one name="person" cascade="persist"/>]]></programlisting>
+
+ <para>
+ Les styles de cascade peuvent être combinés :
+ </para>
+
+ <programlisting><![CDATA[<one-to-one name="person" cascade="persist,delete,lock"/>]]></programlisting>
+
+ <para>
+ Vous pouvez même utiliser <literal>cascade="all"</literal> pour spécifier que <emphasis>toutes</emphasis>
+ les opérations devraient être cascadées le long de l'association. La valeur par défaut
+ <literal>cascade="none"</literal> spécifie qu'aucune opération ne sera cascadée.
+ </para>
+
+ <para>
+ Une style de cascade spécial, <literal>delete-orphan</literal>, s'applique seulement
+ aux associations un-vers-plusieurs, et indique que l'opération <literal>delete()</literal>
+ devrait être appliquée à n'importe quel enfant qui est supprimé de l'association.
+ </para>
+
+
+ <para>
+ Recommandations :
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Cela n'a généralement aucun sens d'activer la cascade sur une association
+ <literal><many-to-one></literal> ou <literal><many-to-many></literal>. Les
+ cascades sont souvent utiles pour des associations
+ <literal><one-to-one></literal> et <literal><one-to-many></literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si la durée de vie de l'objet enfant est liée à la durée de vie de l'objet parent,
+ faites en un <emphasis>objet du cycle de vie</emphasis> en spécifiant
+ <literal>cascade="all,delete-orphan"</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Sinon, vous pourriez ne pas avoir besoin de cascade du tout. Mais si vous pensez que vous
+ travaillerez souvent avec le parent et les enfants ensemble dans la même transaction, et
+ que vous voulez vous éviter quelques frappes, considérez l'utilisation de
+ <literal>cascade="persist,merge,save-update"</literal>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Mapper une association (soit une simple association valuée, soit une collection) avec
+ <literal>cascade="all"</literal> marque l'association comme une relation de style
+ <emphasis>parent/enfant</emphasis> où la sauvegarde/mise à jour/suppression du parent
+ entraîne la sauvegarde/mise à jour/suppression de l'enfant ou des enfants.
+ </para>
+ <para>
+ En outre, une simple référence à un enfant d'un parent persistant aura pour conséquence
+ la sauvegarde/mise à jour de l'enfant. Cette métaphore est cependant incomplète. Un enfant
+ qui devient non référencé par son parent <emphasis>n'est pas</emphasis> automatiquement
+ supprimée, excepté dans le cas d'une association <literal><one-to-many></literal>
+ mappée avec <literal>cascade="delete-orphan"</literal>. La sémantique précise des opérations
+ de cascade pour une relation parent/enfant est la suivante :
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Si un parent est passé à <literal>persist()</literal>, tous les enfant sont passés à
+ <literal>persist()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si un parent est passé à <literal>merge()</literal>, tous les enfants sont passés à
+ <literal>merge()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si un parent est passé à <literal>save()</literal>, <literal>update()</literal> ou
+ <literal>saveOrUpdate()</literal>, tous les enfants sont passés à <literal>saveOrUpdate()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si un enfant détaché ou éphémère devient référencé par un parent persistant,
+ il est passé à <literal>saveOrUpdate()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si un parent est supprimé, tous les enfants sont passés à <literal>delete()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si un enfant est déréférencé par un parent persistant, <emphasis>rien de spécial
+ n'arrive</emphasis> - l'application devrait explicitement supprimer l'enfant si nécessaire -
+ à moins que <literal>cascade="delete-orphan"</literal> soit paramétré,
+ au quel cas l'enfant "orphelin" est supprimé.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Enfin, la cascade des opérations peut être effectuée sur un graphe donné lors
+ de l'<emphasis>appel de l'opération</emphasis> or lors du <emphasis>flush</emphasis>
+ suivant. Toutes les opérations, lorsque cascadées, le sont sur toutes les entités
+ associées atteignables lorsque l'opétation est exécutée. Cependant
+ <literal>save-upate</literal> et <literal>delete-orphan</literal> sont cascadées
+ à toutes les entités associées atteignables lors du flush de la
+ <literal>Session</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-metadata">
+ <title>Utilisation des méta-données</title>
+
+ <para>
+ Hibernate requiert un modèle de méta-niveau très riche de toutes les entités et types valués.
+ De temps en temps, ce modèle est très utile à l'application elle même. Par exemple,
+ l'application pourrait utiliser les méta-données d'Hibernate pour implémenter un algorithme
+ de copie en profondeur "intelligent" qui comprendrait quels objets devraient copiés
+ (par exemple les types de valeur mutables) et lesquels ne devraient pas l'être (par exemple
+ les types de valeurs immutables et, possiblement, les entités associées).
+ </para>
+ <para>
+ Hibernate expose les méta-données via les interfaces <literal>ClassMetadata</literal>
+ et <literal>CollectionMetadata</literal> et la hiérarchie <literal>Type</literal>.
+ Les instances des interfaces de méta-données peuvent être obtenues à partir de la
+ <literal>SessionFactory</literal>.
+ </para>
+
+ <programlisting><![CDATA[Cat fritz = ......;
+ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class);
+
+Object[] propertyValues = catMeta.getPropertyValues(fritz);
+String[] propertyNames = catMeta.getPropertyNames();
+Type[] propertyTypes = catMeta.getPropertyTypes();
+
+// récupère une Map de toutes les propriétés qui ne sont pas des collections ou des associations
+Map namedValues = new HashMap();
+for ( int i=0; i<propertyNames.length; i++ ) {
+ if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType() ) {
+ namedValues.put( propertyNames[i], propertyValues[i] );
+ }
+}]]></programlisting>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/toolset_guide.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/toolset_guide.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/toolset_guide.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,594 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="toolsetguide" revision="2">
+ <title>Guide des outils</title>
+
+ <para>
+ Des outils en ligne de commande, des plugins Eclipse ainsu que des tâches Ant permettent de gérer de cycles de développement complet
+ de projets utilisant Hibernate.
+ </para>
+
+ <para>
+ Les <emphasis>outils Hibernate</emphasis> actuels incluent des plugins pour l'IDE Eclipse ainsi que des tâches Ant pour l'ingénierie
+ inverse de bases de données existantes :
+ </para>
+
+ <itemizedlist>
+ <listitem><para>
+ <emphasis>Mapping Editor :</emphasis> un éditeur pour les fichiers de mapping XML Hibernate, supportant l'auto-complétion et la mise en valeur de la syntaxe.
+ Il supporte aussi l'auto-complétion automatique pour les noms de classes et les noms de propriété/champ,
+ le rendant beaucoup plus polyvalent qu'un éditeurXML normal.
+ </para></listitem>
+ <listitem><para>
+ <emphasis>Console :</emphasis> la console est une nouvelle vue d'Eclipse. En plus de la vue d'ensemble
+ arborescente de vos configurations de console, vous obtenez aussi une vue interactive de vos classes persistantes et de leurs relations.
+ La console vous permet d'exécuter des requête HQL dans votre base de données et de parcourir les résultats directement dans Eclipse.
+ </para></listitem>
+ <listitem><para>
+ <emphasis>Development Wizards :</emphasis> plusieurs assistants sont fournis avec les outils d'Hibernate
+ pour Eclipse ; vous pouvez utiliser un assistant pour générer rapidement les fichiers de configuration d'Hibernate (cfg.xml),
+ ou vous pouvez même complètement générer les fichiers de mapping Hibernate et les sources des POJOs à partir d'un schéma de base de données existant.
+ L'assistant d'ingénierie inverse supporte les modèles utilisateur.
+ </para></listitem>
+ <listitem><para>
+ <emphasis>Tâches Ant :</emphasis>
+ </para></listitem>
+
+ </itemizedlist>
+
+ <para>
+ Veuillez-vous référer au paquet <emphasis>outils Hibernate</emphasis> et sa documentation pour plus d'informations.
+ </para>
+
+ <para>
+ Pourtant, le paquet principal d'Hibernate arrive avec un lot d'outils intégrés (il peut même être utilisé de "l'intérieur" d'Hibernate à la volée) :
+ <emphasis>SchemaExport</emphasis> aussi connu comme
+ <literal>hbm2ddl</literal>.
+ </para>
+
+ <sect1 id="toolsetguide-s1" revision="2">
+ <title>Génération automatique du schéma</title>
+
+ <para>
+ La DDL peut être générée à partir de vos fichiers de mapping par un utilitaire d'Hibernate. Le schéma généré
+ inclut les contraintes d'intégrité référentielle (clefs primaires et étrangères) pour les tables d'entités
+ et de collections. Les tables et les séquences sont aussi créées pour les générateurs d'identifiant mappés.
+ </para>
+
+ <para>
+ Vous <emphasis>devez</emphasis> spécifier un <literal>Dialect</literal> SQL via la propriété
+ <literal>hibernate.dialect</literal> lors de l'utilisation de cet outils, puisque la DDL est
+ fortement dépendante de la base de données.
+ </para>
+
+ <para>
+ D'abord, personnalisez vos fichiers de mapping pour améliorer le schéma généré.
+ </para>
+
+ <sect2 id="toolsetguide-s1-2" revision="3">
+ <title>Personnaliser le schéma</title>
+
+ <para>
+ Plusieurs éléments du mapping hibernate définissent des attributs optionnels
+ nommés <literal>length</literal>, <literal>precision</literal> et <literal>scale</literal>.
+ Vous pouvez paramétrer la longueur, la précision,... d'une colonne avec ces attributs.
+ </para>
+
+ <programlisting><![CDATA[<property name="zip" length="5"/>]]></programlisting>
+ <programlisting><![CDATA[<property name="balance" precision="12" scale="2"/>]]></programlisting>
+
+ <para>
+ Certains éléments acceptent aussi un attribut <literal>not-null</literal>
+ (utilisé pour générer les contraintes de colonnes <literal>NOT NULL</literal>) et
+ un attribut <literal>unique</literal> (pour générer une contrainte de colonne
+ <literal>UNIQUE</literal>).
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="bar" column="barId" not-null="true"/>]]></programlisting>
+ <programlisting><![CDATA[<element column="serialNumber" type="long" not-null="true" unique="true"/>]]></programlisting>
+
+ <para>
+ Un attribut <literal>unique-key</literal> peut être utilisé pour grouper les colonnes
+ en une seule contrainte d'unicité. Actuellement, la valeur spécifiée par
+ l'attribut <literal>unique-key</literal> n'est <emphasis>pas</emphasis> utilisée pour
+ nommer la contrainte dans le DDL généré, elle sert juste à grouper les colonnes
+ dans le fichier de mapping.
+ </para>
+ <programlisting><![CDATA[<many-to-one name="org" column="orgId" unique-key="OrgEmployeeId"/>
+ <property name="employeeId" unique-key="OrgEmployee"/>]]></programlisting>
+
+ <para>
+ Un attribut <literal>index</literal> indique le nom d'un index qui sera
+ créé en utilisant la ou les colonnes mappées. Plusieurs colonnes
+ peuvent être groupées dans un même index, en spécifiant le même
+ nom d'index.
+ </para>
+
+ <programlisting><![CDATA[<property name="lastName" index="CustName"/>
+<property name="firstName" index="CustName"/>]]></programlisting>
+
+ <para>
+ Un attribut <literal>foreign-key</literal> peut être utilisé pour surcharger le nom
+ des clés étrangères générées.
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="bar" column="barId" foreign-key="FKFooBar"/>]]></programlisting>
+
+ <para>
+ Plusieurs éléments de mapping acceptent aussi un élément fils <literal><column></literal>.
+ Ceci est utile pour les type multi-colonnes:
+ </para>
+
+ <programlisting><![CDATA[<property name="name" type="my.customtypes.Name"/>
+ <column name="last" not-null="true" index="bar_idx" length="30"/>
+ <column name="first" not-null="true" index="bar_idx" length="20"/>
+ <column name="initial"/>
+</property>]]></programlisting>
+
+ <para>
+ L'attribut <literal>default</literal> vous laisse spécifier une valeur par défaut pour
+ une colonnes (vous devriez assigner la même valeur à la propriété mappée avant de sauvegarder une nouvelle instance
+ de la classe mappée).
+ </para>
+
+ <programlisting><![CDATA[<property name="credits" type="integer" insert="false">
+ <column name="credits" default="10"/>
+</property>]]></programlisting>
+
+ <programlisting><![CDATA[<version name="version" type="integer" insert="false">
+ <column name="version" default="0"/>
+</property>]]></programlisting>
+
+ <para>
+ L'attribut <literal>sql-type</literal> laisse l'utilisateur surcharger le mapping
+ par défaut du type Hibernate vers un type SQL.
+ </para>
+
+ <programlisting><![CDATA[<property name="balance" type="float">
+ <column name="balance" sql-type="decimal(13,3)"/>
+</property>]]></programlisting>
+
+
+ <para>
+ L'attribut <literal>check</literal> permet de spécifier une contrainte de vérification.
+ </para>
+
+ <programlisting><![CDATA[<property name="foo" type="integer">
+ <column name="foo" check="foo > 10"/>
+</property>]]></programlisting>
+
+ <programlisting><![CDATA[<class name="Foo" table="foos" check="bar < 100.0">
+ ...
+ <property name="bar" type="float"/>
+</class>]]></programlisting>
+
+
+ <table frame="topbot" id="schemattributes-summary" revision="2">
+ <title>Summary</title>
+ <tgroup cols="3">
+ <colspec colwidth="1*"/>
+ <colspec colwidth="1*"/>
+ <colspec colwidth="2.5*"/>
+ <thead>
+ <row>
+ <entry>Attribut</entry>
+ <entry>Valeur</entry>
+ <entry>Interprétation</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>length</literal></entry>
+ <entry>numérique</entry>
+ <entry>taille d'une colonne</entry>
+ </row>
+ <row>
+ <entry><literal>precision</literal></entry>
+ <entry>numérique</entry>
+ <entry>précision décimale de la colonne</entry>
+ </row>
+ <row>
+ <entry><literal>scale</literal></entry>
+ <entry>numérique</entry>
+ <entry>scale décimale de la colonne</entry>
+ </row>
+ <row>
+ <entry><literal>not-null</literal></entry>
+ <entry><literal>true|false</literal></entry>
+ <entry>spécifie que la colonne doit être non-nulle</entry>
+ </row>
+ <row>
+ <entry><literal>unique</literal></entry>
+ <entry><literal>true|false</literal></entry>
+ <entry>spécifie que la colonne doit avoir une contrainte d'unicité</entry>
+ </row>
+ <row>
+ <entry><literal>index</literal></entry>
+ <entry><literal>index_name</literal></entry>
+ <entry>spécifie le nom d'un index (multi-colonnes)</entry>
+ </row>
+ <row>
+ <entry><literal>unique-key</literal></entry>
+ <entry><literal>unique_key_name</literal></entry>
+ <entry>spécifie le nom d'une contrainte d'unicité multi-colonnes</entry>
+ </row>
+ <row>
+ <entry><literal>foreign-key</literal></entry>
+ <entry><literal>foreign_key_name</literal></entry>
+ <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
+ <one-to-one>, <many-to-one>, <key>, et <many-to-many>
+ Notez que les extrêmités <literal>inverse="true"</literal>
+ se seront pas prises en compte par <literal>SchemaExport</literal>.
+ </entry>
+ </row>
+ <row>
+ <entry><literal>sql-type</literal></entry>
+ <entry><literal>SQL column_type</literal></entry>
+ <entry>
+ surcharge le type par défaut (attribut de
+ l'élément <literal><column></literal> uniquement)
+ </entry>
+ </row>
+ <row>
+ <entry><literal>default</literal></entry>
+ <entry>expression SQL</entry>
+ <entry>
+ spécifie une valeur par défaut pour la colonne
+ </entry>
+ </row>
+ <row>
+ <entry><literal>check</literal></entry>
+ <entry>SQL expression</entry>
+ <entry>
+ crée une contrainte de vérification sur la table ou la colonne
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ L'élément <literal><comment></literal> vous permet de spécifier un commentaire pour le schéma généré.
+ </para>
+
+ <programlisting><![CDATA[<class name="Customer" table="CurCust">
+ <comment>Current customers only</comment>
+ ...
+</class>]]></programlisting>
+
+ <programlisting><![CDATA[<property name="balance">
+ <column name="bal">
+ <comment>Balance in USD</comment>
+ </column>
+</property>]]></programlisting>
+
+ <para>
+ Ceci a pour résultat une expression
+ <literal>comment on table</literal> ou
+ <literal>comment on column</literal> dans la DDL générée (où supportée).
+ </para>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-3" revision="2">
+ <title>Exécuter l'outil</title>
+
+ <para>
+ L'outil <literal>SchemaExport</literal> génère un script DDL vers
+ la sortie standard et/ou exécute les ordres DDL.
+ </para>
+
+ <para>
+ <literal>java -cp </literal><emphasis>classpath_hibernate</emphasis>
+ <literal>net.sf.hibernate.tool.hbm2ddl.SchemaExport</literal> <emphasis>options fichiers_de_mapping</emphasis>
+ </para>
+
+ <table frame="topbot">
+ <title><literal>SchemaExport</literal> Options de la ligne de commande</title>
+ <tgroup cols="2">
+ <colspec colwidth="1.5*"/>
+ <colspec colwidth="2*"/>
+ <thead>
+ <row>
+ <entry>Option</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>--quiet</literal></entry>
+ <entry>ne pas écrire le script vers la sortie standard</entry>
+ </row>
+ <row>
+ <entry><literal>--drop</literal></entry>
+ <entry>supprime seuleument les tables</entry>
+ </row>
+ <row>
+ <entry><literal>--create</literal></entry>
+ <entry>ne créé que les tables</entry>
+ </row>
+ <row>
+ <entry><literal>--text</literal></entry>
+ <entry>ne pas exécuter sur la base de données</entry>
+ </row>
+ <row>
+ <entry><literal>--output=my_schema.ddl</literal></entry>
+ <entry>écrit le script ddl vers un fichier</entry>
+ </row>
+ <row>
+ <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+ <entry>sélectionne une <literal>NamingStrategy</literal></entry>
+ </row>
+ <row>
+ <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+ <entry>lit la configuration Hibernate à partir d'un fichier XML</entry>
+ </row>
+ <row>
+ <entry><literal>--properties=hibernate.properties</literal></entry>
+ <entry>lit les propriétés de la base de données à partir d'un fichier</entry>
+ </row>
+ <row>
+ <entry><literal>--format</literal></entry>
+ <entry>formatte proprement le SQL généré dans le script</entry>
+ </row>
+ <row>
+ <entry><literal>--delimiter=x</literal></entry>
+ <entry>paramètre un délimiteur de fin de ligne pour le script</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ Vous pouvez même intégrer <literal>SchemaExport</literal> dans votre application :
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaExport(cfg).create(false, true);]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-4">
+ <title>Propriétés</title>
+
+ <para>
+ Les propriétés de la base de données peuvent être spécifiées
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>comme propriétés système avec <literal>-D</literal><emphasis><property></emphasis></para>
+ </listitem>
+ <listitem>
+ <para>dans <literal>hibernate.properties</literal></para>
+ </listitem>
+ <listitem>
+ <para>dans un fichier de propriétés déclaré avec <literal>--properties</literal></para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Les propriétés nécessaires sont :
+ </para>
+
+ <table frame="topbot">
+ <title>SchemaExport Connection Properties</title>
+ <tgroup cols="2">
+ <colspec colwidth="1.5*"/>
+ <colspec colwidth="2*"/>
+ <thead>
+ <row>
+ <entry>Nom de la propriété</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>hibernate.connection.driver_class</literal></entry>
+ <entry>classe du driver JDBC</entry>
+ </row>
+ <row>
+ <entry><literal>hibernate.connection.url</literal></entry>
+ <entry>URL JDBC</entry>
+ </row>
+ <row>
+ <entry><literal>hibernate.connection.username</literal></entry>
+ <entry>utilisateur de la base de données</entry>
+ </row>
+ <row>
+ <entry><literal>hibernate.connection.password</literal></entry>
+ <entry>mot de passe de l'utilisateur</entry>
+ </row>
+ <row>
+ <entry><literal>hibernate.dialect</literal></entry>
+ <entry>dialecte</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-5">
+ <title>Utiliser Ant</title>
+
+ <para>
+ Vous pouvez appeler <literal>SchemaExport</literal> depuis votre script
+ de construction Ant :
+ </para>
+
+ <programlisting><![CDATA[<target name="schemaexport">
+ <taskdef name="schemaexport"
+ classname="org.hibernate.tool.hbm2ddl.SchemaExportTask"
+ classpathref="class.path"/>
+
+ <schemaexport
+ properties="hibernate.properties"
+ quiet="no"
+ text="no"
+ drop="no"
+ delimiter=";"
+ output="schema-export.sql">
+ <fileset dir="src">
+ <include name="**/*.hbm.xml"/>
+ </fileset>
+ </schemaexport>
+</target>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-6" revision="2">
+ <title>Mises à jour incrémentales du schéma</title>
+
+ <para>
+ L'outil <literal>SchemaUpdate</literal> mettra à jour un schéma existant
+ en effectuant les changement par "incrément".
+ Notez que <literal>SchemaUpdate</literal> dépends beaucoup de l'API JDBC
+ metadata, il ne fonctionnera donc pas avec tous les drivers JDBC.
+ </para>
+
+ <para>
+ <literal>java -cp </literal><emphasis>classpath_hibernate</emphasis>
+ <literal>net.sf.hibernate.tool.hbm2ddl.SchemaUpdate</literal> <emphasis>options fichiers_de_mapping</emphasis>
+ </para>
+
+ <table frame="topbot">
+ <title><literal>SchemaUpdate</literal> Options de ligne de commande</title>
+ <tgroup cols="2">
+ <colspec colwidth="1.5*"/>
+ <colspec colwidth="2*"/>
+ <thead>
+ <row>
+ <entry>Option</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>--quiet</literal></entry>
+ <entry>ne pas écrire vers la sortie standard</entry>
+ </row>
+ <row>
+ <entry><literal>--text</literal></entry>
+ <entry>ne pas exporter vers la base de données</entry>
+ </row>
+ <row>
+ <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+ <entry>choisit une <literal>NamingStrategy</literal></entry>
+ </row>
+ <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>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ Vous pouvez intégrer <literal>SchemaUpdate</literal> dans votre application :
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaUpdate(cfg).execute(false);]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-7">
+ <title>Utiliser Ant pour des mises à jour de schéma par incrément</title>
+
+ <para>
+ Vous pouvez appeler <literal>SchemaUpdate</literal> depuis le script Ant :
+ </para>
+
+ <programlisting><![CDATA[<target name="schemaupdate">
+ <taskdef name="schemaupdate"
+ classname="org.hibernate.tool.hbm2ddl.SchemaUpdateTask"
+ classpathref="class.path"/>
+
+ <schemaupdate
+ properties="hibernate.properties"
+ quiet="no">
+ <fileset dir="src">
+ <include name="**/*.hbm.xml"/>
+ </fileset>
+ </schemaupdate>
+</target>]]></programlisting>
+
+ <sect2 id="toolsetguide-s1-8" revision="1">
+ <title>Validation du schéma</title>
+
+ <para>
+ L'outil <literal>SchemaValidator</literal> validera que le schéma existant correspond à vos documents de mapping.
+ Notez que le <literal>SchemaValidator</literal> dépends de l'API metadata de JDBC, il ne fonctionnera
+ donc pas avec tous les drivers JDBC. Cet outil est extrêmement utile pour tester.
+ </para>
+
+ <para>
+ <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
+ <literal>org.hibernate.tool.hbm2ddl.SchemaValidator</literal> <emphasis>options mapping_files</emphasis>
+ </para>
+
+ <table frame="topbot">
+ <title><literal>SchemaValidator</literal> Options de ligne de commande</title>
+ <tgroup cols="2">
+ <colspec colwidth="1.5*"/>
+ <colspec colwidth="2*"/>
+ <thead>
+ <row>
+ <entry>Option</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+ <entry>Indique une <literal>NamingStrategy</literal></entry>
+ </row>
+ <row>
+ <entry><literal>--properties=hibernate.properties</literal></entry>
+ <entry>lit les propriétés dela base de données depuis un fichier de propriétés</entry>
+ </row>
+ <row>
+ <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+ <entry>indique un fichier <literal>.cfg.xml</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ Vous pouvez inclure <literal>SchemaValidator</literal> dans votre application:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaValidator(cfg).validate();]]></programlisting>
+
+ </sect2>
+
+ </sect2>
+ <sect2 id="toolsetguide-s1-9">
+ <title>Utiliser Ant pour la validation du Schéma</title>
+
+ <para>
+ Vous pouvez appeler <literal>SchemaValidator</literal> depuis le script Ant:
+ </para>
+
+ <programlisting><![CDATA[<target name="schemavalidate">
+ <taskdef name="schemavalidator"
+ classname="org.hibernate.tool.hbm2ddl.SchemaValidatorTask"
+ classpathref="class.path"/>
+
+ <schemavalidator
+ properties="hibernate.properties">
+ <fileset dir="src">
+ <include name="**/*.hbm.xml"/>
+ </fileset>
+ </schemaupdate>
+</target>]]></programlisting>
+
+ </sect2>
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/transactions.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/transactions.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/transactions.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,1074 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="transactions" revision="2">
+ <title>Transactions et accès concurrents</title>
+
+ <para>
+ L'un des principaux avantages du mécanisme de contrôle des accès concurrents d'Hibernate est qu'il est très
+ facile à comprendre. Hibernate utilise directement les connexions JDBC ainsi que les ressources JTA sans y
+ ajouter davantage de mécanisme de blocage. Nous vous recommandons de vous familiariser avec les spécifications
+ JDBC, ANSI et d'isolement de transaction de la base de données que vous utilisez.
+ </para>
+
+ <para>
+ Hibernate ne vérouille pas vos objets en mémoire. Votre application peut suivre le
+ comportement défini par le niveau d'isolation de vos transactions de base de données.
+ Notez que grâce à la <literal>Session</literal>, qui est aussi un cache de scope transaction, Hibernate
+ fournit des lectures répétées pour les récupération par identifiants et les requêtes
+ d'entités (pas celle de valeurs scalaires).
+ </para>
+
+ <para>
+ En addition au versionning pour le controle automatique de concurrence, Hibernate fournit
+ une API (mineure) pour le verrouillage perssimiste des enregistrements, en générant
+ une syntaxe <literal>SELECT FOR UPDATE</literal>. Le controle de concurrence optimiste
+ et cette API seront détaillés plus tard dans ce chapitre.
+ </para>
+
+ <para>
+ Nous aborderons la gestion des accès concurrents en discutant de la granularité des objets <literal>Configuration</literal>,
+ <literal>SessionFactory</literal>, et <literal>Session</literal>, ainsi que de certains concepts relatifs à la base de données
+ et aux longues transactions applicatives.
+ </para>
+
+ <sect1 id="transactions-basics" revision="1">
+ <title>Gestion de session et délimitation de transactions</title>
+
+ <para>Il est important de savoir qu'un objet <literal>SessionFactory</literal> est un objet complexe et optimisé pour
+ fonctionner avec les threads(thread- safe). Il est coûteux à créer et est ainsi prévu pour n'être instancié qu?une
+ seule fois via un objet <literal>Configuration</literal> au démarrage de l'application,
+ et être partagé par tous les threads d'une application.
+ </para>
+
+ <para>Un objet <literal>Session</literal> est relativement simple et n'est threadsafe. Il est également peu
+ coûteux à créer. Il devrait n'être utilisé qu'une seule fois, pour un processus d'affaire ou une unité de
+ travail ou une conversation et ensuite être relâché. Un objet <literal>Session</literal> ne tentera pas
+ d'obtenir de connexion ( <literal>Connection</literal> )
+ JDBC (ou de <literal>Datasource</literal> ) si ce n'est pas nécessaire.
+ </para>
+
+ <para>Afin de compléter ce tableau, vous devez également penser aux transactions de base de données. Une
+ transaction de base de données se doit d'être la plus courte possible afin de réduire les risques de
+ collision sur des enregistrements verrouillés. De longues transactions à la base de données nuiront à
+ l'extensibilité de vos applications lorsque confrontées à de hauts niveaux de charge. Par conséquent,
+ il n'est jamais bon de maintenir une transaction ouverte pendant la durée de reflexion de l'utilisateur,
+ jusqu'a ce que l'unité de travail soit achevée.
+ </para>
+
+ <para>Maintenant, comment délimiter une unité de travail? Est-ce qu'une instance de <literal>Session</literal> peut avoir une durée
+ de vie dépassant plusieurs transactions à la base de données, ou bien est-ce que celles-ci doivent être liées une à une?
+ Quand faut-il ouvrir et fermer une <literal>Session</literal> ? Comment définir la démarcation de vos transactions à la base de données?
+ </para>
+
+ <sect2 id="transactions-basics-uow" revision="1">
+ <title>Unité de travail</title>
+
+ <para>
+ Il est important de mentionner que d'utiliser un paradigme <emphasis>session-par-operation</emphasis>
+ est un anti-pattern. Autrement dit: n'ouvrez et ne fermez pas la
+ <literal>Session</literal> à chacun de vos accès simples à la base de données dans un même thread! Bien sûr, le même raisonnement
+ s'applique sur la gestion des transactions à la base de données. Les appels à la base de données
+ devraient être faits en ordre et selon une séquence définie. Ils devraient également être regroupés en
+ des unités de travail atomiques. (Notez que l?utilisation d?une connexion auto-commit constitue le même
+ anti-pattern. Ce mode de fonctionnement existe pour les applications émettant des commandes SQL à partir
+ d?une console. Hibernate désengage le mode auto-commit et s'attend à ce qu'un serveur d'applications le
+ fasse également.)
+ Les transactions avec la base de données ne sont jamais optionnelles, toute communication
+ avec une base de données doit se dérouler dans une transaction, peu importe si vous lisez
+ ou écrivez des données. Comme évoqué, le comportement auto-commit pour lire les
+ données devrait être évité, puisque plusieurs petites transactions ne seront jamais
+ aussi efficaces qu'une seule plus grosse clairement définie comme unité de travail.
+ Ce dernier choix et en plus beaucoup plus facile a maintenir et à faire évoluer.
+ </para>
+
+ <para>
+ Le pattern d'utilisation le plus fréquemment rencontré dans des applications clients serveur
+ multi-usagers est le <emphasis>session-per-request</emphasis>
+ (littéralement : Session par requête). Dans ce modèle, la requête d'un client est envoyée à un serveur
+ (Où la couche de persistance est implémentée via Hibernate), une nouvelle
+ <literal>Session</literal> est ouverte et toutes les opérations d'accès à la base de données sont exécutées à l'intérieur de
+ celle-ci. Lorsque le travail est terminé (et que les réponses à envoyer au client ont été préparées), la
+ session est flushée et fermée. Une seule transaction à la base de données peut être utilisée pour répondre
+ à la requête du client. La transaction est démarrée et validée au même moment où la Session est ouverte
+ et fermée. La relation entre la <literal>Session</literal> et la <literal>Transaction</literal> est donc one-to-one.
+ Ce modèle permet de répondre parfaitement aux attentes de la grande majorité des
+ applications.
+ </para>
+
+ <para>
+ Le défi réside dans l'implémentation. Hibernate fournit une fonction de gestion de
+ la "session courante" pour simplifier ce pattern. Tout ce que vous devez faire
+ est démarrer une transaction lorsqu'une requête est traitée par le serveur, et
+ la terminer avant que la réponse ne soit envoyée au client. Vous pouvez le faire
+ de la manière que vous voulez, les solutions communes sont un <literal>ServletFilter</literal>,
+ l'interception via AOP avec une pointcut sur les méthodes de type "service", ou un conteneur
+ avec interception/proxy. Un conteneur EJB est un moyen standard d'implémenter ce genre d'acpect
+ tranverse comme la démarcation des transactions sur les EJBs session, de manière déclarative
+ avec CMT. Si vous décidez d'utiliser la démarcation programmatique des transactions, préferrez
+ l'API Hibernate <literal>Transaction</literal> détaillée plus tard dans ce chapitre, afin de
+ facilité l'utilisation et la portabilité du code.
+ </para>
+
+ <para>
+ Votre application peut accéder la "session courante" pour exécuter une requête
+ en invoquant simplement <literal>sessionFactory.getCurrentSession()</literal> n'importe où
+ et autant de fois que souhaité. Vous obtiendrez toujours une <literal>Session</literal>
+ dont le scope est la transaction courante avec la base de données. Ceci doit être configuré
+ soit dans les ressources local ou dans l'environnement JTA, voir <xref linkend="architecture-current-session"/>.
+ </para>
+
+ <para>
+ Il est parfois utile d'étendre le scope d'une <literal>Session</literal> et d'une transaction
+ à la base de données jusqu'à ce que "la vue soit rendue". Ceci est particulièrement
+ utile dans des applications à base de servlet qui utilisent une phase de rendue séparée une fois
+ que la réponse a été préparée. Etendre la transaction avec la base de données jusqu'à la fin du
+ rendering de la vue est aisé si vous implémentez votre propre intercepteur. Cependant,
+ ce n'est pas facile si vous vous appuyez sur les EJBs avec CMT, puisqu'une transaction sera
+ achevée au retour de la méthode EJB, avant le rendu de la vue. Rendez vous sur le site
+ Hibernate et sur le forum pour des astuces et des exemples sur le pattern
+ <emphasis>Open Session in View</emphasis> pattern..
+ </para>
+ </sect2>
+
+ <sect2 id="transactions-basics-apptx" revision="1">
+ <title>Longue conversation</title>
+
+ <para>Le paradigme
+ <emphasis>session-per-request</emphasis>
+ n'est pas le seul élément à utiliser dans le design de vos unités de travail. Plusieurs processus
+ d'affaire requièrent toute une série d'interactions avec l'utilisateur, entrelacées d'accès à la base de
+ donnée. Dans une application Web ou une application d'entreprise, il serait inacceptable que la durée de
+ vie d'une transaction s'étale sur plusieurs interactions avec l'usager. Considérez l'exemple suivant:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Un écran s'affiche. Les données vues par l'usager ont été chargées dans l'instance d'un objet
+ <literal>Session</literal> , dans le cadre d'une transaction de base de données. L'usager est libre de modifier ces objets.
+ </para>
+ </listitem>
+ <listitem>
+
+ <para>L'usager clique "Sauvegarder" après 5 minutes et souhaite persister les modifications qu'il a
+ apportées. Il s'attend à être la seule personne a avoir modifié ces données et qu'aucune
+ modification conflictuelle ne se soit produite durant ce laps de temps.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Ceci s'appelle une unité de travail. Du point de vue de l'utilisateur: une
+ <emphasis>conversation</emphasis> (ou <emphasis>transaction d'application</emphasis>).
+ Il y a plusieurs façon de mettre ceci en place dans votre application.
+ </para>
+
+ <para>Une première implémentation naïve pourrait consister à garder la
+ <literal>Session</literal> et la transaction à la base de données ouvertes durant le temps de travail de l'usager, à maintenir les
+ enregistrements verrouillés dans la base de données afin d'éviter des modifications concurrentes et de
+ maintenir l'isolation et l'atomicité de la transaction de l'usager. Ceci est un anti-pattern à éviter,
+ puisque le verrouillage des enregistrements dans la base de données ne permettrait pas à l'application
+ de gérer un grand nombre d'usagers concurrents.
+ </para>
+
+ <para>Il apparaît donc évident qu'il faille utiliser plusieurs transactions BDD afin d'implémenter la
+ conversation. Dans ce cas, maintenir l'isolation des processus d'affaire devient
+ partiellement la responsabilité de la couche applicative. Ainsi, la durée de vie d'une conversation
+ devrait englober celle d'une ou de plusieurs transactions de base de données. Celle-ci sera
+ atomique seulement si l'écriture des données mises à jour est faite exclusivement par la dernière
+ transaction BDD la composant. Toutes les autres sous transactions BD ne doivent faire que la lecture de
+ données. Ceci est relativement facile à mettre en place, surtout avec l'utilisation de certaines
+ fonctionnalités d'Hibernate:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Versionnage Automatique</emphasis>
+ - Hibernate peut gérer automatiquement les accès concurrents de manière optimiste et détecter si
+ une modification concurrente s'est produite durant le temps de réflexion d'un usager.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Objets Détachés</emphasis>
+ - Si vous décidez d'utiliser le paradigme
+ <emphasis>session-par-requête</emphasis>
+ discuté plus haut, toutes les entités chargées en mémoire deviendront des objets détachés durant
+ le temps de réflexion de l'usager. Hibernate vous permet de rattacher ces objets et de persister
+ les modifications y ayant été apportées. Ce pattern est appelé:
+ <emphasis>session-per- request-with-detached-objects</emphasis>
+ (littéralement: session- par-requête-avec-objets-détachés). Le versionnage automatique est
+ utilisé afin d'isoler les modifications concurrentes.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Session Longues (conversation)</emphasis>
+ - Une
+ <literal>Session</literal> Hibernate peut être déconnectée de la couche JDBC sous-jacente après que commit() ait été appelé
+ sur une transaction à la base de données et reconnectée lors d'une nouvelle requête-client. Ce
+ pattern s'appelle:
+ <emphasis>session-per-conversation</emphasis>
+ (Littéralement: session-par- conversation) et rend superflu le rattachement des
+ objets. Le versionnage automatique est utilisé afin d'isoler les modifications concurrentes.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Les deux patterns
+ <emphasis>session-per-request-with- detached- objects</emphasis>
+ (session-par-requête-avec-objets- détachés) et
+ <emphasis>session-per-conversation</emphasis>
+ (session-par-conversation) ont chacun leurs avantages et désavantages qui seront exposés
+ dans ce même chapitre, dans la section au sujet du contrôle optimiste de concurrence.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-basics-identity">
+ <title>L'identité des objets</title>
+
+ <para>Une application peut accéder à la même entité persistante de manière concurrente dans deux
+ <literal>Session</literal> s différentes. Toutefois, une instance d'une classe persistante n'est jamais partagée par deux instances
+ distinctes de la classe
+ <literal>Session</literal> . Il existe donc deux notions de l'identité d'un objet:
+ </para>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>Identité BD</term>
+ <listitem>
+ <para>
+ <literal>foo.getId().equals( bar.getId() )</literal> </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Identité JVM</term>
+ <listitem>
+ <para>
+ <literal>foo==bar</literal> </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>Ainsi, pour des objets attachés à une
+ <literal>Session</literal> <emphasis>précise</emphasis>
+ (dans la cadre d'exécution (scope) d'une instance de
+ <literal>Session</literal> ), ces deux notions d'identité sont équivalentes et garanties par Hibernate. Par contre, si une
+ application peut accéder de manière concurrente à la même entité persistante dans deux sessions
+ différentes, les deux instances seront en fait différentes (en ce qui a trait à l'identité JVM). Les
+ conflits sont résolus automatiquement par approche optimiste grâce au système de versionnage automatique
+ lorsque
+ <literal>Session.flush()</literal> ou
+ <literal>Transaction.commit()</literal> est appelé.
+ </para>
+
+ <para>Cette approche permet de reléguer à Hibernate et à la base de données sous-jacente le soin de gérer
+ les problèmes d'accès concurrents. Cette manière de faire assure également une meilleure extensibilité
+ de l'application puisque assurer l'identité JVM dans un thread ne nécessite pas de mécanismes de
+ verrouillage coûteux ou d'autres dispositifs de synchronisation. Une application n'aura jamais le besoin
+ de synchroniser des objets d'affaire tant qu'elle peut garantir qu'un seul thread aura accès à une
+ instance de
+ <literal>Session</literal> . Dans le cadre d'exécution d'un objet
+ <literal>Session</literal> , l'application peut utiliser en toute sécurité <literal>==
+ </literal> pour comparer des objets.
+ </para>
+
+ <para>
+ Une application qui utiliserait <literal>==</literal> à l'extérieur du cadre d'exécution d'une <literal>Session</literal>
+ pourrait obtenir des résultats inattendus et causer certains effets de bords. Par exemple, si vous mettez 2
+ objets dans le même <literal>Set</literal> , ceux-ci pourraient avoir la même identité BD (i.e. ils représentent le même enregistrement), mais leur
+ identité JVM pourrait être différente (elle ne peut, par définition, pas être garantie sur deux objets
+ détachés). Le développeur doit donc redéfinir l'implémentation des méthodes <literal>equals()</literal> et <literal>hashcode()</literal>
+ dans les classes persistantes et y adjoindre sa propre notion d'identité. Il existe toutefois une
+ restriction: Il ne faut jamais utiliser uniquement l'identifiant de la base de données dans l'implémentation
+ de l'égalité; Il faut utiliser une clé d'affaire, généralement une combinaison de plusieurs attributs
+ uniques, si possible immuables. Les identifiants de base de données vont changer si un objet transitoire
+ (transient) devient persistant. Si une instance transitoire est contenue dans un <literal>Set</literal> ,
+ changer le hashcode brisera le contrat du <literal>Set</literal> . Les attributs pour les clés d'affaire
+ n'ont pas à être aussi stables que des clés primaires de bases de
+ données. Il suffit simplement qu'elles soient stables tant et aussi longtemps que les objets sont dans le
+ même <literal>Set</literal> . Veuillez consulter le site web Hibernate pour des discussions plus pointues à ce sujet. Notez que ce
+ concept n'est pas propre à Hibernate mais bien général à l'implémentation de l'identité et de l'égalité en
+ Java.
+ </para>
+ </sect2>
+
+
+ <sect2 id="transactions-basics-issues">
+ <title>Problèmes communs</title>
+
+ <para>Bien qu'il puisse y avoir quelques rares exceptions à cette règle, il est recommandé de ne jamais utiliser
+ les anti-patterns
+ <emphasis>session-per- user-session</emphasis>
+ et
+ <emphasis>session-per-application</emphasis>
+ . Vous trouverez ici- bas quelques problèmes que vous risquez de rencontrer si vous en faite l?utilisation.
+ (Ces problèmes pourraient quand même survenir avec des patterns recommandés) Assurez-vous de bien comprendre
+ les implications de chacun des patterns avant de prendre votre décision.
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>L'objet
+ <literal>Session</literal> n?est pas conçu pour être utilisé par de multiples threads. En conséquence, les objets
+ potentiellement multi-thread comme les requêtes HTTP, les EJB Session et Swing Worker, risquent de
+ provoquer des conditions de course dans la
+ <literal>Session</literal> si celle-ci est partagée. Dans un environnement web classique, il serait préférable de synchroniser
+ les accès à la session http afin d?éviter qu?un usager ne recharge une page assez rapidement pour
+ que deux requêtes s?exécutant dans des threads concurrents n?utilisent la même
+ <literal>Session</literal> .
+ </para>
+ </listitem>
+ <listitem>
+ <para>Lorsque Hibernate lance une exception, le roll back de la transaction en cours doit être effectué
+ et la
+ <literal>Session</literal> doit être immédiatement fermée. (Ceci sera exploré plus tard dans le chapitre.) Si la
+ <literal>Session</literal> est directement associée à une application, il faut arrêter l?application. Le roll back de la
+ transaction ne remettra pas les objets dans leur état du début de la transaction. Ainsi, ceux-ci
+ pourraient être désynchronisés d?avec les enregistrements. (Généralement, cela ne cause pas de réels
+ problèmes puisque la plupart des exceptions sont non traitables et requièrent la reprise du
+ processus d?affaire ayant échoué.)
+ </para>
+ </listitem>
+ <listitem>
+ <para>La
+ <literal>Session</literal> met en mémoire cache tous les objets persistants (les objets surveillés et dont l'état est géré par
+ Hibernate.) Si la
+ <literal>Session</literal> est ouverte indéfiniment ou si une trop grande quantité d'objets y est chargée, l?utilisation de la
+ mémoire peut potentiellement croître jusqu?à atteindre le maximum allouable à l?application
+ (java.lang.OutOfMemoryError.) Une solution à ce problème est d?appeler les méthodes
+ <literal>Session.clear()</literal> et
+ <literal>Session.evict()</literal> pour gérer la mémoire cache de la
+ <literal>Session</literal> . Vous pouvez également utiliser des stored procedures si vous devez lancer des traitements sur de
+ grandes quantités d?informations. Certaines solutions sont décrites ici :
+ <xref linkend="batch"/>
+ . Garder une
+ <literal>Session</literal> ouverte pour toute la durée d?une session usager augmente également considérablement le risque de
+ travailler avec de l?information périmée.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect2>
+</sect1>
+
+<sect1 id="transactions-demarcation">
+ <title>Démarcation des transactions</title>
+
+ <para>La démarcation des transactions est importante dans le design d?une application. Aucune communication avec la
+ base de données ne peut être effectuée à l?extérieur du cadre d?une transaction. (Il semble que ce concept soit
+ mal compris par plusieurs développeurs trop habitués à utiliser le mode auto-commit.) Même si certains niveaux
+ d'isolation et certaines possibilités offertes par les bases de données permettent de l?éviter, il n'est jamais
+ désavantageux de toujours explicitement indiquer les bornes de transaction pour les opérations complexes comme
+ pour les opérations simples de lecture.</para>
+
+ <para>Une application utilisant Hibernate peut s'exécuter dans un environnement léger n?offrant pas la gestion
+ automatique des transactions (application autonome, application web simple ou applications Swing) ou dans un
+ environnement J2EE offrant des services de gestion automatique des transactions JTA. Dans un environnement
+ simple, Hibernate a généralement la responsabilité de la gestion de son propre pool de connexions à la base de
+ données. Le développeur de l'application doit manuellement délimiter les transactions. En d'autres mots, il
+ appartient au développeur de gérer les appels à
+ <literal>Transaction.begin()</literal>
+ ,
+ <literal>Transaction.commit()</literal>
+ et
+ <literal>Transaction.rollback()</literal>
+ . Un environnement transactionnel J2EE (serveur d'application J2EE) doit offrir la gestion des transactions au
+ niveau du container J2EE. Les bornes de transaction peuvent normalement être définies de manière déclarative
+ dans les descripteurs de déploiement d'EJB Session, par exemple. La gestion programmatique des transactions n'y
+ est donc pas nécessaire. Même les appels à
+ <literal>Session.flush()</literal>
+ sont faits automatiquement.
+ </para>
+
+ <para>Il peut être requis d'avoir une couche de persistance portable. Hibernate offre donc une API appelée
+ <literal>Transaction</literal>
+ qui sert d'enveloppe pour le système de transaction natif de l'environnement de déploiement. Il n'est pas
+ obligatoire d'utiliser cette API mais il est fortement conseillé de le faire, sauf lors de l'utilisation de CMT
+ Session Bean (EJB avec transactions gérées automatiquement par le container EJB).
+ </para>
+
+ <para>Il existe quatre étapes disctinctes lors de la fermeture d'une
+ <literal>Session</literal>
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>flush de la session</para>
+ </listitem>
+ <listitem>
+ <para>commit de la transaction</para>
+ </listitem>
+ <listitem>
+ <para>Fermeture de la session (Close)</para>
+ </listitem>
+ <listitem>
+ <para>Gestion des exceptions</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>La synchronisation de bdd depuis la session (flush) a déjà été expliqué, nous nous attarderons maintenant à la démarcation des
+ transactions et à la gestion des exceptions dans les environnements légers et les environnements J2EE.</para>
+
+
+ <sect2 id="transactions-demarcation-nonmanaged" revision="2">
+ <title>Environnement non managé</title>
+
+ <para>
+ Si la couche de persistance Hibernate s'exécute dans un environnement non managé, les connexions à la base de
+ données seront généralement prises en charge par le mécanisme de pool d'Hibernate. La gestion de la session
+ et de la transaction se fera donc de la manière suivante:</para>
+
+ <programlisting><![CDATA[// Non-managed environment idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+ tx = sess.beginTransaction();
+
+ // do some work
+ ...
+
+ tx.commit();
+}
+catch (RuntimeException e) {
+ if (tx != null) tx.rollback();
+ throw e; // or display error message
+}
+finally {
+ sess.close();
+}]]></programlisting>
+
+ <para>
+ Vous n'avez pas à invoquer <literal>flush()</literal> explicitement sur la <literal>Session</literal> -
+ l'appel de <literal>commit()</literal> déclenchera automatiquement la synchronisation (selon le <xref linkend="objectstate-flushing">FlushMode</xref>
+ de la session. Un appel à <literal>close()</literal> marque la fin de la session.
+ La conséquence directe est que la connexion à la base de données sera relachée par la session.
+ Ce code est portable est fonctionne dans les environnements non managé ET les environnements JTA.
+ </para>
+
+ <para>
+ Une solution plus flexible est la gestion par contexte fourni par Hibernate que nous avons
+ déjà rencontré:
+ </para>
+
+ <programlisting><![CDATA[// Non-managed environment idiom with getCurrentSession()
+try {
+ factory.getCurrentSession().beginTransaction();
+
+ // do some work
+ ...
+
+ factory.getCurrentSession().getTransaction().commit();
+}
+catch (RuntimeException e) {
+ factory.getCurrentSession().getTransaction().rollback();
+ throw e; // or display error message
+}]]></programlisting>
+
+ <para>
+ Vous ne verrez probablement jamais ces exemples de code dans les applications;
+ les exceptions fatales (exceptions du système) ne devraient être traitées que
+ dans la couche la plus "haute". En d'autres termes, le code qui exécute les appels
+ à Hibernate (à la couche de persistance) et le code qui gère les
+ <literal>RuntimeException</literal> (qui ne peut généralement effectuer qu'un nettoyage et une sortie)
+ sont dans des couches différentes. La gestion du contexte courant par Hibernate peut
+ simplifier notablement ce design, puisque vous devez accéder à la gestion des exceptions
+ de la <literal>SessionFactory</literal>, ce qui est décrit plus tard dans ce chapitre.
+ </para>
+
+ <para>
+ Notez que vous devriez sélectionner <literal>org.hibernate.transaction.JDBCTransactionFactory</literal>
+ (le défaut), pour le second exemple <literal>"thread"</literal> comme
+ <literal>hibernate.current_session_context_class</literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-demarcation-jta" revision="2">
+ <title>Utilisation de JTA</title>
+
+ <para>Si votre couche de persistance s'exécute dans un serveur d'application (par exemple, derrière un EJB
+ Session Bean), toutes les datasource utilisées par Hibernate feront automatiquement partie de transactions
+ JTA globales. Hibernate propose deux stratégies pour réussir cette intégration.</para>
+
+ <para>
+ Si vous utilisez des transactions gérées par un EJB (bean managed transactions - BMT), Hibernate informera
+ le serveur d'application du début et de la fin des transactions si vous utilisez l'API <literal>Transaction</literal> .
+ Ainsi, le code de gestion des transactions sera identique dans les deux types d'environnements.
+ </para>
+
+ <programlisting><![CDATA[// BMT idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+ tx = sess.beginTransaction();
+
+ // do some work
+ ...
+
+ tx.commit();
+}
+catch (RuntimeException e) {
+ if (tx != null) tx.rollback();
+ throw e; // or display error message
+}
+finally {
+ sess.close();
+}]]></programlisting>
+
+ <para>Ou encore, avec la gestion automatique de contexte:</para>
+
+ <programlisting><![CDATA[// BMT idiom with getCurrentSession()
+try {
+ factory.getCurrentSession().beginTransaction();
+
+ // do some work
+ ...
+
+ factory.getCurrentSession().getTransaction().commit();
+}
+catch (RuntimeException e) {
+ factory.getCurrentSession().getTransaction().rollback();
+ throw e; // or display error message
+}]]></programlisting>
+
+ <para>
+ Avec CMT, la démarcation des transactions est faite dans les descripteurs de déploiement des Beans Sessions et non
+ de manière programmmatique, ceci réduit le code:
+ </para>
+
+ <programlisting><![CDATA[// CMT idiom
+ Session sess = factory.getCurrentSession();
+
+ // do some work
+ ...
+]]></programlisting>
+
+ <para>
+ Dans un EJB CMT même le rollback intervient automatiquement, puisqu'une <literal>RuntimeException</literal>
+ non traitée et soulevée par une méthode d'un bean session indique au conteneur d'annuler la transaction
+ globale. <emphasis>Ceci veut donc dire que vous n'avez pas à utiliser l'API <literal>Transaction</literal> d'Hibernate
+ dans CMT.</emphasis>
+ </para>
+
+ <para>
+ Notez que le fichier de configuration Hibernate devrait contenir les valeurs
+ <literal>org.hibernate.transaction.JTATransactionFactory</literal> dans un environnement BMT ou
+ <literal>org.hibernate.transaction.CMTTransactionFactory</literal> dans un environnement CMT là où vous
+ configurez votre transaction factory Hibernate.
+ N'oubliez pas non plus de spécifier le paramètre <literal>org.hibernate.transaction.manager_lookup_class</literal> .
+ De plus, assurez vous de fixez votre <literal>hibernate.current_session_context_class</literal> soit à <literal>"jta"</literal>
+ ou de ne pas le configurer (compatibilité avec les versions précédentes).
+ </para>
+
+ <para>
+ La méthode <literal>getCurrentSession()</literal> a un inconvénient dans les environnement JTA.
+ Il y a une astuce qui est d'utiliser un mode de libération de connexion <literal>after_statement</literal> ,
+ qui est alors utilisé par défaut. Du à une étrange limitation de la spec JTA, il n'est pas possible
+ pour Hibernate de nettoyer et ferme automatiquement un <literal>ScrollableResults</literal> ouvert
+ ou une instance d'<literal>Iterator</literal> retournés <literal>scroll()</literal> ou
+ <literal>iterate()</literal>. Vous <emphasis>devez</emphasis> libérer le curseur base de données
+ sous jacent ou invoquer <literal>Hibernate.close(Iterator)</literal> explicitement depuis un
+ bloc <literal>finally</literal>. (Bien sur, la plupart des applications peuvent éviter
+ d'uiliser <literal>scroll()</literal> ou <literal>iterate()</literal> dans un code CMT.)
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-demarcation-exceptions">
+ <title>Gestion des exceptions</title>
+
+ <para>
+ Si une <literal>Session</literal> lance une exception (incluant les exceptions du type <literal>SQLException</literal>
+ ou d'un sous-type), vous devez immédiatement faire le rollback de la transaction, appeler <literal>Session.close()</literal>
+ et relâcher les références sur l'objet <literal>Session</literal> . La <literal>Session</literal> contient des méthodes
+ pouvant la mettre dans un état inutilisable. Vous devez considérer qu'<emphasis>aucune</emphasis>
+ exception lancée par Hibernate n'est traitable. Assurez-vous de fermer la session en faisant l'appel à
+ <literal>close()</literal> dans un bloc <literal>finally</literal> .
+ </para>
+
+ <para>
+ L'exception <literal>HibernateException</literal> , qui englobe la plupart des exceptions pouvant survenir dans la
+ couche de persistance Hibernate, est une exception non vérifiée (Ceci n'était pas le cas dans certaines versions antérieures de Hibernate.) Il est de
+ notre avis que nous ne devrions pas forcer un développeur à gérer une exception qu'il ne peut de toute façon
+ pas traiter dans une couche technique. Dans la plupart des applications, les exceptions non vérifiées et les
+ exceptions fatales sont gérées en amont du processus (dans les couches hautes) et un message d'erreur est
+ alors affiché à l'usager (ou un traitement alternatif est invoqué.) Veuillez noter qu'Hibernate peut
+ également lancer des exceptions non vérifiées d'un autre type que <literal>HibernateException</literal> . Celles-ci sont
+ également non traitables et vous devez les traiter comme telles.
+ </para>
+
+ <para>
+ Hibernate englobe les <literal>SQLException</literal> s lancées lors des interactions directes avec la base de données
+ dans des exceptions de type: <literal>JDBCException</literal> . En fait, Hibernate essaiera de convertir l'exception dans
+ un sous-type plus significatif de <literal>JDBCException</literal> . L'exception <literal>SQLException</literal> sous-jacente
+ est toujours disponible via la méthode <literal>JDBCException.getCause()</literal> . Cette conversion est faite par un objet
+ de type <literal>SQLExceptionConverter</literal> , qui est rattaché à l'objet <literal>SessionFactory</literal> .
+ Par défaut, le <literal>SQLExceptionConverter</literal> est associé au dialecte de BD configuré dans Hibernate. Toutefois,
+ il est possible de fournir sa propre implémentation de l'interface. (Veuillez vous référer à la javadoc sur la classe
+ <literal>SQLExceptionConverterFactory</literal> pour plus de détails. Les sous-types standard de <literal>JDBCException</literal> sont:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>JDBCConnectionException</literal> - Indique une erreur de communication avec la couche JDBC sous-jacente.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>SQLGrammarException</literal> - Indique un problème de grammaire ou de syntaxe avec la requête SQL envoyée.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ConstraintViolationException</literal> - Indique une violation de contrainte d'intégrité.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockAcquisitionException</literal> - Indique une erreur de verrouillage lors de l'éxécution de la requête.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>GenericJDBCException</literal> - Indique une erreur générique JDBC d'une autre catégorie.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect2>
+
+ <sect2 id="transactions-demarcation-timeout">
+ <title>Timeout de transaction</title>
+
+ <para>L'un des avantages fournis par les environnements transactionnels JTA (tels les containers EJB) est la
+ gestion du timeout de transaction. La gestion des dépassements de temps de transaction vise à s'assurer
+ qu'une transaction agissant incorrectement ne viendra pas bloquer indéfiniment les ressources de
+ l'application. Hibernate ne peut fournir cette fonctionnalité dans un environnement transactionnel non-JTA.
+ Par contre, Hibernate gère les opérations d'accès aux données en allouant un temps maximal aux requêtes pour
+ s'exécuter. Ainsi, une requête créant de l'inter blocage ou retournant de très grandes quantités
+ d'information pourrait être interrompue. Dans un environnement transactionnel JTA, Hibernate peut déléguer
+ au gestionnaire de transaction le soin de gérer les dépassements de temps. Cette fonctionnalité est
+ abstraite par l'objet <literal>Transaction</literal> .
+ </para>
+
+ <programlisting><![CDATA[
+ Session sess = factory.openSession();
+ try {
+ //mettre le timeout à 3 secondes.
+ sess.getTransaction().setTimeout(3);
+ sess.getTransaction().begin();
+
+ // Effectuer le travail ...
+
+ sess.getTransaction().commit()
+ }
+ catch (RuntimeException e) {
+ if ( sess.getTransaction().isActive() ) {
+ sess.getTransaction().rollback();
+ }
+ throw e;
+ // ou afficher le message d'erreur.
+ }
+ finally {
+ sess.close();
+ }]]></programlisting>
+
+
+ <para>
+ Notez que <literal>setTimeout()</literal> ne peut pas être appelé d'un EJB CMT, puisque le timeout
+ des transaction doit être spécifié de manière déclarative.
+ </para>
+
+ </sect2>
+
+</sect1>
+
+<sect1 id="transactions-optimistic">
+ <title>Contrôle de consurrence optimiste</title>
+
+ <para>La gestion optimiste des accès concurrents avec versionnage est la seule approche pouvant garantir
+ l'extensibilité des applications à haut niveau de charge. Le système de versionnage utilise des numéros de
+ version ou l'horodatage pour détecter les mises à jour causant des conflits avec d'autres actualisations
+ antérieures. Hibernate propose trois approches pour l'écriture de code applicatif utilisant la gestion optimiste
+ d'accès concurrents. Le cas d'utilisation décrit plus bas fait mention de conversation,
+ mais le versionnage peut également améliorer la qualité d'une application en prévenant la perte de mises à
+ jour.</para>
+
+ <sect2 id="transactions-optimistic-manual">
+ <title>Gestion du versionnage au niveau applicatif</title>
+
+ <para>Dans cet exemple d'implémentation utilisant peu les fonctionnalités d'Hibernate, chaque interaction avec
+ la base de données se fait en utilisant une nouvelle <literal>Session</literal> et le développeur doit recharger
+ les données persistantes à partir de la BD avant de les manipuler. Cette
+ implémentation force l'application à vérifier la version des objets afin de maintenir l'isolation
+ transactionnelle. Cette approche, semblable à celle retrouvée pour les EJB, est la moins efficace de celles
+ présentées dans ce chapitre.
+ </para>
+
+ <programlisting>
+ <![CDATA[// foo est une instance chargée antérieurement par une autre
+ Session session = factory.openSession();
+ Transaction t = session.beginTransaction();
+
+ int oldVersion = foo.getVersion();
+ session.load( foo, foo.getKey() ); // Charger l'état courant
+
+ if ( oldVersion!=foo.getVersion )
+ throw new StaleObjectStateException();
+
+ foo.setProperty("bar");
+ t.commit();
+ session.close();]]></programlisting>
+
+ <para>Le mapping de la propriété <literal>version</literal> est fait via <literal><version></literal> et
+ Hibernate l'incrémentera automatiquement à chaque flush() si l'entité doit être mise à jour.
+ </para>
+
+
+ <para>Bien sûr, si votre application ne fait pas face à beaucoup d'accès concurrents et ne nécessite pas
+ l'utilisation du versionnage, cette approche peut également être utilisée, il n'y a qu'à ignorer le code
+ relié au versionnage. Dans ce cas, la stratégie du
+ <emphasis>last commit wins</emphasis>
+ (littéralement: le dernier commit l'emporte) sera utilisée pour les conversations (longues transactions applicatives).
+ Gardez à l'esprit que cette approche pourrait rendre perplexe les utilisateurs de l'application car ils
+ pourraient perdre des données mises à jour sans qu'aucun message d'erreur ne leur soit présenté et sans
+ avoir la possibilité de fusionner les données.
+ </para>
+
+ <para>Il est clair que la gestion manuelle de la vérification du versionnage des objets ne peut être effectuée
+ que dans certains cas triviaux et que cette approche n'est pas valable pour la plupart des applications. De
+ manière générale, les applications ne cherchent pas à actualiser de simples objets sans relations, elles le
+ font généralement pour de larges graphes d'objets. Pour toute application utilisant le paradigme des conversations
+ ou des objets détachés, Hibernate peut gérer automatiquement la vérification des versions
+ d'objets.</para>
+
+ </sect2>
+
+ <sect2 id="transactions-optimistic-longsession">
+ <title>Les sessions longues et le versionnage automatique.</title>
+
+ <para>Dans ce scénario, une seule instance de <literal>Session</literal> et des objets persistants est utilisée
+ pour toute l'application. Hibernate vérifie la version des objets
+ persistants avant d'effectuer le flush() et lance une exception si une modification concurrente est
+ détectée. Il appartient alors au développeur de gérer l'exception. Les traitements alternatifs généralement
+ proposés sont alors de permettre à l'usager de faire la fusion des données ou de lui offrir de recommencer
+ son travail à partie des données les plus récentes dans la BD.
+ </para>
+
+ <para>Il est à noter que lorsqu'une application est en attente d'une action de la part de l?usager, La <literal>Session</literal>
+ n'est pas connectée à la couche JDBC sous-jacente. C'est la manière la plus efficace de gérer les accès à la
+ base de données. L'application ne devrait pas se préoccuper du versionnage des objets, de la réassociation
+ des objets détachés, ni du rechargement de tous les objets à chaque transaction.
+ </para>
+
+ <programlisting>
+ <![CDATA[// foo est une instance chargée antérieurement par une autre session
+
+ session.reconnect();// Obtention d'une nouvelle connexion JDBC
+ Transaction t = session.beginTransaction();
+ foo.setProperty("bar");
+ t.commit(); //Terminer la transaction, propager les changements et vérifier les versions.
+ session.disconnect(); // Retourner la connexion JDBC
+ ]]></programlisting>
+
+
+ <para>L'objet <literal>foo</literal> sait quel objet <literal>Session</literal> l'a chargé. <literal>Session.reconnect()</literal>
+ obtient une nouvelle connexion (celle-ci peut être également fournie) et permet à la session de continuer
+ son travail. La méthode <literal>Session.disconnect()</literal> déconnecte la session de la connexion JDBC et
+ retourne celle-ci au pool de connexion (à moins que vous ne
+ lui ayez fourni vous même la connexion.) Après la reconnexion, afin de forcer la vérification du versionnage
+ de certaines entités que vous ne cherchez pas à actualiser, vous pouvez faire un appel à <literal>Session.lock()</literal>
+ en mode <literal>LockMode.READ</literal> pour tout objet ayant pu être modifié par une autre transaction. Il n'est pas nécessaire de verrouiller les
+ données que vous désirez mettre à jour.
+ </para>
+
+ <para>Si des appels implicites aux méthodes <literal>disconnect()</literal> et <literal>reconnect()</literal> sont trop
+ coûteux, vous pouvez les éviter en utilisant <literal>hibernate.connection.release_mode</literal> .
+ </para>
+
+ <para>Ce pattern peut présenter des problèmes si la <literal>Session</literal> est trop volumineuse pour être
+ stockée entre les actions de l'usager. Plus spécifiquement, une session <literal>HttpSession</literal> se doit
+ d'être la plus petite possible. Puisque la <literal>Session</literal> joue obligatoirement le rôle de mémoire
+ cache de premier niveau et contient à ce titre tous les objets
+ chargés, il est préférable de n'utiliser cette stratégie que pour quelques cycles de requêtes car les objets
+ risquent d'y être rapidement périmés.
+ </para>
+
+ <para>Notez que la <literal>Session</literal> déconnectée devrait être conservée près de la couche de persistance. Autrement dit, utilisez un EJB stateful
+ 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>
+
+ </sect2>
+
+ <sect2 id="transactions-optimistic-detached">
+ <title>Les objets détachés et le versionnage automatique</title>
+
+ <para>Chaque interaction avec le système de persistance se fait via une nouvelle <literal>Session</literal> .
+ Toutefois, les mêmes instances d'objets persistants sont réutilisées pour chacune de ces interactions.
+ L'application doit pouvoir manipuler l'état des instances détachées ayant été chargées antérieurement via
+ une autre session. Pour ce faire, ces objets persistants doivent être rattachés à la <literal>Session</literal>
+ courante en utilisant <literal>Session.update()</literal> , <literal>Session.saveOrUpdate()</literal> , ou <literal>Session.merge()</literal> .
+ </para>
+
+ <programlisting>
+ <![CDATA[// foo est une instance chargée antérieurement par une autre session
+
+ foo.setProperty("bar");
+ session = factory.openSession();
+ Transaction t = session.beginTransaction();
+ session.saveOrUpdate(foo); //Utiliser merge() si "foo" pourrait avoir été chargé précédement
+ t.commit();
+ session.close();]]> </programlisting>
+
+
+ <para>Encore une fois, Hibernate vérifiera la version des instances devant être actualisées durant le flush().
+ Une exception sera lancée si des conflits sont détectés.</para>
+
+ <para>Vous pouvez également utiliser <literal>lock()</literal> au lieu de <literal>update()</literal> et
+ utiliser le mode <literal>LockMode.READ</literal> (qui lancera une vérification de version, en ignorant tous les niveaux de mémoire cache) si vous êtes
+ certain que l'objet n'a pas été modifié.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-optimistic-customizing">
+ <title>Personnaliser le versionnage automatique</title>
+
+ <para>Vous pouvez désactiver l'incrémentation automatique du numéro de version de certains attributs et
+ collections en mettant la valeur du paramètre de mapping <literal>optimistic-lock</literal> à
+ false. Hibernate cessera ainsi d'incrémenter leur numéro de version s'ils sont mis à jour.
+ </para>
+
+ <para>Certaines entreprises possèdent de vieux systèmes dont les schémas de bases de données sont statiques et
+ ne peuvent être modifiés. Il existe aussi des cas où plusieurs applications doivent accéder à la même base
+ de données, mais certaines d'entre elles ne peuvent gérer les numéros de version ou les champs horodatés.
+ Dans les deux cas, le versionnage ne peut être implanté par le rajout d'une colonne dans la base de données.
+ Afin de forcer la vérification de version dans un système sans en faire le mapping, mais en forçant une
+ comparaison des états de tous les attributs d'une entité, vous pouvez utiliser l'attribut <literal>optimistic- lock="all"</literal>
+ sous l'élément <literal><class></literal> . Veuillez noter que cette manière de gérer le versionnage ne peut être utilisée que si l'application
+ utilises de longues sessions, lui permettant de comparer l'ancien état et le nouvel état d'une entité.
+ L'utilisation d'un pattern <literal>session-per-request-with-detached- objects</literal> devient alors impossible.
+ </para>
+
+ <para>Il peut être souhaitable de permettre les modifications concurrentes lorsque des champs distincts sont
+ modifiés. En mettant la propriété <literal>optimistic-lock="dirty"</literal> dans l'élément <literal><class></literal> ,
+ Hibernate ne fera la comparaison que des champs devant être actualisés lors du flush().
+ </para>
+
+ <para>Dans les deux cas: en utilisant une colonne de version/horodatée ou via la comparaison de l'état complet
+ de l'objet ou de ses champs modifiés, Hibernate ne créera qu'une seule commande d'UPDATE par entité avec la
+ clause WHERE appropriée pour mettre à jour l'entité
+ <emphasis>ET</emphasis>
+ en vérifier la version. Si vous utilisez la persistance transitive pour propager l'évènement de rattachement
+ à des entités associées, il est possible qu'Hibernate génère des commandes d'UPDATE inutiles. Ceci n'est
+ généralement pas un problème, mais certains déclencheurs
+ <emphasis>on update</emphasis>
+ dans la base de données pourraient être activés même si aucun changement n'était réellement persisté sur des
+ objets associés. Vous pouvez personnaliser ce comportement en indiquant <literal>select-before- update="true"</literal>
+ dans l'élément de mapping <literal><class></literal> . Ceci forcera Hibernate à faire le SELECT de l'instance
+ afin de s'assurer que l'entité doit réellement être
+ actualisée avant de lancer la commande d'UPDATE.
+ </para>
+
+ </sect2>
+
+</sect1>
+
+<sect1 id="transactions-locking">
+ <title>Verouillage pessimiste</title>
+
+ <para>Il n'est nécessaire de s'attarder à la stratégie de verrouillage des entités dans une application utilisant
+ Hibernate. Il est généralement suffisant de définir le niveau d'isolation pour les connexions JDBC et de laisser
+ ensuite la base de donnée effectuer son travail. Toutefois, certains utilisateurs avancés peuvent vouloir
+ obtenir un verrouillage pessimiste exclusif sur un enregistrement et le réobtenir au lancement d'une nouvelle
+ transaction.</para>
+
+ <para>Hibernate utilisera toujours le mécanisme de verrouillage de la base de données et ne verrouillera jamais les
+ objets en mémoire!</para>
+
+ <para>La classe
+ <literal>LockMode</literal>
+ définit les différents niveaux de verrouillage pouvant être obtenus par Hibernate. Le verrouillage est obtenu
+ par les mécanismes suivants:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>LockMode.WRITE</literal> est obtenu automatiquement quand Hibernate actualise ou insert un enregistrement.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.UPGRADE</literal> peut être obtenu de manière explicite via la requête en utilisant
+ <literal>SELECT ... FOR UPDATE</literal> sur une base de données supportant cette syntaxe.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.UPGRADE_NOWAIT</literal> peut être obtenu de manière explicite en utilisant
+ <literal>SELECT ... FOR UPDATE NOWAIT</literal> sur Oracle.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.READ</literal> est obtenu automatiquement quand Hibernate lit des données dans un contexte d'isolation
+ <literal>Repeatable Read</literal> ou
+ <literal>Serializable</literal> . Peut être réobtenu explicitement via une requête.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.NONE</literal> représente l'absence de verouillage. Tous les objets migrent vers ce mode a la fin d'une
+ <literal>Transaction</literal> . Les objets associés à une session via un appel à
+ <literal>saveOrUpdate()</literal> commencent également leur cycle de vie dans cet état.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Les niveaux de verrouillage peuvent être explicitement obtenus de l'une des manières suivantes:</para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>Un appel à
+ <literal>Session.load()</literal> , en spécifiant un niveau verrouillage
+ <literal>LockMode</literal> .
+ </para>
+ </listitem>
+ <listitem>
+ <para>Un appel à
+ <literal>Session.lock()</literal> .
+ </para>
+ </listitem>
+ <listitem>
+ <para>Une appel à
+ <literal>Query.setLockMode()</literal> .
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Si
+ <literal>Session.load()</literal>
+ est appelé avec le paramètre de niveau de verouillage
+ <literal>UPGRADE</literal>
+ ou
+ <literal>UPGRADE_NOWAIT</literal>
+ et que l'objet demandé n'est pas présent dans la session, celui-ci sera chargé à l'aide d'une requête
+ <literal>SELECT ... FOR UPDATE</literal>
+ . Si la méthode
+ <literal>load()</literal>
+ est appelée pour un objet déjà en session avec un verrouillage moindre que celui demandé, Hibernate appellera la
+ méthode
+ <literal>lock()</literal>
+ pour cet objet.
+ </para>
+
+ <para>
+ <literal>Session.lock()</literal>
+ effectue une vérification de version si le niveau de verrouillage est
+ <literal>READ</literal>
+ ,
+ <literal>UPGRADE</literal>
+ ou
+ <literal>UPGRADE_NOWAIT</literal>
+ . (Dans le cas des niveaux
+ <literal>UPGRADE</literal>
+ ou
+ <literal>UPGRADE_NOWAIT</literal>
+ , une requête
+ <literal>SELECT ... FOR UPDATE</literal>
+ sera utilisée.)
+ </para>
+
+ <para>Si une base de données ne supporte pas le niveau de verrouillage demandé, Hibernate utilisera un niveau
+ alternatif convenable au lieux de lancer une exception. Ceci assurera la portabilité de votre
+ application.</para>
+</sect1>
+
+ <sect1 id="transactions-connection-release">
+ <title>Mode de libération de Connection</title>
+
+ <para>
+ Le comportement original (2.x) d'Hibernate pour la gestion des connexions JDBC
+ était que la <literal>Session</literal> obtenait une connexion dès qu'elle en avait
+ besoin et la libérait une fois la session fermée.
+ Hibernate 3 a introduit les modes de libération de connexion pour indiquer à la session
+ comment gérer les transactions JDBC. Notez que la discussion suivante n'est pertinente
+ que pour des connexions fournies par un <literal>ConnectionProvider</literal>, celles gérées
+ par l'utilisateur sont en dehors du scope de cette discussion. Les différents modes
+ sont définies par <literal>org.hibernate.ConnectionReleaseMode</literal>:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>ON_CLOSE</literal> - est essentiellement le comportement passé.
+ La session Hibernate obtient une connexion lorsqu'elle en a besoin et la garde
+ jusqu'à ce que la session se ferme.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>AFTER_TRANSACTION</literal> - indique de relacher la connexion après qu'une
+ <literal>org.hibernate.Transaction</literal> se soit achevée.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>AFTER_STATEMENT</literal> (aussi appelé libération brutale) - indique de relacher
+ les connexions après chaque exécution d'un statement. Ce relachement aggressif est annulé
+ si ce statement laisse des ressources associées à une session donnée ouvertes, actuellement
+ ceci n'arrive que lors de l'utilisation de <literal>org.hibernate.ScrollableResults</literal>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Le paramètre de configuration <literal>hibernate.connection.release_mode</literal> est utilisé
+ pour spécifier quel mode de libération doit être utiliser. Les valeurs possibles sont:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>auto</literal> (valeur par défaut) - ce choix délègue le choix de libération
+ à la méthode <literal>org.hibernate.transaction.TransactionFactory.getDefaultReleaseMode()</literal>
+ Pour la JTATransactionFactory, elle retourne ConnectionReleaseMode.AFTER_STATEMENT; pour
+ JDBCTransactionFactory, elle retourne ConnectionReleaseMode.AFTER_TRANSACTION. C'est rarement
+ une bonne idée de changer ce comportement par défaut puisque les erreurs soulevées par ce
+ paramétrage tend à prouver une erreur dans le code de l'utilisateur.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>on_close</literal> - indique d'utiliser ConnectionReleaseMode.ON_CLOSE. Ce paramétrage
+ existe pour garantir la compatibilité avec les versions précédentes, mais ne devrait plus être utilisé.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>after_transaction</literal> - indique d'utiliser ConnectionReleaseMode.AFTER_TRANSACTION.
+ Ne devrait pas être utilisé dans les environnements JTA. Notez aussi qu'avec
+ ConnectionReleaseMode.AFTER_TRANSACTION, si une session est considérée comme étant en mode auto-commit
+ les connexions seront relachées comme si le mode était AFTER_STATEMENT.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>after_statement</literal> - indique d'utiliser ConnectionReleaseMode.AFTER_STATEMENT.
+ Additonnellement, le <literal>ConnectionProvider</literal> utilisé est consulté pour savoir s'il supporte
+ ce paramétrage (<literal>supportsAggressiveRelease()</literal>). Si ce n'est pas le cas, le mode de
+ libération est ré initialisé à ConnectionReleaseMode.AFTER_TRANSACTION.
+ Ce paramétrage n'est sûr que dans les environnements où il est possible d'obtenir à nouveau
+ la même connexion JDBC à chaque fois que l'on fait un appel de <literal>ConnectionProvider.getConnection()</literal>
+ ou dans les envrionnements auto-commit où il n'est pas important d'obtenir plusieurs fois la
+ même connexion.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/tutorial.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/tutorial.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/tutorial.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,1575 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="tutorial">
+ <title>Introduction à Hibernate</title>
+
+ <sect1 id="tutorial-intro" revision="1">
+ <title>Préface</title>
+
+ <para>
+ Ce chapitre est un didacticiel introductif destiné aux nouveaux utilisateurs
+ d'Hibernate. Nous commençons avec une simple application en ligne de commande
+ utilisant une base de données en mémoire, et la développons en étapes faciles
+ à comprendre.
+ </para>
+
+ <para>
+ Ce didacticiel est destiné aux nouveaux utilisateurs d'Hibernate mais requiert
+ des connaissances Java et SQL. Il est basé sur un didacticiel de Michael Gloegl,
+ les bibliothèques tierces que nous nommons sont pour les JDK 1.4 et 5.0. Vous
+ pourriez avoir besoin d'autres bibliothèques pour le JDK 1.3.
+ </para>
+
+ <para>
+ Le code source de ce tutoriel est inclus dans la distribution dans le répertoire
+ <literal>doc/reference/tutorial/</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="tutorial-firstapp" revision="1">
+ <title>Partie 1 - Première application Hibernate</title>
+
+ <para>
+ D'abord, nous créerons une simple application Hibernate en console. Nous utilisons
+ une base de données en mémoire (HSQL DB), donc nous n'avons pas à installer de
+ serveur de base de données.
+ </para>
+
+ <para>
+ Supposons que nous ayons besoin d'une petite application de base de données qui
+ puisse stocker des événements que nous voulons suivre, et des informations à propos
+ des hôtes de ces événements.
+ </para>
+
+ <para>
+ La première chose que nous faisons est de configurer notre répertoire de
+ développement et de mettre toutes les bibliothèques dont nous avons besoin dedans.
+ Téléchargez la distribution Hibernate à partir du site web d'Hibernate.
+ Extrayez le paquet et placez toutes les bibliothèques requises trouvées dans
+ <literal>/lib</literal> dans le répertoire <literal>/lib</literal> de votre
+ nouveau répertoire de travail. Il devrait ressembler à ça :
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ antlr.jar
+ cglib-full.jar
+ asm.jar
+ asm-attrs.jars
+ commons-collections.jar
+ commons-logging.jar
+ ehcache.jar
+ hibernate3.jar
+ jta.jar
+ dom4j.jar
+ log4j.jar ]]></programlisting>
+
+ <para>
+ Ceci est l'ensemble minimum de bibliothèques requises (notez que nous avons aussi
+ copié hibernate3.jar, l'archive principale) pour Hibernate. Lisez le fichier
+ <literal>README.txt</literal> dans le répertoire <literal>lib/</literal> de la
+ distribution Hibernate pour plus d'informations à propos des biliothèques tierces
+ requises et optionnelles. (En fait, log4j n'est pas requis mais préféré par beaucoup
+ de développeurs.)
+ </para>
+
+ <para>
+ Ensuite, nous créons une classe qui réprésente l'événement que nous voulons
+ stocker dans notre base de données.
+ </para>
+
+ <sect2 id="tutorial-firstapp-firstclass" revision="1">
+ <title>La première classe</title>
+
+ <para>
+ Notre première classe persistante est une simple classe JavaBean avec
+ quelques propriétés :
+ </para>
+
+ <programlisting><![CDATA[package events;
+
+import java.util.Date;
+
+public class Event {
+ private Long id;
+
+ private String title;
+ private Date date;
+
+ public Event() {}
+
+ public Long getId() {
+ return id;
+ }
+
+ private void setId(Long id) {
+ this.id = id;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+}]]></programlisting>
+
+ <para>
+ Vous pouvez voir que cette classe utilise les conventions de nommage standard JavaBean
+ pour les méthodes getter/setter des propriétés, ainsi qu'une visibilité privée
+ pour les champs. Ceci est la conception recommandée - mais pas obligatoire. Hibernate peut
+ aussi accéder aux champs directement, le bénéfice des méthodes d'accès est la robustesse
+ pour la refonte de code. Le constructeur sans argument est requis pour instancier
+ un objet de cette classe via reflexion.
+ </para>
+
+ <para>
+ La propriété <literal>id</literal> contient la valeur d'un identifiant unique pour un
+ événement particulier. Toutes les classes d'entités persistantes (ainsi que les classes
+ dépendantes de moindre importance) auront besoin d'une telle propriété identifiante si nous
+ voulons utiliser l'ensemble complet des fonctionnalités d'Hibernate. En fait, la plupart des
+ applications (surtout les applications web) ont besoin de distinguer des objets par des
+ identifiants, donc vous devriez considérer ça comme une fonctionnalité plutôt que comme une
+ limitation. Cependant, nous ne manipulons généralement pas l'identité d'un objet, dorénavant
+ la méthode setter devrait être privée. Seul Hibernate assignera les identifiants lorsqu'un
+ objet est sauvegardé. Vous pouvez voir qu'Hibernate peut accéder aux méthodes publiques,
+ privées et protégées, ainsi qu'aux champs (publics, privés, protégés) directement. Le choix
+ vous est laissé, et vous pouvez l'ajuster à la conception de votre application.
+ </para>
+
+ <para>
+ Le constructeur sans argument est requis pour toutes les classes persistantes ;
+ Hibernate doit créer des objets pour vous en utilisant la réflexion Java. Le
+ constructeur peut être privé, cependant, la visibilité du paquet est requise
+ pour la génération de proxy à l'exécution et une récupération des données efficaces
+ sans instrumentation du bytecode.
+ </para>
+
+ <para>
+ Placez ce fichier source Java dans un répertoire appelé <literal>src</literal>
+ dans le dossier de développement. Ce répertoire devrait maintenant ressembler
+ à ça :
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ <Hibernate et bibliothèques tierces>
++src
+ +events
+ Event.java]]></programlisting>
+
+
+ <para>
+ Dans la prochaine étape, nous informons Hibernate de cette classe persistante.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-mapping" revision="1">
+ <title>Le fichier de mapping</title>
+
+ <para>
+ Hibernate a besoin de savoir comment charger et stocker des objets d'une classe
+ persistante. C'est là qu'intervient le fichier de mapping Hibernate. Le fichier
+ de mapping indique à Hibernate à quelle table dans la base de données il doit
+ accéder, et quelles colonnes de cette table il devra utiliser.
+ </para>
+
+ <para>
+ La structure basique de ce fichier de mapping ressemble à ça :
+ </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">
+
+<hibernate-mapping>
+[...]
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Notez que la DTD Hibernate est très sophistiquée. Vous pouvez l'utiliser
+ pour l'auto-complétement des éléments et des attributs de mapping XML dans
+ votre éditeur ou votre IDE. Vous devriez aussi ouvrir le fichier DTD dans
+ votre éditeur de texte - c'est le moyen le plus facile d'obtenir une vue
+ d'ensemble de tous les éléments et attributs, et de voir les valeurs par
+ défaut, ainsi que quelques commentaires. Notez qu'Hibernate ne chargera
+ pas le fichier DTD à partir du web, mais regardera d'abord dans le classpath
+ de l'application. Le fichier DTD est inclus dans <literal>hibernate3.jar</literal>
+ ainsi que dans le répertoire <literal>src</literal> de la distribution
+ Hibernate.
+ </para>
+
+ <para>
+ Nous omettrons la déclaration de la DTD dans les exemples futurs pour
+ raccourcir le code. Bien sûr il n'est pas optionnel.
+ </para>
+
+ <para>
+ Entre les deux balises <literal>hibernate-mapping</literal>, incluez un
+ élément <literal>class</literal>. Toutes les classes d'entités persistantes
+ (encore une fois, il pourrait y avoir des classes dépendantes plus tard,
+ qui ne sont pas des entités mère) ont besoin d'un mapping vers une table
+ de la base de données SQL :
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Event" table="EVENTS">
+
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Plus loin, nous disons à Hibernate comment persister et charger un objet de la classe
+ <literal>Event</literal> dans la table <literal>EVENTS</literal>, chaque instance est
+ représentée par une ligne dans cette table. Maintenant nous continuons avec le mapping de
+ la propriété de l'identifiant unique vers la clef primaire de la table. De plus, comme
+ nous ne voulons pas nous occuper de la gestion de cet identifiant, nous utilisons une
+ stratégie de génération d'identifiant d'Hibernate pour la colonne de la clef primaire
+ subrogée :
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Event" table="EVENTS">
+ <id name="id" column="EVENT_ID">
+ <generator class="increment"/>
+ </id>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ L'élément <literal>id</literal> est la déclaration de la propriété de l'identifiant,
+ <literal>name="id"</literal> déclare le nom de la propriété Java - Hibernate
+ utilisera les méthodes getter et setter pour accéder à la propriété. L'attribut
+ <literal>column</literal> indique à Hibernate quelle colonne de la table
+ <literal>EVENTS</literal> nous utilisons pour cette clef primaire. L'élément
+ <literal>generator</literal> imbriqué spécifie la stratégie de génération de
+ l'identifiant, dans ce cas nous avons utilisé <literal>increment</literal>,
+ laquelle est une méthode très simple utile surtout pour les tests
+ (et didacticiels). Hibernate supporte aussi les identifiants générés par les
+ bases de données, globalement uniques, ainsi que les identifiants assignés par
+ l'application (ou n'importe quelle stratégie que vous avez écrit en extension).
+ </para>
+
+ <para>
+ Finalement nous incluons des déclarations pour les propriétés persistantes de la classe
+ dans le fichier de mapping. Par défaut, aucune propriété de la classe n'est considérée
+ comme persistante :
+ </para>
+
+ <programlisting><![CDATA[
+<hibernate-mapping>
+
+ <class name="Event" table="EVENTS">
+ <id name="id" column="EVENT_ID">
+ <generator class="increment"/>
+ </id>
+ <property name="date" type="timestamp" column="EVENT_DATE"/>
+ <property name="title"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Comme avec l'élément <literal>id</literal>, l'attribut <literal>name</literal>
+ de l'élément <literal>property</literal> indique à Hibernate quels getters/setters
+ utiliser.
+ </para>
+
+ <para>
+ Pourquoi le mapping de la propriété <literal>date</literal> inclut
+ l'attribut <literal>column</literal>, mais pas <literal>title</literal> ?
+ Sans l'attribut <literal>column</literal> Hibernate utilise par défaut
+ le nom de la propriété comme nom de colonne. Ca fonctionne bien pour
+ <literal>title</literal>. Cependant, <literal>date</literal> est un mot clef
+ réservé dans la plupart des bases de données, donc nous utilisons un nom
+ différent pour le mapping.
+ </para>
+
+ <para>
+ La prochaine chose intéressante est que le mapping de <literal>title</literal>
+ manque aussi d'un attribut <literal>type</literal>. Les types que nous déclarons
+ et utilisons dans les fichiers de mapping ne sont pas, comme vous pourriez vous
+ y attendre, des types de données Java. Ce ne sont pas, non plus, des types de
+ base de données SQL. Ces types sont donc appelés des <emphasis>types de mapping
+ Hibernate</emphasis>, des convertisseurs qui peuvent traduire des types Java en
+ types SQL et vice versa. De plus, Hibernate tentera de déterminer la bonne conversion
+ et le type de mapping lui-même si l'attribut <literal>type</literal> n'est pas
+ présent dans le mapping. Dans certains cas, cette détection automatique (utilisant
+ la réflexion sur la classe Java) pourrait ne pas donner la valeur attendue ou
+ dont vous avez besoin. C'est le cas avec la propriété <literal>date</literal>.
+ Hibernate ne peut pas savoir si la propriété "mappera" une colonne SQL de type
+ <literal>date</literal>, <literal>timestamp</literal> ou <literal>time</literal>.
+ Nous déclarons que nous voulons conserver des informations avec une date complète
+ et l'heure en mappant la propriété avec un <literal>timestamp</literal>.
+ </para>
+
+ <para>
+ Ce fichier de mapping devrait être sauvegardé en tant que <literal>Event.hbm.xml</literal>,
+ juste dans le répertoire à côté du fichier source de la classe Java <literal>Event</literal>.
+ Le nommage des fichiers de mapping peut être arbitraire, cependant le suffixe
+ <literal>hbm.xml</literal> est devenu une convention dans la communauté des
+ développeurs Hibernate. La structure du répertoire devrait ressembler à ça :
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ <Hibernate et bibliothèques tierces>
++src
+ Event.java
+ Event.hbm.xml]]></programlisting>
+
+ <para>
+ Nous poursuivons avec la configuration principale d'Hibernate.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-configuration" revision="1">
+ <title>Configuration d'Hibernate</title>
+
+ <para>
+ Nous avons maintenant une classe persistante et son fichier de mapping. Il est temps de
+ configurer Hibernate. Avant ça, nous avons besoin d'une base de données. HSQL DB, un
+ SGBD SQL basé sur Java et travaillant en mémoire, peut être téléchargé à partir du site
+ web de HSQL. En fait, vous avez seulement besoin de <literal>hsqldb.jar</literal>. Placez
+ ce fichier dans le répertoire <literal>lib/</literal> du dossier de développement.
+ </para>
+
+ <para>
+ Créez un répertoire appelé <literal>data</literal> à la racine du répertoire de développement -
+ c'est là que HSQL DB stockera ses fichiers de données. Démarrez maintenant votre base de données
+ en exécutant <literal>java -classpath lib/hsqldb.jar org.hsqldb.Server</literal> dans votre répertoire de travail.
+ Vous observez qu'elle démarre et ouvre une socket TCP/IP, c'est là que notre application
+ se connectera plus tard. Si vous souhaitez démarrez à partir d'une nouvelle base de données
+ pour ce tutoriel (faites <literal>CTRL + C</literal> dans la fenêtre the window), effacez
+ le répertoire <literal>data/</literal> et redémarrez HSQL DB à nouveau.
+
+ </para>
+
+ <para>
+ Hibernate est la couche de votre application qui se connecte à cette base de données,
+ donc il a besoin des informations de connexion. Les connexions sont établies à travers
+ un pool de connexions JDBC, que nous devons aussi configurer. La distribution Hibernate
+ contient différents outils de gestion de pools de connexions JDBC open source, mais
+ pour ce didacticiel nous utiliserons le pool de connexions intégré à Hibernate. Notez
+ que vous devez copier les bibliothèques requises dans votre classpath et utiliser
+ une configuration de pool de connexions différente si vous voulez utiliser
+ un logiciel de gestion de pools JDBC tiers avec une qualité de production.
+ </para>
+
+ <para>
+ Pour la configuration d'Hibernate, nous pouvons utiliser un simple fichier
+ <literal>hibernate.properties</literal>, un fichier <literal>hibernate.cfg.xml</literal>
+ légèrement plus sophistiqué, ou même une configuration complète par programmation. La
+ plupart des utilisateurs préfèrent le fichier de configuration XML :
+ </para>
+
+ <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+ "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+ <session-factory>
+
+ <!-- Database connection settings -->
+ <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
+ <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
+ <property name="connection.username">sa</property>
+ <property name="connection.password"></property>
+
+ <!-- JDBC connection pool (use the built-in) -->
+ <property name="connection.pool_size">1</property>
+
+ <!-- SQL dialect -->
+ <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
+
+ <!-- Enable Hibernate's automatic session context management -->
+ <property name="current_session_context_class">thread</property>
+
+ <!-- Disable the second-level cache -->
+ <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
+
+ <!-- Echo all executed SQL to stdout -->
+ <property name="show_sql">true</property>
+
+ <!-- Drop and re-create the database schema on startup -->
+ <property name="hbm2ddl.auto">create</property>
+
+ <mapping resource="events/Event.hbm.xml"/>
+
+ </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+ <para>
+ Notez que cette configuration XML utilise une DTD différente. Nous configurons
+ une <literal>SessionFactory</literal> d'Hibernate - une fabrique globale responsable
+ d'une base de données particulière. Si vous avez plusieurs base de données, utilisez
+ plusieurs configurations <literal><session-factory></literal>, généralement
+ dans des fichiers de configuration différents (pour un démarrage plus facile).
+ </para>
+
+ <para>
+ Les quatre premiers éléments <literal>property</literal> contiennent la configuration
+ nécessaire pour la connexion JDBC. L'élément <literal>property</literal> du dialecte
+ spécifie quelle variante du SQL Hibernate va générer. La gestion automatique des sessions
+ d'Hibernate pour les contextes de persistance sera détaillée très vite.
+ L'option <literal>hbm2ddl.auto</literal> active la génération automatique des schémas de
+ base de données - directement dans la base de données. Cela peut bien sûr aussi être
+ désactivé (en supprimant l'option de configuration) ou redirigé vers un fichier avec
+ l'aide de la tâche Ant <literal>SchemaExport</literal>. Finalement, nous ajoutons
+ le(s) fichier(s) de mapping pour les classes persistantes.
+ </para>
+
+ <para>
+ Copiez ce fichier dans le répertoire source, il terminera dans la racine
+ du classpath. Hibernate cherchera automatiquement, au démarrage, un fichier appelé
+ <literal>hibernate.cfg.xml</literal> dans la racine du classpath.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-ant" revision="1">
+ <title>Construction avec Ant</title>
+
+ <para>
+ Nous allons maintenant construire le didacticiel avec Ant. Vous aurez besoin d'avoir Ant
+ d'installé - récupérez-le à partir de <ulink url="http://ant.apache.org/bindownload.cgi"> la page
+ de téléchargement de Ant</ulink>. Comment installer Ant ne sera pas couvert ici. Référez-vous
+ au <ulink url="http://ant.apache.org/manual/index.html">manuel d'Ant</ulink>. Après que
+ vous aurez installé Ant, nous pourrons commencer à créer le fichier de construction. Il
+ s'appellera <literal>build.xml</literal> et sera placé directement dans le répertoire de
+ développement.
+ </para>
+
+ <para>
+ Un fichier de construction basique ressemble à ça :
+ </para>
+
+ <programlisting><![CDATA[<project name="hibernate-tutorial" default="compile">
+
+ <property name="sourcedir" value="${basedir}/src"/>
+ <property name="targetdir" value="${basedir}/bin"/>
+ <property name="librarydir" value="${basedir}/lib"/>
+
+ <path id="libraries">
+ <fileset dir="${librarydir}">
+ <include name="*.jar"/>
+ </fileset>
+ </path>
+
+ <target name="clean">
+ <delete dir="${targetdir}"/>
+ <mkdir dir="${targetdir}"/>
+ </target>
+
+ <target name="compile" depends="clean, copy-resources">
+ <javac srcdir="${sourcedir}"
+ destdir="${targetdir}"
+ classpathref="libraries"/>
+ </target>
+
+ <target name="copy-resources">
+ <copy todir="${targetdir}">
+ <fileset dir="${sourcedir}">
+ <exclude name="**/*.java"/>
+ </fileset>
+ </copy>
+ </target>
+
+</project>]]></programlisting>
+
+ <para>
+ Cela dira à Ant d'ajouter tous les fichiers du répertoire lib finissant par
+ <literal>.jar</literal> dans le classpath utilisé pour la compilation. Cela copiera aussi
+ tous les fichiers source non Java dans le répertoire cible, par exemple les fichiers de
+ configuration et de mapping d'Hibernate. Si vous lancez Ant maintenant, vous devriez
+ obtenir cette sortie :
+ </para>
+
+ <programlisting><![CDATA[C:\hibernateTutorial\>ant
+Buildfile: build.xml
+
+copy-resources:
+ [copy] Copying 2 files to C:\hibernateTutorial\bin
+
+compile:
+ [javac] Compiling 1 source file to C:\hibernateTutorial\bin
+
+BUILD SUCCESSFUL
+Total time: 1 second ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-helpers" revision="3">
+ <title>Démarrage et aides</title>
+
+ <para>
+ Il est temps de charger et de stocker quelques objets <literal>Event</literal>,
+ mais d'abord nous devons compléter la configuration avec du code
+ d'infrastructure. Nous devons démarrer Hibernate. Ce démarrage inclut la construction
+ d'un objet <literal>SessionFactory</literal> global et le stocker quelque part
+ facile d'accès dans le code de l'application. Une <literal>SessionFactory</literal>
+ peut ouvrir des nouvelles <literal>Session</literal>s. Une <literal>Session</literal>
+ représente une unité de travail simplement "threadée", la <literal>SessionFactory</literal>
+ est un objet global "thread-safe", instancié une seule fois.
+ </para>
+
+ <para>
+ Nous créerons une classe d'aide <literal>HibernateUtil</literal> qui s'occupe du
+ démarrage et rend la gestion des <literal>Session</literal>s plus facile.
+ Regardons l'implémentation :
+ </para>
+
+ <programlisting><![CDATA[package util;
+
+import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+ public static final SessionFactory sessionFactory;
+
+ static {
+ try {
+ // Création de la SessionFactory à partir de hibernate.cfg.xml
+ sessionFactory = new Configuration().configure().buildSessionFactory();
+ } catch (Throwable ex) {
+ // Make sure you log the exception, as it might be swallowed
+ System.err.println("Initial SessionFactory creation failed." + ex);
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ public static final ThreadLocal session = new ThreadLocal();
+
+ public static SessionFactory getSessionFactory() {
+ return sessionFactory;
+ }
+}]]></programlisting>
+
+ <para>
+ Cette classe ne produit pas seulement la <literal>SessionFactory</literal> globale
+ dans un initialiseur statique (appelé une seule fois par la JVM lorsque la classe
+ est chargée), elle masque le fait qu'elle exploite un singleton. Elle pourrait aussi
+ obtenir la <literal>SessionFactory</literal> depuis JNDI dans un serveur d'applications.
+ </para>
+
+ <para>
+ Si vous nommez la <literal>SessionFactory</literal> dans votre fichier de configuration,
+ Hibernate tentera la récupération depuis JNDI. Pour éviter ce code, vous pouvez aussi
+ utiliser un déploiement JMX et laisser le conteneur (compatible JMX) instancier et lier
+ un <literal>HibernateService</literal> à JNDI. Ces options avancées sont détaillées dans
+ la documentation de référence Hibernate.
+ </para>
+
+ <para>
+ Placez <literal>HibernateUtil.java</literal> dans le répertoire source de développement,
+ et ensuite <literal>Event.java</literal> :
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ <Hibernate and third-party libraries>
++src
+ +events
+ Event.java
+ Event.hbm.xml
+ +util
+ HibernateUtil.java
+ hibernate.cfg.xml
++data
+build.xml]]></programlisting>
+
+ <para>
+ Cela devrait encore compiler sans problème. Nous avons finalement besoin de configurer
+ le système de "logs" - Hibernate utilise commons-logging et vous laisse le choix entre
+ log4j et le système de logs du JDK 1.4. La plupart des développeurs préfèrent log4j :
+ copiez <literal>log4j.properties</literal> de la distribution d'Hibernate (il est dans
+ le répertoire <literal>etc/</literal>) dans votre répertoire <literal>src</literal>,
+ puis faites de même avec <literal>hibernate.cfg.xml</literal>. Regardez la configuration
+ d'exemple et changez les paramètres si vous voulez une sortie plus verbeuse. Par défaut,
+ seul le message de démarrage d'Hibernate est affiché sur la sortie standard.
+ </para>
+
+ <para>
+ L'infrastructure de ce didacticiel est complète - et nous sommes prêts à effectuer un
+ travail réel avec Hibernate.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-workingpersistence" revision="4">
+ <title>Charger et stocker des objets</title>
+
+ <para>
+ Finalement nous pouvons utiliser Hibernate pour charger et stocker des objets.
+ Nous écrivons une classe <literal>EventManager</literal> avec une méthode
+ <literal>main()</literal> :
+ </para>
+
+ <programlisting><![CDATA[package events;
+import org.hibernate.Session;
+
+import java.util.Date;
+
+import util.HibernateUtil;
+
+public class EventManager {
+
+ public static void main(String[] args) {
+ EventManager mgr = new EventManager();
+
+ if (args[0].equals("store")) {
+ mgr.createAndStoreEvent("My Event", new Date());
+ }
+
+ HibernateUtil.getSessionFactory().close();
+ }
+
+ private void createAndStoreEvent(String title, Date theDate) {
+
+ Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+ session.beginTransaction();
+
+ Event theEvent = new Event();
+ theEvent.setTitle(title);
+ theEvent.setDate(theDate);
+
+ session.save(theEvent);
+
+ session.getTransaction().commit();
+ }]]></programlisting>
+
+ <para>
+ Nous créons un nouvel objet <literal>Event</literal>, et le remettons à Hibernate.
+ Hibernate s'occupe maintenant du SQL et exécute les <literal>INSERT</literal>s
+ dans la base de données. Regardons le code de gestion de la <literal>Session</literal>
+ et de la <literal>Transaction</literal> avant de lancer ça.
+ </para>
+
+ <para>
+ Une <literal>Session</literal> est une unité de travail. Pour le moment, nous allons faire
+ les choses simplement et assumer une granularité un-un entre une <literal>Session</literal>
+ hibernate et une transaction à la base de données. Pour isoler notre code du système de transaction
+ sous-jacent (dans notre cas, du pure JDBC, mais cela pourrait être JTA), nous utilisons l'API
+ <literal>Transaction</literal> qui est disponible depuis la <literal>Session</literal> Hibernate.
+ </para>
+
+ <para>
+ Que fait <literal>sessionFactory.getCurrentSession()</literal> ? Premièrement, vous pouvez
+ l'invoquer autant de fois que vous le voulez et n'importe où du moment que vous avez votre
+ <literal>SessionFactory</literal> (facile grâce à <literal>HibernateUtil</literal>).
+ 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
+ <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
+ (commit ou rollback), Hibernate délie la <literal>Session</literal> du thread et la ferme
+ pour vous. Si vous invoquez <literal>getCurrentSession()</literal> une autre fois, vous obtenez
+ une nouvelle <literal>Session</literal> et pouvez entamer une nouvelle unité de travail.
+ Ce modèle de programmation "<emphasis>thread-bound</emphasis>" est le moyen le plus
+ populaire d'utiliser Hibernate.
+ </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.
+ </para>
+
+ <para>
+ Pour lancer cette première routine, nous devons ajouter une cible appelable dans
+ le fichier de construction de Ant :
+ </para>
+
+ <programlisting><![CDATA[<target name="run" depends="compile">
+ <java fork="true" classname="events.EventManager" classpathref="libraries">
+ <classpath path="${targetdir}"/>
+ <arg value="${action}"/>
+ </java>
+</target>]]></programlisting>
+
+ <para>
+ La valeur de l'argument <literal>action</literal> correspond à la ligne de commande
+ qui appelle la cible :
+ </para>
+
+ <programlisting><![CDATA[C:\hibernateTutorial\>ant run -Daction=store]]></programlisting>
+
+ <para>
+ Vous devriez voir, après la compilation, Hibernate démarrer et, en fonction de votre
+ configuration, beaucoup de traces sur la sortie. À la fin vous trouverez la ligne suivante :
+ </para>
+
+ <programlisting><![CDATA[[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)]]></programlisting>
+
+ <para>
+ C'est l'<literal>INSERT</literal> exécuté par Hibernate, les points d'interrogation
+ représentent les paramètres JDBC liés. Pour voir les valeurs liées aux arguments, ou
+ pour réduire la verbosité des traces, vérifier votre <literal>log4j.properties</literal>.
+ </para>
+
+ <para>
+ Maintenant nous aimerions aussi lister les événements stockés, donc nous ajoutons une
+ option à la méthode principale :
+ </para>
+
+ <programlisting><![CDATA[if (args[0].equals("store")) {
+ mgr.createAndStoreEvent("My Event", new Date());
+}
+else if (args[0].equals("list")) {
+ List events = mgr.listEvents();
+ for (int i = 0; i < events.size(); i++) {
+ Event theEvent = (Event) events.get(i);
+ System.out.println("Event: " + theEvent.getTitle() +
+ " Time: " + theEvent.getDate());
+ }
+}]]></programlisting>
+
+ <para>
+ Nous ajoutons aussi une nouvelle méthode <literal>listEvents()</literal> :
+ </para>
+
+ <programlisting><![CDATA[private List listEvents() {
+
+ Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+ session.beginTransaction();
+
+ List result = session.createQuery("from Event").list();
+
+ session.getTransaction().commit();
+
+ return result;
+}]]></programlisting>
+
+ <para>
+ Ce que nous faisons ici c'est utiliser une requête HQL (Hibernate Query Language) pour
+ charger tous les objets <literal>Event</literal> existants de la base de données.
+ Hibernate générera le SQL approprié, l'enverra à la base de données et peuplera des
+ objets <literal>Event</literal> avec les données. Vous pouvez créer des requêtes plus
+ complexes avec HQL, bien sûr.
+ </para>
+
+ <para>
+ Maintenant, pour exécuter et tester tout ça, suivez ces étapes :
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Exécutez <literal>ant run -Daction=store</literal> pour stocker quelque
+ chose dans la base de données et, bien sûr, pour générer, avant, le schéma
+ de la base de données grâce à hbm2ddl.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Maintenant désactivez hbm2ddl en commentant la propriété dans votre fichier
+ <literal>hibernate.cfg.xml</literal>. Généralement vous la laissez seulement
+ activée dans des tests unitaires en continu, mais une autre exécution de hbm2ddl
+ <emphasis>effacerait</emphasis> tout ce que vous avez stocké - le paramètre de
+ configuration <literal>create</literal> se traduit en fait par "supprimer toutes les
+ tables du schéma, puis re-créer toutes les tables, lorsque la SessionFactory est
+ construite".
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Si maintenant vous appelez Ant avec <literal>-Daction=list</literal>, vous devriez voir
+ 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>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="tutorial-associations">
+ <title>Partie 2 - Mapper des associations</title>
+
+ <para>
+ Nous avons mappé une classe d'une entité persistante vers une table. Partons de là et
+ ajoutons quelques associations de classe. D'abord nous ajouterons des gens à notre
+ application, et stockerons une liste d'événements auxquels ils participent.
+ </para>
+
+ <sect2 id="tutorial-associations-mappinguser" revision="1">
+ <title>Mapper la classe Person</title>
+
+ <para>
+ La première version de la classe <literal>Person</literal> est simple :
+ </para>
+
+ <programlisting><![CDATA[package events;
+
+public class Person {
+
+ private Long id;
+ private int age;
+ private String firstname;
+ private String lastname;
+
+ public Person() {}
+
+ // Accessor methods for all properties, private setter for 'id'
+
+}]]></programlisting>
+
+ <para>
+ Créez un nouveau fichier de mapping appelé <literal>Person.hbm.xml</literal>
+ (n'oubliez pas la référence à la DTD)
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="events.Person" table="PERSON">
+ <id name="id" column="PERSON_ID">
+ <generator class="native"/>
+ </id>
+ <property name="age"/>
+ <property name="firstname"/>
+ <property name="lastname"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Finalement, ajoutez la nouveau mapping à la configuration d'Hibernate :
+ </para>
+
+ <programlisting><![CDATA[<mapping resource="events/Event.hbm.xml"/>
+<mapping resource="events/Person.hbm.xml"/>]]></programlisting>
+ <para>
+ Nous allons maintenant créer une association entre ces deux entités. Évidemment,
+ des personnes peuvent participer aux événements, et des événements ont des participants.
+ Les questions de conception que nous devons traiter sont : direction, cardinalité et comportement
+ de la collection.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-unidirset" revision="2">
+ <title>Une association unidirectionnelle basée sur Set</title>
+
+ <para>
+ Nous allons ajouter une collection d'événements à la classe <literal>Person</literal>. De
+ cette manière nous pouvons facilement naviguer dans les événements d'une personne
+ particulière, sans exécuter une requête explicite - en appelant
+ <literal>aPerson.getEvents()</literal>. Nous utilisons une collection Java, un
+ <literal>Set</literal>, parce que la collection ne contiendra pas d'éléments dupliqués et
+ l'ordre ne nous importe pas.
+ </para>
+
+ <para>
+ Nous avons besoin d'une association unidirectionnelle, pluri-valuée, implémentée avec
+ un <literal>Set</literal>. Écrivons le code pour ça dans les classes Java et mappons les :
+ </para>
+
+ <programlisting><![CDATA[public class Person {
+
+ private Set events = new HashSet();
+
+ public Set getEvents() {
+ return events;
+ }
+
+ public void setEvents(Set events) {
+ this.events = events;
+ }
+}]]></programlisting>
+
+ <para>
+ D'abord nous mappons cette association, mais pensez à l'autre côté. Clairement, nous pouvons
+ la laisser unidirectionnelle. Ou alors, nous pourrions créer une autre collection sur
+ <literal>Event</literal>, si nous voulons être capable de la parcourir de manière
+ bidirectionnelle, c'est-à-dire avoir <literal>anEvent.getParticipants()</literal>.
+ Ce n'est pas nécessaire d'un point de vue fonctionnel. Vous pourrez toujours exécuter une requête
+ explicite pour récupérer les participants d'un "event" particulier. Ce choix de conception
+ vous est laissé, mais ce qui reste certains est la cardinalité de l'association: "plusieurs"
+ des deux côtés, nous appelons cela une association <emphasis>many-to-many</emphasis>.
+ Par conséquent nous utilisons un mapping Hibernate many-to-many:
+ </para>
+
+ <programlisting><![CDATA[<class name="events.Person" table="PERSON">
+ <id name="id" column="PERSON_ID">
+ <generator class="native"/>
+ </id>
+ <property name="age"/>
+ <property name="firstname"/>
+ <property name="lastname"/>
+
+ <set name="events" table="PERSON_EVENT">
+ <key column="PERSON_ID"/>
+ <many-to-many column="EVENT_ID" class="Event"/>
+ </set>
+
+</class>]]></programlisting>
+
+ <para>
+ Hibernate supporte toutes sortes de mapping de collection, un <literal><set></literal>
+ étant le plus commun. Pour une association many-to-many (ou une relation
+ d'entité <emphasis>n:m</emphasis>), une table d'association est requise. Chaque ligne dans cette table représente un lien entre une personne et un événement. Le nom de la table est
+ configuré avec l'attribut <literal>table</literal> de l'élément <literal>set</literal>. Le
+ nom de la colonne identifiant dans l'association, du côté de la personne, est défini avec
+ l'élément <literal><key></literal>, et le nom de la colonne pour l'événement dans
+ l'attribut <literal>column</literal> de <literal><many-to-many></literal>. Vous
+ devez aussi donner à Hibernate la classe des objets de votre collection (c'est-à-dire : la
+ classe de l'autre côté de la collection).
+ </para>
+
+ <para>
+ Le schéma de base de données pour ce mapping est donc :
+ </para>
+
+ <programlisting><![CDATA[
+ _____________ __________________
+ | | | | _____________
+ | EVENTS | | PERSON_EVENT | | |
+ |_____________| |__________________| | PERSON |
+ | | | | |_____________|
+ | *EVENT_ID | <--> | *EVENT_ID | | |
+ | EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID |
+ | TITLE | |__________________| | AGE |
+ |_____________| | FIRSTNAME |
+ | LASTNAME |
+ |_____________|
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-working" revision="1">
+ <title>Travailler avec l'association</title>
+
+ <para>
+ Réunissons quelques personnes et quelques événements dans une nouvelle méthode dans
+ <literal>EventManager</literal> :
+ </para>
+
+ <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+ Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+ session.beginTransaction();
+
+ Person aPerson = (Person) session.load(Person.class, personId);
+ Event anEvent = (Event) session.load(Event.class, eventId);
+
+ aPerson.getEvents().add(anEvent);
+
+ session.getTransaction().commit();
+}]]></programlisting>
+
+ <para>
+ Après le chargement d'une <literal>Person</literal> et d'un <literal>Event</literal>, modifiez
+ simplement la collection en utilisant les méthodes normales de la collection. Comme vous
+ pouvez le voir, il n'y a pas d'appel explicite à <literal>update()</literal> ou
+ <literal>save()</literal>, Hibernate détecte automatiquement que la collection a été
+ modifiée et a besoin d'être mise à jour. Ceci est appelé <emphasis>la vérification sale
+ automatique</emphasis> (NdT : "automatic dirty checking"), et vous pouvez aussi l'essayer en
+ modifiant le nom ou la propriété date de n'importe lequel de vos objets. Tant qu'ils sont dans
+ un état <emphasis>persistant</emphasis>, c'est-à-dire, liés à une <literal>Session</literal> Hibernate
+ particulière (c-à-d qu'ils ont juste été chargés ou sauvegardés dans une unité de travail),
+ Hibernate surveille les changements et exécute le SQL correspondant. Le processus de
+ synchronisation de l'état de la mémoire avec la base de données, généralement seulement à la fin
+ d'une unité de travail, est appelé <emphasis>flushing</emphasis>. Dans notre code, l'unité de travail
+ s'achève par un commit (ou rollback) de la transaction avec la base de données - comme défini
+ par notre option <literal>thread</literal> de configuration pour la classe <literal>CurrentSessionContext</literal>.
+ </para>
+
+ <para>
+ Vous pourriez bien sûr charger une personne et un événement dans différentes unités de travail. Ou
+ vous modifiez un objet à l'extérieur d'une <literal>Session</literal>, s'il n'est pas dans un état
+ persistant (s'il était persistant avant, nous appelons cet état <emphasis>détaché</emphasis>).
+ Vous pouvez même modifier une collection lorsqu'elle est détachée:
+ </para>
+
+ <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+
+ Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+ session.beginTransaction();
+
+ Person aPerson = (Person) session
+ .createQuery("select p from Person p left join fetch p.events where p.id = :pid")
+ .setParameter("pid", personId)
+ .uniqueResult(); // Eager fetch the collection so we can use it detached
+
+ Event anEvent = (Event) session.load(Event.class, eventId);
+
+ session.getTransaction().commit();
+
+ // End of first unit of work
+
+ aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached
+
+ // Begin second unit of work
+
+ Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
+ session2.beginTransaction();
+
+ session2.update(aPerson); // Reattachment of aPerson
+
+ session2.getTransaction().commit();
+}]]></programlisting>
+
+ <para>
+ L'appel à <literal>update</literal> rend un objet détaché à nouveau persistant, vous pourriez
+ dire qu'il le lie à une unité de travail, ainsi toutes les modifications (ajout, suppression) que vous avez faites
+ pendant qu'il était détaché peuvent être sauvegardées dans la base de données
+ (il se peut que vous ayez besoin de modifier quelques unes des méthodes précédentes
+ pour retourner cet identifiant).
+ </para>
+
+ <programlisting><![CDATA[else if (args[0].equals("addpersontoevent")) {
+ Long eventId = mgr.createAndStoreEvent("My Event", new Date());
+ Long personId = mgr.createAndStorePerson("Foo", "Bar");
+ mgr.addPersonToEvent(personId, eventId);
+ System.out.println("Added person " + personId + " to event " + eventId);]]></programlisting>
+
+ <para>
+ Ce n'est pas très utile dans notre situation actuelle, mais c'est un concept important
+ que vous pouvez mettre dans votre propre application.
+ Pour le moment, complétez cet exercice en ajoutant une nouvelle action à la méthode
+ principale des <literal>EventManager</literal>s et appelez la à partir de la ligne de
+ commande. Si vous avez besoin des identifiants d'une personne et d'un événement - la
+ méthode <literal>save()</literal> les retourne.
+ </para>
+
+ <para>
+ C'était un exemple d'une association entre deux classes de même importance, deux entités.
+ Comme mentionné plus tôt, il y a d'autres classes et d'autres types dans un modèle typique,
+ généralement "moins importants". Vous en avez déjà vu certains, comme un <literal>int</literal>
+ ou une <literal>String</literal>. Nous appelons ces classes des <emphasis>types de valeur</emphasis>,
+ et leurs instances <emphasis>dépendent</emphasis> d'une entité particulière. Des instances de ces
+ types n'ont pas leur propre identité, elles ne sont pas non plus partagées entre des entités (deux
+ personnes ne référencent pas le même objet <literal>firstname</literal>, même si elles ont le
+ même prénom). Bien sûr, des types de valeur ne peuvent pas seulement être trouvés dans
+ le JDK (en fait, dans une application Hibernate toutes les classes du JDK sont considérées
+ comme des types de valeur), vous pouvez aussi écrire vous-même des classes dépendantes,
+ <literal>Address</literal> ou <literal>MonetaryAmount</literal>, par exemple.
+ </para>
+
+ <para>
+ Vous pouvez aussi concevoir une collection de types de valeur. C'est conceptuellement très
+ différent d'une collection de références vers d'autres entités, mais très ressemblant en Java.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-valuecollections">
+ <title>Collection de valeurs</title>
+
+ <para>
+ Nous ajoutons une collection d'objets de type de valeur à l'entité <literal>Person</literal>.
+ Nous voulons stocker des adresses email, donc le type que nous utilisons est <literal>String</literal>,
+ et la collection est encore un <literal>Set</literal> :
+ </para>
+ <programlisting><![CDATA[private Set emailAddresses = new HashSet();
+
+public Set getEmailAddresses() {
+ return emailAddresses;
+}
+
+public void setEmailAddresses(Set emailAddresses) {
+ this.emailAddresses = emailAddresses;
+}]]></programlisting>
+
+ <para>
+ Le mapping de ce <literal>Set</literal> :
+ </para>
+
+ <programlisting><![CDATA[<set name="emailAddresses" table="PERSON_EMAIL_ADDR">
+ <key column="PERSON_ID"/>
+ <element type="string" column="EMAIL_ADDR"/>
+</set>]]></programlisting>
+
+ <para>
+ La différence comparée au mapping vu plus tôt est la partie <literal>element</literal>,
+ laquelle dit à Hibernate que la collection ne contient pas de références vers une autre entité,
+ mais une collection d'éléments de type <literal>String</literal> (le nom en minuscule vous
+ indique que c'est un type/convertisseur du mapping Hibernate). Une fois encore, l'attribut
+ <literal>table</literal> de l'élément <literal>set</literal> détermine le nom de la table pour la
+ collection. L'élément <literal>key</literal> définit le nom de la colonne de la clef étrangère
+ dans la table de la collection. L'attribut <literal>column</literal> dans l'élément
+ <literal>element</literal> définit le nom de la colonne où les valeurs de <literal>String</literal>
+ seront réellement stockées.
+ </para>
+
+ <para>
+ Regardons le schéma mis à jour :
+ </para>
+
+ <programlisting><![CDATA[
+ _____________ __________________
+ | | | | _____________
+ | EVENTS | | PERSON_EVENT | | | ___________________
+ |_____________| |__________________| | PERSON | | |
+ | | | | |_____________| | PERSON_EMAIL_ADDR |
+ | *EVENT_ID | <--> | *EVENT_ID | | | |___________________|
+ | EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID | <--> | *PERSON_ID |
+ | TITLE | |__________________| | AGE | | *EMAIL_ADDR |
+ |_____________| | FIRSTNAME | |___________________|
+ | LASTNAME |
+ |_____________|
+ ]]></programlisting>
+
+ <para>
+ Vous pouvez voir que la clef primaire de la table de la collection est en fait une
+ clef composée, utilisant deux colonnes. Ceci implique aussi qu'il ne peut pas y avoir
+ d'adresses email dupliquées par personne, ce qui est exactement la sémantique dont
+ nous avons besoin pour un ensemble en Java.
+ </para>
+
+ <para>
+ Vous pouvez maintenant tester et ajouter des éléments à cette collection, juste comme
+ nous l'avons fait avant en liant des personnes et des événements. C'est le même code
+ en Java.
+ </para>
+
+ <programlisting><![CDATA[private void addEmailToPerson(Long personId, String emailAddress) {
+
+ Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+ session.beginTransaction();
+
+ Person aPerson = (Person) session.load(Person.class, personId);
+
+ // The getEmailAddresses() might trigger a lazy load of the collection
+ aPerson.getEmailAddresses().add(emailAddress);
+
+ session.getTransaction().commit();
+}]]></programlisting>
+
+ <para>
+ Cette fois ci, nous n'avons pas utilisé une requête de chargement agressif (<emphasis>fetch</emphasis>)
+ pour initialiser la collection. Par conséquent, l'invocation du getter déclenchera un
+ select supplémentaire pour l'initialiser. Traquez les logs SQL et tentez d'optimiser
+ ce cas avec un chargement aggressif.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-bidirectional" revision="1">
+ <title>Associations bidirectionnelles</title>
+
+ <para>
+ Ensuite nous allons mapper une association bidirectionnelle - faire fonctionner
+ l'association entre une personne et un événement à partir des deux côtés en Java.
+ Bien sûr, le schéma de la base de données ne change pas, nous avons toujours une pluralité
+ many-to-many. Une base de données relationnelle est plus flexible qu'un langage de
+ programmation réseau, donc elle n'a pas besoin de direction de navigation - les données
+ peuvent être vues et récupérées de toutes les manières possibles.
+ </para>
+
+ <para>
+ D'abord, ajouter une collection de participants à la classe <literal>Event</literal> :
+ </para>
+
+ <programlisting><![CDATA[private Set participants = new HashSet();
+
+public Set getParticipants() {
+ return participants;
+}
+
+public void setParticipants(Set participants) {
+ this.participants = participants;
+}]]></programlisting>
+
+ <para>
+ Maintenant mapper ce côté de l'association aussi, dans <literal>Event.hbm.xml</literal>.
+ </para>
+
+ <programlisting><![CDATA[<set name="participants" table="PERSON_EVENT" inverse="true">
+ <key column="EVENT_ID"/>
+ <many-to-many column="PERSON_ID" class="events.Person"/>
+</set>]]></programlisting>
+
+ <para>
+ Comme vous le voyez, ce sont des mappings de <literal>set</literal>s normaux dans les
+ deux documents de mapping. Notez que les noms de colonne dans <literal>key</literal> et
+ <literal>many-to-many</literal> sont inversés dans les 2 documents de mapping. L'ajout
+ le plus important ici est l'attribut <literal>inverse="true"</literal> dans l'élément
+ <literal>set</literal> du mapping de la collection des <literal>Event</literal>s.
+ </para>
+
+ <para>
+ Ce que signifie qu'Hibernate devrait prendre l'autre côté - la classe <literal>Person</literal> -
+ s'il a besoin de renseigner des informations à propos du lien entre les deux. Ce sera
+ beaucoup plus facile à comprendre une fois que vous verrez comment le lien bidirectionnel
+ entre les deux entités est créé.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-usingbidir">
+ <title>Travailler avec des liens bidirectionnels</title>
+
+ <para>
+ Premièrement, gardez à l'esprit qu'Hibernate n'affecte pas la sémantique normale de Java.
+ Comment avons-nous créé un lien entre une <literal>Person</literal> et un <literal>Event</literal>
+ dans l'exemple unidirectionnel ? Nous avons ajouté une instance de <literal>Event</literal>
+ à la collection des références d'événement d'une instance de <literal>Person</literal>. Donc,
+ évidemment, si vous voulons rendre ce lien bidirectionnel, nous devons faire la même chose de
+ l'autre côté - ajouter une référence de <literal>Person</literal> à la collection d'un
+ <literal>Event</literal>. Cette "configuration du lien des deux côtés" est absolument
+ nécessaire et vous ne devriez jamais oublier de le faire.
+ </para>
+
+ <para>
+ Beaucoup de développeurs programment de manière défensive et créent des
+ méthodes de gestion de lien pour affecter correctement les deux côtés,
+ par exemple dans <literal>Person</literal> :
+ </para>
+
+ <programlisting><![CDATA[protected Set getEvents() {
+ return events;
+}
+
+protected void setEvents(Set events) {
+ this.events = events;
+}
+
+public void addToEvent(Event event) {
+ this.getEvents().add(event);
+ event.getParticipants().add(this);
+}
+
+public void removeFromEvent(Event event) {
+ this.getEvents().remove(event);
+ event.getParticipants().remove(this);
+}]]></programlisting>
+
+ <para>
+ Notez que les méthodes get et set pour la collection sont maintenant protégées - ceci permet à des
+ classes du même paquet et aux sous-classes d'accéder encore aux méthodes, mais empêche n'importe qui
+ d'autre de mettre le désordre directement dans les collections (enfin, presque). Vous devriez
+ probablement faire de même avec la collection de l'autre côté.
+ </para>
+
+ <para>
+ Et à propos de l'attribut de mapping <literal>inverse</literal> ? Pour vous, et pour Java, un lien
+ bidirectionnel est simplement une manière de configurer correctement les références des deux côtés.
+ Hibernate n'a cependant pas assez d'informations pour ordonner correctement les expressions SQL
+ <literal>INSERT</literal> et <literal>UPDATE</literal> (pour éviter les violations de contrainte), et
+ a besoin d'aide pour gérer proprement les associations bidirectionnelles. Rendre
+ <literal>inverse</literal> un côté d'une assocation dit à Hibernate de l'ignorer essentiellement, pour
+ le considérer comme un <emphasis>miroir</emphasis> de l'autre côté. C'est tout ce qui est nécessaire à
+ Hibernate pour découvrir tout des problèmes de transformation d'un modèle de navigation
+ directionnelle vers un schéma SQL de base de données. Les règles dont vous devez vous souvenir sont :
+ toutes les associations bidirectionnelles ont besoin d'un côté marqué <literal>inverse</literal>.
+ Dans une association un-vers-plusieurs vous pouvez choisir n'importe quel côté, il n'y a pas de
+ différence.
+ </para>
+<!--
+ <para>
+ In the next section we integrate Hibernate with Tomcat and WebWork - the <literal>EventManager</literal>
+ doesn't scale anymore with our growing application.
+ </para>
+-->
+ </sect2>
+ </sect1>
+
+ <sect1 id="tutorial-webapp">
+ <title>Part 3 - L'application web EventManager</title>
+
+ <para>
+ Une application web Hibernate utilise la <literal>Session</literal> et <literal>Transaction</literal>
+ comme une application standalone. Cependant, quelques patterns sont utiles. Nous allons coder une
+ <literal>EventManagerServlet</literal>. Cette servlet peut lister tous les évènements stockés dans
+ la base de données, et fournir une formulaire HTML pour saisir d'autres évènements.
+ </para>
+
+ <sect2 id="tutorial-webapp-servlet">
+ <title>Ecrire la servlet de base</title>
+
+ <para>
+ 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>:
+ </para>
+
+ <programlisting><![CDATA[protected void doGet(HttpServletRequest request,
+ HttpServletResponse response)
+ throws ServletException, IOException {
+
+ try {
+ // Begin unit of work
+ HibernateUtil.getSessionFactory()
+ .getCurrentSession().beginTransaction();
+
+ // Process request and render page...
+
+ // End unit of work
+ HibernateUtil.getSessionFactory()
+ .getCurrentSession().getTransaction().commit();
+
+ } catch (Exception ex) {
+ HibernateUtil.getSessionFactory()
+ .getCurrentSession().getTransaction().rollback();
+ throw new ServletException(ex);
+ }
+
+}]]></programlisting>
+
+ <para>
+ La pattern que nous utilisons ici est appelé <emphasis>session-per-request</emphasis>.
+ Lorsqu'une requête touche la servlet, une nouvelle <literal>Session</literal> hibernate est
+ ouverte à l'invocationde <literal>getCurrentSession()</literal> sur la
+ <literal>SessionFactory</literal>. Ensuite, une transaction avec la base de données est démarrée—
+ 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>
+ Ensuite, les actions possibles de la requêtes sont exécutées et la réponse HTML
+ est rendue. Nous en parlerons plus tard.
+ </para>
+
+ <para>
+ Enfin, l'unité de travail s'achève lorsque l'exécution et le rendu sont achevés.
+ Si un problème survient lors de ces deux phases, une exception est soulevée et la
+ transaction avec la base de données subit un rollback. Voila pour le pattern
+ <literal>session-per-request</literal>. Au lieu d'un code de démarcation de transaction
+ au sein de chaque servlet, vous pouvez écrire un filtre de servlet.
+ Voir le site Hibernate et le Wiki pour plus d'information sur ce pattern, appelé
+ <emphasis>Open Session in View</emphasis>— vous en aurez besoin dès que vous
+ utiliserez des JSPs et non plus des servlets pour le rendu de vos vues.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-webapp-processing">
+ <title>Procéder et rendre</title>
+
+ <para>
+ Implémentons l'exécution de la requête et le rendu de la page.
+ </para>
+
+<programlisting><![CDATA[// Write HTML header
+PrintWriter out = response.getWriter();
+out.println("<html><head><title>Event Manager</title></head><body>");
+
+// Handle actions
+if ( "store".equals(request.getParameter("action")) ) {
+
+ String eventTitle = request.getParameter("eventTitle");
+ String eventDate = request.getParameter("eventDate");
+
+ if ( "".equals(eventTitle) || "".equals(eventDate) ) {
+ out.println("<b><i>Please enter event title and date.</i></b>");
+ } else {
+ createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
+ out.println("<b><i>Added event.</i></b>");
+ }
+}
+
+// Print page
+printEventForm(out);
+listEvents(out);
+
+// Write HTML footer
+out.println("</body></html>");
+out.flush();
+out.close();]]></programlisting>
+
+ <para>
+ Ce style de code avec un mix de Java et d'HTML ne serait pas scalable
+ dans une application plus complexe—gardez à l'esprit que nous ne faisons qu'illustrer
+ les concepts basiques d'Hibernate dans ce tutoriel. Ce code affiche une en tête et un pied de page
+ HTML. Dans cette page, sont affichés un formulaire pour la saisie d'évènements ainsi
+ qu'une liste de tous les évènements de la base de données. La première méthode
+ est triviale est ne fait que sortir de l'HTML:
+ </para>
+
+ <programlisting><![CDATA[private void printEventForm(PrintWriter out) {
+ out.println("<h2>Add new event:</h2>");
+ out.println("<form>");
+ out.println("Title: <input name='eventTitle' length='50'/><br/>");
+ out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>");
+ out.println("<input type='submit' name='action' value='store'/>");
+ out.println("</form>");
+}]]></programlisting>
+
+ <para>
+ La méthode <literal>listEvents()</literal> utilise la
+ <literal>Session</literal> Hibernate liée au thread courant pour exécuter la
+ requête:
+ </para>
+
+ <programlisting><![CDATA[private void listEvents(PrintWriter out) {
+ List result = HibernateUtil.getSessionFactory()
+ .getCurrentSession().createCriteria(Event.class).list();
+ if (result.size() > 0) {
+ out.println("<h2>Events in database:</h2>");
+ out.println("<table border='1'>");
+ out.println("<tr>");
+ out.println("<th>Event title</th>");
+ out.println("<th>Event date</th>");
+ out.println("</tr>");
+ for (Iterator it = result.iterator(); it.hasNext();) {
+ Event event = (Event) it.next();
+ out.println("<tr>");
+ out.println("<td>" + event.getTitle() + "</td>");
+ out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");
+ out.println("</tr>");
+ }
+ out.println("</table>");
+ }
+}]]></programlisting>
+
+ <para>
+ FEnfin, l'action <literal>store</literal> renvoie à la méthode
+ <literal>createAndStoreEvent()</literal>, qui utilise aussi la
+ <literal>Session</literal> du thread courant:
+ </para>
+
+ <programlisting><![CDATA[protected void createAndStoreEvent(String title, Date theDate) {
+ Event theEvent = new Event();
+ theEvent.setTitle(title);
+ theEvent.setDate(theDate);
+
+ HibernateUtil.getSessionFactory()
+ .getCurrentSession().save(theEvent);
+}]]></programlisting>
+
+ <para>
+ La servlet est faite. Une requête à la servlet sera exécutée par une seule
+ <literal>Session</literal> et <literal>Transaction</literal>. Comme pour une application
+ standalone, Hibernate peut automatiquement lier ces objets au thread courant d'exécution.
+ Cela vous laisse la liberté de séparer votre code en couches et d'accéder à la
+ <literal>SessionFactory</literal> par le moyen que vous voulez.
+ Généralement, vous utiliserez des conceptions plus sophistiquées et déplacerez
+ le code d'accès aux données dans une couche DAO. Voir le wiki Hibernate pour plus
+ d'exemples.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-webapp-deploy">
+ <title>Déployer et tester</title>
+
+ <para>
+ Pour déployer cette application, vous devez créer une archive Web, un War. Ajoutez
+ la cible Ant suivante dans votre <literal>build.xml</literal>:
+ </para>
+
+<programlisting><![CDATA[<target name="war" depends="compile">
+ <war destfile="hibernate-tutorial.war" webxml="web.xml">
+ <lib dir="${librarydir}">
+ <exclude name="jsdk*.jar"/>
+ </lib>
+
+ <classes dir="${targetdir}"/>
+ </war>
+</target>]]></programlisting>
+
+ <para>
+ Cette cible créé un fichier nommé <literal>hibernate-tutorial.war</literal>
+ dans le répertoire de votre projet. Elle package les bibliothèques et le descripteur <literal>web.xml</literal>
+ qui est attendu dans le répertoire racine de votre projet:
+ </para>
+
+ <programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4"
+ xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+ <servlet>
+ <servlet-name>Event Manager</servlet-name>
+ <servlet-class>events.EventManagerServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Event Manager</servlet-name>
+ <url-pattern>/eventmanager</url-pattern>
+ </servlet-mapping>
+</web-app>]]></programlisting>
+
+ <para>
+ Avant de compiler et déployer l'application web, notez qu'une bibliothèque supplémentaire
+ est requise: <literal>jsdk.jar</literal>. C'est le kit de développement de Servlet Java,
+ si vous ne disposez pas de cette bibliothèque, prenez la sur le site de Sun et copiez la
+ dans votre répertoire des bibliothèques. Cependant, elle ne sera utilisée uniquement pour la
+ compilation et sera exclue du paackage WAR.
+ </para>
+
+ <para>
+ Pour construire et déployer, appelez <literal>ant war</literal> dans votre projet et
+ copier le fichier <literal>hibernate-tutorial.war</literal> dans le répertoire <literal>webapp</literal> de tomcat
+ Si vous n'avez pas installé Tomcat, téléchargez le et suivez la notice d'installation.
+ Vous n'avez pas à modifier la configuration Tomcat pour déployer cette application.
+ </para>
+
+ <para>
+ Une fois l'application déployée et Tomcat lancé, accédez à l'application via
+ <literal>http://localhost:8080/hibernate-tutorial/eventmanager</literal>.
+ Assurez vous de consulter les traces tomcat pour observer l'initialisation
+ d'Hibernate à la première requête touchant votre servlet (l'initialisation statique dans <literal>HibernateUtil</literal>
+ est invoquée) et pour vérifier qu'aucune exception ne survienne.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="tutorial-summary" revision="1">
+ <title>Résumé</title>
+
+ <para>
+ Ce didacticiel a couvert les bases de l'écriture d'une simple application Hibernate ainsi qu'une petite application web.
+ </para>
+
+ <para>
+ Si vous êtes déjà confiants avec Hibernate, continuez à parcourir les sujets que vous trouvez
+ intéressants à travers la table des matières de la documentation de référence - les plus
+ demandés sont le traitement transactionnel (<xref linkend="transactions"/>), la performance
+ des récupérations d'information (<xref linkend="performance"/>), ou l'utilisation de l'API
+ (<xref linkend="objectstate"/>) et les fonctionnalités des requêtes (<xref linkend="objectstate-querying"/>).
+ </para>
+
+ <para>
+ N'oubliez pas de vérifier le site web d'Hibernate pour d'autres didacticiels (plus spécialisés).
+ </para>
+
+ </sect1>
+
+</chapter>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/xml.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/xml.xml (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/docbook/modules/xml.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,292 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<chapter id="xml">
+ <title>Mapping XML</title>
+
+ <para><emphasis>
+ Notez que cette fonctionnalité est expérimentale dans Hibernate 3.0 et
+ est en développement extrêmement actif.
+ </emphasis></para>
+
+ <sect1 id="xml-intro" revision="1">
+ <title>Travailler avec des données XML</title>
+
+ <para>
+ Hibernate vous laisse travailler avec des données XML persistantes de la
+ même manière que vous travaillez avec des POJOs persistants. Un arbre XML
+ peut être vu comme une autre manière de représenter les données relationnelles
+ au niveau objet, à la place des POJOs.
+ </para>
+
+ <para>
+ Hibernate supporte dom4j en tant qu'API pour la manipulation des arbres XML.
+ Vous pouvez écrire des requêtes qui récupèrent des arbres dom4j à partie de la
+ base de données, et avoir toutes les modifications que vous faites sur l'arbre
+ automatiquement synchronisées dans la base de données. Vous pouvez même prendre
+ un document XML, l'analyser en utilisant dom4j, et l'écrire dans la base de
+ données via les opérations basiques d'Hibernate :
+ <literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal>
+ (merge() n'est pas encore supporté).
+ </para>
+
+ <para>
+ Cette fonctionnalité a plusieurs applications dont l'import/export de données,
+ l'externalisation d'entités via JMS ou SOAP et les rapports XSLT.
+ </para>
+
+ <para>
+ Un simple mapping peut être utilisé pour simultanément mapper les propriétés
+ d'une classe et les noeuds d'un document XML vers la base de données, ou,
+ si il n'y a pas de classe à mapper, il peut être utilisé juste pour mapper
+ le XML.
+ </para>
+
+ <sect2 id="xml-intro-mapping">
+ <title>Spécifier le mapping XML et le mapping d'une classe ensemble</title>
+
+ <para>
+ Voici un exemple de mapping d'un POJO et du XML simultanément :
+ </para>
+
+ <programlisting><![CDATA[<class name="Account"
+ table="ACCOUNTS"
+ node="account">
+
+ <id name="accountId"
+ column="ACCOUNT_ID"
+ node="@id"/>
+
+ <many-to-one name="customer"
+ column="CUSTOMER_ID"
+ node="customer/@id"
+ embed-xml="false"/>
+
+ <property name="balance"
+ column="BALANCE"
+ node="balance"/>
+
+ ...
+
+</class>]]></programlisting>
+ </sect2>
+
+ <sect2 id="xml-onlyxml">
+ <title>Spécifier seulement un mapping XML</title>
+
+ <para>
+ Voici un exemple dans lequel il n'y a pas de class POJO :
+ </para>
+
+ <programlisting><![CDATA[<class entity-name="Account"
+ table="ACCOUNTS"
+ node="account">
+
+ <id name="id"
+ column="ACCOUNT_ID"
+ node="@id"
+ type="string"/>
+
+ <many-to-one name="customerId"
+ column="CUSTOMER_ID"
+ node="customer/@id"
+ embed-xml="false"
+ entity-name="Customer"/>
+
+ <property name="balance"
+ column="BALANCE"
+ node="balance"
+ type="big_decimal"/>
+
+ ...
+
+</class>]]></programlisting>
+
+ <para>
+ Ce mapping vous permet d'accéder aux données comme un arbre dom4j, ou comme
+ un graphe de paire nom de propriété/valeur (<literal>Map</literal>s java). Les
+ noms des propriétés sont des constructions purement logiques qui peuvent être
+ référées des dans requêtes HQL.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="xml-mapping" revision="1">
+ <title>Métadonnées du mapping XML</title>
+
+ <para>
+ Plusieurs éléments du mapping Hibernate acceptent l'attribut <literal>node</literal>.
+ Ceci vous permet de spécifier le nom d'un attribut XML ou d'un élément qui
+ contient la propriété ou les données de l'entité. Le format de l'attribut
+ <literal>node</literal> doit être un des suivants :
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para><literal>"element-name"</literal> - mappe vers l'élément XML nommé</para>
+ </listitem>
+ <listitem>
+ <para><literal>"@attribute-name"</literal> - mappe vers l'attribut XML nommé</para>
+ </listitem>
+ <listitem>
+ <para><literal>"."</literal> - mappe vers le parent de l'élément</para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>"element-name/@attribute-name"</literal> -
+ mappe vers l'élément nommé de l'attribut nommé
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Pour des collections et de simples associations valuées, il y a un attribut
+ <literal>embed-xml</literal> supplémentaire. Si <literal>embed-xml="true"</literal>,
+ qui est la valeur par défaut, l'arbre XML pour l'entité associée (ou la collection
+ des types de valeurs) sera embarquée directement dans l'arbre XML pour l'entité qui
+ possède l'association. Sinon, si <literal>embed-xml="false"</literal>, alors
+ seule la valeur de l'identifiant référencé apparaîtra dans le XML pour de simples
+ associations de points, et les collections n'appraîtront simplement pas.
+ </para>
+
+ <para>
+ Vous devriez faire attention à ne pas laisser <literal>embed-xml="true"</literal>
+ pour trop d'associations, puisque XML ne traite pas bien les liens circurlaires.
+ </para>
+
+ <programlisting><![CDATA[<class name="Customer"
+ table="CUSTOMER"
+ node="customer">
+
+ <id name="id"
+ column="CUST_ID"
+ node="@id"/>
+
+ <map name="accounts"
+ node="."
+ embed-xml="true">
+ <key column="CUSTOMER_ID"
+ not-null="true"/>
+ <map-key column="SHORT_DESC"
+ node="@short-desc"
+ type="string"/>
+ <one-to-many entity-name="Account"
+ embed-xml="false"
+ node="account"/>
+ </map>
+
+ <component name="name"
+ node="name">
+ <property name="firstName"
+ node="first-name"/>
+ <property name="initial"
+ node="initial"/>
+ <property name="lastName"
+ node="last-name"/>
+ </component>
+
+ ...
+
+</class>]]></programlisting>
+
+ <para>
+ dans ce cas, nous avons décidé d'embarquer la collection d'identifiants de compte,
+ mais pas les données actuelles du compte. La requête HQL suivante :
+ </para>
+
+ <programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
+
+ <para>
+ devrait retourner l'ensemble de données suivant :
+ </para>
+
+ <programlisting><![CDATA[<customer id="123456789">
+ <account short-desc="Savings">987632567</account>
+ <account short-desc="Credit Card">985612323</account>
+ <name>
+ <first-name>Gavin</first-name>
+ <initial>A</initial>
+ <last-name>King</last-name>
+ </name>
+ ...
+</customer>]]></programlisting>
+
+ <para>
+ Si vous positionnez <literal>embed-xml="true"</literal> sur le mapping
+ <literal><one-to-many></literal>, les données pourraient
+ ressembler plus à ça :
+ </para>
+
+ <programlisting><![CDATA[<customer id="123456789">
+ <account id="987632567" short-desc="Savings">
+ <customer id="123456789"/>
+ <balance>100.29</balance>
+ </account>
+ <account id="985612323" short-desc="Credit Card">
+ <customer id="123456789"/>
+ <balance>-2370.34</balance>
+ </account>
+ <name>
+ <first-name>Gavin</first-name>
+ <initial>A</initial>
+ <last-name>King</last-name>
+ </name>
+ ...
+</customer>]]></programlisting>
+
+ </sect1>
+
+
+ <sect1 id="xml-manipulation" revision="1">
+ <title>Manipuler des données XML</title>
+
+ <para>
+ Relisons et mettons à jour des documents XML dans l'application. Nous faisons
+ ça en obtenant une session dom4j :
+ </para>
+
+ <programlisting><![CDATA[Document doc = ....;
+
+Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+List results = dom4jSession
+ .createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName")
+ .list();
+for ( int i=0; i<results.size(); i++ ) {
+ //add the customer data to the XML document
+ Element customer = (Element) results.get(i);
+ doc.add(customer);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ <programlisting><![CDATA[Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+Element cust = (Element) dom4jSession.get("Customer", customerId);
+for ( int i=0; i<results.size(); i++ ) {
+ Element customer = (Element) results.get(i);
+ //change the customer name in the XML and database
+ Element name = customer.element("name");
+ name.element("first-name").setText(firstName);
+ name.element("initial").setText(initial);
+ name.element("last-name").setText(lastName);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ Il est extrêmement utile de combiner cette fonctionnalité avec l'opération
+ <literal>replicate()</literal> d'Hibernate pour implémenter des imports/exports
+ de données XML.
+ </para>
+
+ </sect1>
+
+</chapter>
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/css/html.css
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/css/html.css (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/css/html.css 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,97 @@
+A {
+ color: #003399;
+}
+
+A:active {
+ color: #003399;
+}
+
+A:visited {
+ color: #888888;
+}
+
+P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE {
+ color: #000000;
+}
+
+TD, TH, SPAN {
+ color: #000000;
+}
+
+BLOCKQUOTE {
+ margin-right: 0px;
+}
+
+
+H1, H2, H3, H4, H5, H6 {
+ color: #000000;
+ font-weight:500;
+ margin-top:10px;
+ padding-top:15px;
+}
+
+TABLE {
+ border-collapse: collapse;
+ border-spacing:0;
+ border: 1px thin black;
+ empty-cells: hide;
+}
+
+TD {
+ padding: 4pt;
+}
+
+H1 { font-size: 150%; }
+H2 { font-size: 140%; }
+H3 { font-size: 110%; font-weight: bold; }
+H4 { font-size: 110%; font-weight: bold;}
+H5 { font-size: 100%; font-style: italic; }
+H6 { font-size: 100%; font-style: italic; }
+
+TT {
+font-size: 90%;
+ font-family: "Courier New", Courier, monospace;
+ color: #000000;
+}
+
+PRE {
+font-size: 100%;
+ padding: 5px;
+ border-style: solid;
+ border-width: 1px;
+ border-color: #CCCCCC;
+ background-color: #F4F4F4;
+}
+
+UL, OL, LI {
+ list-style: disc;
+}
+
+HR {
+ width: 100%;
+ height: 1px;
+ background-color: #CCCCCC;
+ border-width: 0px;
+ padding: 0px;
+ color: #CCCCCC;
+}
+
+.variablelist {
+ padding-top: 10;
+ padding-bottom:10;
+ margin:0;
+}
+
+.itemizedlist, UL {
+ padding-top: 0;
+ padding-bottom:0;
+ margin:0;
+}
+
+.term {
+ font-weight:bold;
+}
+
+
+
+
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/AuthorWork.gif
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/AuthorWork.gif (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/AuthorWork.gif 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,62 @@
+GIF89aüñ
+Ä¢ñL*̦ó J§ÔªõÍj·Ü®÷Çä²ùN«×ì¶û
+ËçôºýÏë÷ü¾ÿ(8HXhx¨¸ÈØèø)9IYiy©¹ÉÙéù *:JZjzªºÊÚêú
++;K[k{«»ËÛëû,<L\l|¬¼ÌÜìü-=M]m}½ÍÝíý
+.>N^n~®¾ÎÞî/?O_o¯¿ÏßïÿoÀ<x0
+Â
:)+Z¼1£Æþ;zü2$Æ
+r(£¢H:U©Ô
+Ó§T«
+Uh5ëѨ¦jýj+¯`Ëþ¬Ùµ"ÑRË6nN·XåÚåéò®^tÁ-{30Ç¿lû!\±
+¸a})²8`zêɨâ¦Ùeá!ÆÄÔtÞ·#`ûÉ&Ô°8d %K'FIåU/VÉ MXn¹Q^üÈåS^NfÄÙh&crQf¶éffhÆIå£Ñ¥P´§Oö¥Â
+ NðIhHÒh¢¥MéhcWF*[D]i¦
+ ¤i§~:B Jê?sRª_¨¦zتþéê]^«ÖÔ¬ªâÊ*òú®Jü
+ìb§RxþY±0 K¦FA¦¬dƸbFÄBÉì%mJÙF±-´Ý§µâk,¬B-ù,æçºéÂã,»Ô)½À~kgúâ/¼þ9ÊïXõ¶8RÜQ¨lÁìa .|m¯eøðºÓ¨Ãj`±ÆØÇL\Ä#«ÉA Ìð+gL§Ë·ú73IJÍI´¦$Íîβ«>û
+3yCûÞ'?æÁíSàê¡´Õ
+1^ÓDÁ+¥? Z$È$!±': XØöµËsÖÚÆÃ$jA"ü×2øM9y£$îÌ0.8¬ÆJÔ4ÃL:à µ ¦icûáþ»Ä:Ý7íâ"ÅεDódQNêÜ3EµÍhD`=EÀ
:z¡ñÔ(6ÿåiu$ú8¢<ZlIÓ!í§2<*ÍË«I÷äÈøu][kQùÉ4=bË1ª$yÈEVèXMª"(ï#Hý±Nf©DäÞÖȳ*½`$1YI".îxaÛxɶï)o¡ÑM0{èK
+`3ýqHÐGYFçðqÚ3;ÐaþGÔ{LÿÚHLõó]p ün¸ÎN|gJ'=å£Þ5Ùܧ·¸éO~úèI9Ê;{"tziQ8þûvÐ
èøPUÚ¤TíèB8åÑôD¹ÞHO
+ªV(mi?VÊÊôýæ`j=âÔ¦%`^F¦Òò´8hC¸Ó ¦wÜNbF¾Èî¨QÞ.I6`É㧴ÕuµKShûîÕT¹½¬Y-£ùÖ&`ò쪮âO¡Ö$uñB]óÕWYæ¬Û<È×uAuÓ¥[Y)ÍV±¼á¾Å¦2KÃÏÕN·h6¶gh+ò±4hq&Õ²&Y5=p6sÞl+ÐÚÄ¢q¨
,g÷ÈY
sµ#ã+iÃþv\YiÕ·Q%-lÛÌÛJR
}_$×-V׺
+D!vg½¸uQ¬°¬ZiÍ«h~ïÛKØ{Q±¼¦L.zå©Z 6qH´o}7)ÉøÍoº$0IpB;òndßh#ÆßÊN;
+n<Ý(:Ø»HÕï|Ïû\Qbs\ã¹V®úñü=¬c7"Ò
+ÁaæXÃëC«í¸Ãwrmn¼áîVõ¶9¾°áZJ¸*1`,¾+ozgeW
Þ1x/l*xÆc>pµ$#
+Ì2^²½|V©Q¹ý´kaÎ\¨ëÉdærÙÌþ=%9뤩9³L.¿9Àns«:<oEÒ«sQjæowÏî÷hÂ&oÚ§fè«êNP¿Õ|³P*Ñ¡Â
+í{ÿÝ^M¶Ç7màÿöw¿ï·úÐ¸Æ kWÌØo9àù2Úì×°Ïó´$~EÄzÐâ$záÊn¬Á»¼Ð¥¹Ø>{pþiKE¾pÌ>|Z;VÙj}>%5öb_ÛsæR¸£kz]K3¤û×ä·²:Þ°^4{ÒHYs³(vSãþ0}'+õßóä§ämØçzÞÿr®ìUdeÓ>õk+Þní~óîp²=äCVúá·®ïÒñ=Å'îeõŶ½qѲ«ÒÌ0SY®9åûyó#·ææ_Èz²U(q 4µ'\ö¤ò-ËÞÿí>~wO+9_w¸½?é-ÍWí:}ÚRøßÍócýäeÿeÝÇ4ñ=þT_ð,¿A¯¿ýÍþÀ4ýÁs²Ïïkú_`ýì¬6ú¿_láW<ú§^¹'g'Q>Æ
+WL9G¸EØ15G¢{÷CG´
æUG|aH
+7Üòpd´xxE˸w§Wçr)BG1tBIX_1§wo?ÖWë±Xt~q5|ÈzÇAåÈôA
W-78Bv¶:2uÄTW\UèpÊt_MñàÄsÎE
+uõ%z·t·
gÄXÙÑCrgE9BYcø9ùeuPÈKhØJM²p'3ºM¨´ÒôKt3+{ ×0$W\:8p~×[¿³þ\[èt:ès
§wT¨#(uj´-§V£Øx#&öF
Ly5]uµÓ6ÇT#vx7¤èyå`hwØ_¾ZL8^E'c7a¦¥ÇSX'6^>7
+öA8>WØqP¶o8¸R¸UøKväÊ8ÕKÆäzcÅhWOÜ·TÐ0è;e(Á¾
xÉ~mp
+H:þ(Ef]¢¦FöÇÛã~ù
+¥órQؤ÷bzqÉ<¥~4"bDÖXÖnp¨¦»©zæã-DôðH¡KZkP-ÉxºtH¸7g@:N¥ÍT¨yꧡ3{Ü?k½Æ/I;z:þlû(nD';imzºO[©Éö§¢ú©Z=f¦zeª%5S³+ù ïЮzªøGºç& Gª{;W;³§¬ n
+ç£ö¨E6Joêéi
k¬ú¬PXBx<Ø"TC=È{Õ½Ù´HpgßêgXÏh;¨ly¹Öz©ýU°¦y°¯[ Xqm(Ø9êdØ8Çtb¢Öò+Û°ð`(±¾U%(tÇÇ®Cv¡Ïi¤§¯Ô $%;'[t8*¿W/þ»4J3k:+Ó³®âÈ¥'çʯñ8t¦ÿ2Gå*£¬Gy={¯KûMI6U{¨_«b;¶IÍê:¥¬âãjë¼ °
+~tÛ£Êy¨úzË|«f¾Zjs¸i·Jú1Gy¸y ¸@)´Û¸xð¸×ê·9¹¸Ë%¹ëxDùÆxˬer-J²Ë(}é¯õæccº»XY${ »ËX꺨rx¨Y®o%$*GrV®:LÂË9¤9¯04Ôk¥D¦²;¹ÁÛB2K2)ëxÚk®a6{þVËÌ»1$ê!AU§Å³Õ,àûºí¹¦ó;µ8ÀtMú±k^WH_×±h yÃjZzX"ûvù«¿¹» 8ê¾%úJ¢Iú¶,¯];´
+\³'Âü½à«Á;K¾ZæÕÁ÷ÁÐ+¤»Ø£F´ÈxÃÂÁˤXhÃQ¶»XWrÝ£C,ûÃX[bÊk\d±¤µ×{
uZÁn»,ºQ3Y|¹%ÃŨóÅáÑVb¹K¸Öî[¹ÇÊ«Æk|¸JOoü¹q|JÇu<´*È£ÇrÈ~1ÀÇswÈТÇ@øǼþ¶øÈ
+ZJhÊÖ;q(
©e¬´«ÌʯÚ,¾LÊq=ë¿®ä±ô«ÌËw`>TÐÌ £±öɲmJøËÌÌú!GvÍÿ+ëÍÛ¢'Óv:s1;uÒÃ-9ç\.ëüOdÑù¾»åÉô¿ g¨ôÜÆ[1¨VéM.KÐvÜÊÞv¦¥
+²·ÎÚÐÚÒ)ѪmeÉ<©ýÑ, <H$í+&Él¬ÒðÀÒ¶ºª/Í(1=±JÓÚbÓ9þ-;п[Ísy£l¶ÊìÓk
+ÚºÝÒÂÜ´!ÛÐêÒÍý7ÏílÝ!ÝÎÜÙÍÝÝLÝÝ
+ÞÁóÝáMÞ:
+ß´ôÞñMß:ßõß"pÞùÍß9tßý
+àê÷ßNà°ßàú=à Îàò³à
+áv!NáÛóààáÎá®á.ânVÜ#nâlVâ'®â!®âÎâ-á/ã.ã3á5nãã9à;Îãîã?àA.äüMäEÞ×ä
+îäjåmcSNå¿jßX¾´UÞ§!¹äÅåàåãÛc^YVÑýwæòæj.Æçr®
+ʽüÜæÃç§Àæ=÷YfKPè¨h}±oøæ¶þgç¾²B¤þç|©oNé¦@k&ÒNv TSí'>
+Ê÷Ï|ê6inê§ê¡@Ñ<I£îIºlT³þ "Ùç~.ê¶Á¡^Ìë PæÀîêÂNÂÙ\ìpìöè²gÅ¥ÊØìÆ®åÑè×Î Ïîè·èÜîìaNîù0w.îÝíà;é¾ ÞnÎÚ=î ðNìì¾íôn åÚiÜ=åNÈú £+"Omìí.ðû>ÑÙ»äH¥²\ïó¾ðàI°«nåÉ®ðoÜ´ýØÎk"v®ì)òÆ=¬
+Ù;ÎòMýëØòþæ½HlëñÅÉÛA'+˧óË
+HR
+ñDûµøóN»ÈxyÈïGܵèçÞ¨eòüíVÔõ*ÿòJF
+í`ö,©òQ_Úó_¯öxíÆZ¿õyÂîkôsÏÑóg÷ùÎ÷¢}oñ/ø=
+õoøùZ¸>_Ùßöù&; a©ÿøÝh÷ôáÎùßðÛnñ
+ÂN
+Úv¿áqù^·ßñ:iß÷ÿØpö¿<@ÍÎ]×ò$')+-/135}ö
+É;Óú7cegikmoçXCwyam
+="F #TW:Ãte~q£¥§©«ñƲµ·¹»½¿ÁÃÅÇÉ!F-zÓ+ ¯ÛÝßáãþÛÕëíØ5èSïýGä8`A;ûþ%T/B
+8bÅfô1F,9¤5Ïú±TB'?¦ãXfM7¡{èËb¾gQ£GÑY¢Ø0/@añ¢TKTNϸ
+Сg&;lÈ¥«©ªÊo+´øxbeë6ׯÃÕ»ï<bÙÒ>Mö×2¹§}T÷ÜÝyûF<YÓYº-È0ÃÜ
+±µ?Ù͸
+× ¦!SV½uËÅÀ~«ö-Ík
+î¢Î1÷uqãÇ]ÿägØ÷Óå¸ÿ2
+¢_þ³ÅÎu7Þo¶â¾9<Úî@S#W¿ý¦Ï®ç'*ØöÍ/bùí¶µ iOÀ ¬aìâ[Ã'_ÎÙF¿òÄp?ÞSkè,PÃ
+/ÁwÛ¸ ¡PÄíxúì¶8lÑEÊ<ü0¾g1ÅTô«ÑFÿ
+ó.½Ò¢e¼Fê¨K)V<ñ¹Äzì/!©¬ò&"j7¼ÆÈÊ/Á2Ë1E¡Ì
ÂLSM°</íÜdlÍ9鬦Í8]ÏêìÓÏZî\Ò@ÑX0¸)¶Ü³§?mô³lóBI±«ôTtPG9íô åÆ{©¤þêPQ¿ËªÔTNU<ô¥rhÕÖ[ÇðT×]ÛxMEÿ£j6cò0«¤:xmÖÙÁpIë¾(¯C=»-Êý
+W\!Í[sé*´t{7pÇW^ÖÔµñ×{ëE÷ºvsÖ\æ
+Xà½,Ûª9î¢tuTæüuU
ê¼ÅL®Øb£(
+KI5¢çÇAÙ{áö1CYå "YÓ]>fYæ3qùåùhÎYç[l¾Ïº2³Yè£N¢g¢7MÚé§áXéI¡®Új&¤:«¹îZ@IÛhVÁòÚì³ÍäX>Q^1R^þF[î!ð<ô¦zXaVíu8YQMfpîÁÏö5áSªë]Ù¦[ößмëh]N¾]·¸®nÉA¯Úð¾ÏVsÐ÷uÈCoéÑÑ»3ÕO=óÍw]wºAE¸_AU¯îªÔÄüÔEwOæ÷àÖzJå¡_ùÀ¶'u¤è±9kë»ÊÞû·çþïÉ7|ñ-(_}qÏG¿Ìõáßµ}÷]ß~Oç§ûùo4ý¯×?ÒéNaóÅ?&Fµ.PMåªÔñª§BÐtdà«T7e(ìRѪø&
+öçØi
+àþ&Ï¥-¯
ª$ðv¤þHÞj±Ø
.ôá(lvE´¡µNgÃÎQE?t¢òµñp¿K¢¾®H¸=d"²|EY
}»»Æõ,VnCálg)}+û2a¤dA5îq5ÿã6V/ñªñ£Út3ÈB.²/ I½8[ä%[öÈ7aÓäc:Ê+á¥4å)¿!JU®tå+aKYε´å-qK]î½ôå/LaÅ4æ1Le.Ítæ3¡MiNÕ´æ5±MmnÝôæ7ÁNqå4ç9ÑNu®ítç;á¹
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/AuthorWork.zargo
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/AuthorWork.zargo (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/AuthorWork.zargo 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,70 @@
+PK
+
+2õëçyü}RÜ'Ñl1(üGï^½¨Q0¯û}5±oÉ*ÔÉ7?¬ñ=Õ÷Ô«ÇÙ¬ dkÉJ¼¼~H&é,-/4k¡á \³òÿÉ4)ï>Z.Óñp.>Ì8¤qõ¸`MÉp3"z¸ý2o_¹hëÁ£Çå´HçÓ4N/[º5å;ê7zxHQ2hGy4{Hj4ª_K"ú¶öp0Í>'yÅSÃÁr>ßüÿEýy/ö>°M²[RÀ £ßÞçy,Wç,£ê%ü'zûlü¥ü´
à®ü
+ÞeãdJ_ëíøæ±ú
+ XüòkmJ?'ѤFøú~QäQLתÉ5Ã|HÆ¿GÓeÒd§ÛÝOô¸}Ñ0ÇQ® ßÝ8î
+nn|ÿÆÇ7Èó&0~9AØñ¼±Ø/o˲ÌI=yT a±&Kód²I
+îÚ"h°ßÞ%«ô~»ufgÉxMß\ÖN£Å^Ð`Çdù§áà)]¤÷é´bòÝ|yO8]b;Y±CMäø£ü2.Ò§Á2]Øfë¬ãO&aãÙrìsI±:°<Km)HæÉlLÔÚÖ¬sEqLv°,<$ÅÛñW_^{]kÃ^#6ÉDËûaKÑ\[þâÊ>¢G²ø¢¶FX-=çæ&n¬LûQðrb^âÙhLyß^<Ö
+ÅӴͧ[ÂM!bÍËæ2Æþ{7°
+ ¡Ìyx]yz¿,ZÜéÈs÷&]Iuº0Z[#RR##©Kª¯±¤ì3õ6-¦Öí2uÐöökhõ`aÅÂùÜyJaÅ}¬a +¶!
50Âz¸°Jj½ÖÕfíÎWB82ÉG$*9ÓÛÐ\Ê-±üÊà=ʯRþCÍ?ÄÙÊcÎE4+çÉ¿IþEà¬kya·:íjsqã¸Û"#BÄ?º=t/rAÝDcÆR²p»Ñ÷ÉÇè)ÍòhúãJ|Fó('BQð·_6µWB9«óÜhÖAnÊ¿OélL]Ì!x~1L>ôT>³ÍhúÎüT],ËSLbvZû:³ìÈrß¶Õ gïýd¡ýö@aÆÄâc6®1ÐÒiͳºí¨qE3ÏâdLÏFÙT4ª9YÑ!·u[ßêªbúúnêë¶ W²«iã}ü º=M(¯ù»3da2Bæ*¨ÙC4ÖWv¡2Ûé¡Bf+öPkF!kRr2Û;B&djê¸fPmÙ7eËâLÜÀr/'üÄáÞ&å5¶æ£¶9á¾* 9áÔhz©7Áßía¶m<}äxc½fÛªWM
Ì/û ù|4¨¨9°'ƱÜE¾É±;:DÑÃ.§Üj4R÷o0Ü©ä¸x
+'¢¿ÿ
+Yßln·²téøË]<ÓûÏ.W_q8»I
+¥©ºâN9r-H9r%GüÀS骽*Ê3«PlÜÁѯ°¾ÜM¿¢Kq6sù¦rÅظ¦_½^IÈI;\ÁãùIÍâeWAêhúï,910O;¤Èè´"¢H4Î
+
+Q¸}Q¸°!¦f
+Ã8yogjÅMû×=qâ^^æïà%`¶ün[>lzW¢±lËú¸åÃV%'wkfËoR*ö¨êäq>;$Éâ@¾>c¸Ú5*w5ÃÖMÊk×d°U3^o¾ÞWªÞçuÀ?Ø),kF9v)6LìpêvXÃ0'NRÚµ¹§M;|湬£F×9]
,.Eó@£Ñ¶¾»?DMP«ªÂìÔÜPFyã(oXäv9å
+6+Ùá9ê ¾`Ê[ØCåÍïJ!ÃGÖ0òÖ¤TÐæS©wÅ¥KlØz£ÖAù6K}RÀ ñ
ðÆ5¤hòí"&ß!¿ß$Ñ8
+Ä$á#c¬~"üP$ô·ÍídÅ2DÉ*~Å@Ê>lì{ÂÛdøöÉ
+±DtjÇ")ûÔGÏJ(ä#ÒwÛ>E.Pò1¸äcÀ|4J(Þ£e$õpIUïñRÊÂ</ߧi´0º]&HØóHãðüñªìyÀO"9©°ìcÕk½Ç
+dMb¤1véÑÂJj½ÖÕg at R,¤ÜæÆ{öUÌìa cqÝ¡Ãa3ûB`
+Y b¶^[k865«G+dȲz¨!3ÆT¶¦Ðë|=daÁ)oÊS[S0&ÅÓÆëÙl
+d¹JÈ2iÜãLÏ:?^z¨¬ /Êȶ4.»ë/¦2BíÐ
+GB}DUF¨C¸cÿ Æ©öÐA¢ N0AâI`²UÄUFH¾
+C`e 0"Ñ4ADé4B]Îv/|ú¬P£FBÍ56kú5-ë,ÿÄCÙ<EȲ٦´'FÙDfScC,dú³0Ð&§¬5ãòmR^;"aé@£Í³é³¸'ª
+$ѸlÓ§ôgÓÇ°)¨ §Ô5³é7)USc»¯÷
+¬csJ[Xã0QREGM)üóõ.¼ÇÖ÷MMk
+Fß/ùL=¾ïXjëûN²·ýú¾Æx ú>ѽÏ^ûìס¯¹i¦ü¹ÖS¯ü9°Ñ@Sõ§
+Nè³ à±}üóì=Ñ[¢ûª=ì°Èer\>NòtöP~³Uñp@¦'Û;̲Y[Ñ(¢ü!)ø#Q
+h7ÔÍS.bXmFËiÎÉìÈõ<>xGÑÔNT H_5ÊËQcú׸þ bL³ÏIJ!ÉÛZÎç«ÿßj©1´I9Ýeé@5(õs¢1Gãs¢ /pñûä°¬>êôýYä]÷-
+Ð<ªz÷«~ çâdÁï\Þ;pÇeÑå`v.åÞºZlݬEÖÔîâOQS (¤wz¾Ùï9b$ó\/ßÅ1>¥Þ>´C9æ0®éÊ9{¹ÇÍåÔWJ«¶ÔÐÎú]PÝÒYqgq×v²Óud0§lØ©»Ù?ô)7§è»uÈKÜÏn&ݼàvC>Å· ÖåUío mLx¹yÁ!)Õ~§¨*±dÄ'4 GÍö±m
+WÓr)ÍíCQ:·ÎÂmåÄ~JÎÎ÷3 gÔ¬QhÂ͸vmzìÓJ7L³èN× CRâ~nã´ZeBnãnw«åü%/(¬/
nv´,ÒiÏ})$N¨qX/¥;¸:)ëöCrU»!¤/%ä@X£Ðd7ܲ´öè^п'qå×þ9!§1
+k° [ý9%o»(Á:Ì£8N¡Ô£gÇgXîjNg }<!åîjâlûÒ,Û(¦¬!xÜIùiÏv
+ÇI°iÞ5óRçm«ts½æA{wTÝ¿úZð6$Ïkäýr»¸ôyÉGÀ0©¡ÆÀ>;&\WóÞÕ'äwnÜóæËùPrKýÝçv£à3èþÛ7é:HkÒº0ÒZ_$PCPcÌ
+æÆI{JV2ø¶Íг¬ò}©Z-Ø2TOc
+´[NAË°Õ!)ÃI¦ëEk
+G1Ýúð-¯uÞ(Ð0
+1ÍèoLý-d¡ã]^Åb(\¹üéoÈê£þ:Ô Ëpç$`ÃèoMJAg1¢ÂÁwâJÕÀËblÉ6)ûcÅim}Iû¹ÒöGuÉæÇj}c~ðS(
+,ÿíi8çjÜþ¡[8DÊü,±zS¾÷,~6Öt¤ 5`[¸±T¯\á¬é>¶pÁ¶
gÐHZS0Í.!Æq£1q×`H9
+ìϱc¿ _æF÷F
ã©p*váø.I Sá°ÛK®gJÀRk
+ý`ÊÖ¿U/W3J§Ö]BØ,dèP*Ø%¶%m¬Ç§abCb{¦ Q-Ìåzîq:§a[X©¡fGlÃÆó],·ÄéÀçèmçhk·ÑphýÊ:tâ¶j>颰}¦Cئ;!ªã
+°
+YuMáÍ;T¹áÄNE%ÌExUíýIïViØfU1¯:vãr,7.6¥Öå`45IÖÆUBÜõ§UZ¡;4Â}ÕMájñù°«ÿ;á¹6ýÿ§dFÌÕiú¿òÙ\ñ°ýgüT£hZºN3%p5ª®Ïªt, v8 Gd4¹AM¡Ö 4«|¢Ã¹s<j£Êv.rÊغÀº0GÆAëãÖUæèbë²@?É {<Î3#°»uÌD=ÀîXp?±ËÏh?ÀzìÖlC`!Ûõ¼#°!_`¥Î¶þ
+ìêÇ3
+Q
+|Oç\XÛ` %Xv2<u£®h FbO9Ú-
+x°<[c¸x°b÷±Àfñ2Xã0y×MÊëÍ»öÖyÓ!qï\yØ<Xͺ>´RÈÃö CkÆý
Aò°ÑµºõQ£Ôq:%+D=ØtR[cÈ[8¥.è¥Rìµ2)ô»BÔ§`ï:*cåß%JD}`£Ááê&åõ*>fiQ
+*¾-mªT"N¾½SÅXñ; aì7V4.1VE§3Vê[fÐ+UâÆÛUÇÖ¸îÌXñ½>+>°Ùk [S8ÚXaÝwCêj°ÎU»°«ºJ²Q@±@óÅ5.,QìN
+ÎQìýd;®bǯV¿ bÀzY°Æ%`]ÐËÔ
+_l
+[S0æÊÕ<&¥ ¹ÈwļôD+c°@¶
+Dø5W®íÀ,fô/lãTõø÷YöéñNBØ!"²âqh\ÞIØÜ%ñNBn5ösaj;wËZqñØñµg¬í´;i1vÈ-Æ6òJ/h-¶Æ¥q
+®7I§ã(þNÆ+é lx%NÆáÜõdrpoXnÊóÁ[²¨:pt(*
+9GÃæY;`¼áh£fÊt9Z"¸N-nõÍ«¾{[6Ä+V4ÕgòïÿPK»s§A×
+gÙ
+.
ãn÷Üáâ&ûÜâ$H
+Tâ©Æ1³M¡³à.cË[\<äØÅ àÞËïùÅ
+Ð%¿ãäs-Ýhc<'ññ8Ê?^dÏ4PÇbyP)RÊØF
+¸Od>@¤
u+[ëRa+¬³GEü
$LG`>Z%A,IÎ$O¿!7¢ylµ
+?17Û$]Ù%fݪ¼+˼õýîrsK¸ªµà)&.BÉñ®Ýl¦2K¬¨Òú
+¬ÔZÙo³'OÛ/R^ÏÒ8¥Ä×álB6"ÛÈcO;dÜÈ?¯³8IiK_Y#µ£HmY®vØé;¸]Eñ· H'¾¹Í]UzhGý§ò&/TRn¨Êíh÷$BZ=羦Ãô$GZ1J³?
+Ãõ®|êCõÐÏ!pxÌ6wui>ѨAýC¶ûìôÙí2¬FVöº¶s±kñ·±½Ø
+ÄÓQìBNìÚ»AHfvíbô+æ$ã{5V-Ì.¬7»Zª]X¯vµCÉ.kjí.ÔI½9½k[*ù]»Øs¿9¿+¶Ý¥ÒOðÂ/MØ`±»jxaÉðÚì¬ BñÚÌDÅÛ(^¦7vÛñÂ6W¤ÕPòúQè§ê(yiäRËKµl¯«¡+Z^1teWº¸
+N»-4¯Ø»íyaÏ+"w\ôÂ6¢WdÖÓôí</lãyEhMEoN½Ñ¼IÍÛhÞ¼÷=&´ÍóÉEo\OÓ»!_Ñÿ&ùVs»#ez¨Ýó }Q<¢´õûÜS÷líÀÓ-ø5}DÛ_ðïP{#½þ!û¼1÷ðå:«æõ:eÇïºÇOµp÷qüp,VßäÇàÛ-äß)¦bF
+§æ#I~\âZË_ ¥åÇ,µ_;ò#u¨ÖóóDôüÑáêE?(
+tÑëV·â¥âÏô㢦úiÞÛÄÝUÕOªALØTº~v®r4
+C¦Cv[öSÜFY(âjhû ºìÇøÙ~¼ÔöàEfgW´ýbðÊl¿,xy®Q¼-l¿Ø»mû)³rw\÷SèFß/Bëéûßa¨¶r7*[SåOÁ¯ Ûk|{¸üÓêáúO«@ÐêsÓW6bØ,Â
+::Ý$õ L7ÀN ÎvÊ 'iprïC¢lèeVFkbˬµ:Áð©¼7#wÓ»ª>I=4õfä¶ëÍ'D½7#íVÆåé»Î¥
.-§n'%ê±vÒ7Kcêkrx¹÷G·güoçW=\Pz¸ Ô,¨Í£óióÏiOCZÅå
+ 6»7L|~¼N¦Áû8Ép¹Ä¿é2öó_÷½gÿ4ÈUìMêg×+?»a+r7L¨ô÷qôØ6ÙÍÃ&DEz¿¿YL6`wþ¯}eÀ(\nÎæ>ìCv6®\
+ýå2ÎÉÒËâ*qhqÙáZHÿG{q§ëtKuVYolÝåÕ£MÕx#qÈãçVË°í+"M¦ä¾õ`ÇB=8Þõ`F?P²¾`:]ë_ÉçYì[$$$]x]ï
+çgBª¨¡?
+KÔ°ôI
¬Ò°M>§]X*uǺ²;¢íìKuJÝXuG¯ÝÑB@Ú¡¼?ÊO¿¯[ÜFþPKú¦F
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/CustomerOrderProduct.gif
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/CustomerOrderProduct.gif (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/CustomerOrderProduct.gif 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,44 @@
+GIF89aÑ
+Ä¢ñL*̦ó J§ÔªõÍj·Ü®÷Çä²ùN«×ì¶û
+ËçôºýÏë÷ü¾ÿ(8HXhx¨¸ÈØèø)9IYiY©¹ÉÙéù *:JZjúÉvªºÊÚêú
+ÛK[k{û
+»ËÛëû[
+ @\l|¬¼ÌÜìü*m}½ÍMÍ3Ü->N^ýín¾ÎÞîþÎÞ _o-FÏßï?ëÀÞt<0!Àû:ÜïLÃ+.Ü1Ñ¢ÆþwudÜ2$Da"K&ëXæ£ÉQÖPÉ2æ37`ʼ)¦8êó§Pr?cz³è£H
+üÉt&§ÊzZ2S3¬=ºàZ^P°½Â »r>ªÝ úc¶e5¶áTÆeiÅ]v\ë"ÍûmÕbcg
+®J_C¿Ä´Nm¬nãÈì½æ²B±-C¦LØ3UÀ*4ãìYlåÇWK6MÔàác«Ek%|qëÖ°Ë&¾·¸³há¶!ïf\·÷Ö¹NQç\¹\pK=ûäáIëM;ôóâäusoù·½àÃ+k×þXz<æM¶ÿ°wòþ!Cþ¾çÛým¢^cê
5
+qäGà}ýìgÅþGPYR8¢{÷÷)hèSx
+VxxnmÈámÙè¡ÀÑW_'êÈâ
!Vdß7îc²5䧣®gãu»YXåP*Æc}òõ
+ÙÝT&ØÞxbn¶$zMâö_ E©ß
+r¹Fw¤b zîyZ(C
+ç¡:HÝ¢Y êh¤1ð'¡}NQ©¤]:B¦Nѧ¢:3ã¨
ªá©©ë©jBúÙj¬:ê¯W²òµâºî:+
+hrðÀ]½Ké´é*(º(!Ì/Äkñ|ã/Ç;eS´æj·²¢¹"
+²¥·L¹¿swS`r¬(lCÎ5»ñd¬Ìf}ôæ2>ºrÇ°ÖÒ;ÞÛ4H»¨ôÏÕÑõ`LcápÊó¬ÖëT½SØ<WÛ{mÙîÎ3W
+LRk46 ggªÝ
+mz'ÝamaMp¨J«ùx§æØoZþÉÚlhwpõãCÏZ·7DG9Í .z¤8bdrYöq¦h`ÖFÂ]é1¶Ë¼ÿ^âĨ×kãí_Aæg2Þv§.ôHï|ó¬oN©j}?üÝ¥½Q½÷ËþÓaï¾Õ·d¹H¾êô¿¾ÏÝûßô*Ý°~»`z^G@ÈÏ=_RÞ-)'áoßËÖ×µ49 LRJÞèH¸¹¾Íno&â!§ùÍÎ~1
+1¸¿Vî<ÓÍ;ÈÐÇM¨"Hçs>É p(®ñ
Ù+"þШè@bKÊabe Ä+zñk|¡¸ª³Ðd£ÃØÆ
qZaVǸQ*×ÈãÁ&ÆG9Ò*gdÛ^GC
+ÍR¤LÂÇB:òTK×$ÉHK^Ò$lÀ>éM¦±g(¥Ò0RJS¤ ócUÉ«$ê´ü×,ôK>I±Ìå9jÉ _zÁ&vÙ6,--
ÔÌèÊ ËHÌä4hÁó
ðv)+ù²MôÉL~[ñ4ÞwGNZócÔ¦4Ù Î+E%.ëÂ×\ióßó·mÑj7
+¥s#k\¶&þðÆ)ö·EjégTã,p:¥Öe8Bû©ä+ÌjXÚ±eµç¤áomÕת_³Ó~JWµ7½,í.JÁz·ôqPJÍíì}
+]³²É (V»¤¡¥äí*~±DÚEݳp[!á*ÇY®5}#lqË×þ>8¾ìM1!\*¡iHb¡o;ËKúÎ6®;j¹xªSómwJp\@ì-8òR[]q:_ Çu£Üd<`ÖPËKq¤¾IÜÏÌÉͪÚú*T±W¯í)lKFMJêUbûroélW5ÃsÈ(*ÁkþüFøJb0oÜÞDówÏÞËtÕ^Æy&iÞé¼[öR,ÊZk>ÍåÎ
+èÈV!eõëoqâÒvV´eX@=ZaX%Ö¤§ãKÏ9¶¬æwñÑEY#×i'nµzko!ÓbµNb²Û²hc×W¾Ä^/£§aÙ·Ê*»¦¶±3
+×g_V¼àk6#Å-ÀGÜ:uur{V&×&&s}nê~Î7mXKïhÞT51<!|á·4})ðÒ4|âZfîø;Y¸7ÎeC,ã=¹5H~mX¢\È&ÈiÝo¯àÂ~eËá1ëþÚz¬ÈK TKª
+}³ >m?½|àÓþ7_îËÿ'ø¿[7×ß¿ÔÏ~ÿ·Ov¯ç}Ú·{á7núB±c~ Va°f|´sÕeX&èTä|ùçu(4¼ÇÿGHH2&hùä6jVÄEy#B)h ÈQf-ëwåwì3y8ø\ÄZó¤\Ö~-HuV±fuxÞ¢ã§Y)2hjí§x5z«5Z5xj|ßåx$¥éÀuÝFoawÊæ,iÕqÐlÃä?çr6WzmX/70EF7¶ÆI|wS#~X¦Un1r4(L|xMrJIkÿquªä4H9çþ>W®wøqm¸_H8v
Hg£xhJ(®h9æ·XM×N£È}ôU'}i\'tMÇTQøS×P1pxZwÚx±:´Owâ8*ªui¸z·8èX8våwÜøvgxkÒ
Ezq'~»XC
WXúH/(j¬W4÷uÅH[Yu
+¬x/8c¡%+Ôg6×x|=(y
+¸: ø+ø~ÏG'"ø)ªHxøÈY¥eü sç8²SÇÁé&
{§eE53#þFX(ù;A)ÿì%îG|JÙw|fy~cd>)y:Èý5²aUId8ÌÆ}¯Ç!yAYyØ58u$)ÜS}5HéÙUU×7_¹8)Ùf©MhI9ØS§oèw6ÈéâXh©v^IyKbXR¹Lû"f2x عe¬Gwõû§_ éUæbç
+è
+Zû ¡ þf¡¢d Ê«Y{*ºI!*¢:ÏBÛ¡(zI*º¢Â #סù&£D£5Úz7ÊswÁ±)/tÈTν;êH=ê
+©Z_·¤ë¨tc}4Xí4&©¥î)¤òx¥TçxX5Ú^:
+ïxþ!OÊlIǤ=·o)¹X:6ªWw½a¤tóp÷y«æ#%ï§ÓÙ%7æù©þ}T¥Óø
+4)ÕyÿäQeÕ<!bµAJªö§x%È|ÎVçWR}n8ôiC°W"µú|.¥]J§£Ø³jþ5z&E×QË
+Ò
4Ú«÷%VxRbÕaÛe«¢&µÖ ð{V¨V'Zk)|<y ·:`ÓÃùY§Î¶\ûר¨©\å&n)®oJ}çZ¯zc¹z;¯Ó¥¯@ק9¤æe,:~°bæ§dj«x"a]by&-}Ç0RتV°à
+±9§/~Ô©\§þVs
+é7²¯
+·<ä¶sX®ÇJÓè³XÉ°Wi>Éi
ûgûo êr²73&CGë>'b
ùª(û*#ên¿yáYwB(BÖóÔ$+ªKwU¡ »)fª¶v=ý©¡ô©»a7j#Ç»K§õè»'¼Õ±'Pê£Ó·¡x£¥Û¼<¡Ñû¸ÓqÕ+nNZpÙ«½1¤{è½Ï¾*¾þãû@ÜKçlé»ë;¾ê¢ð{k3Wqûô«½öë
+
z £É¾»»Ò8EÝÄq&êIzt?'¼%¥GE¥ôØÁ3mQ¥Ú¸¥tºuêÁ¼õ¤bú6Ruf.<hØD´\¦:|ÂJV
°¬P
+U°*DèR³¨¥Û[·#¬ôJR;»úħO'ÅJl$ÍúÃjÃyàÂzj}õ"¨¹7cj\ªøÑÆZªpÅP¨«Ãª¬¿:{/ÆtüÔS¹Jd`jÅ7¤|?(zöÈ@)þUÚue|ÃæyÛz±À*¬kdëÀÊ·»Mk®Åt¼·ÖG°¹°HǸ}6*±÷×°,«&ÕZ³!{©¸Éw TØ°v´cÊ«·lE¹º)¨¨ÉK¶ÊrUÛD{ڰʹ±£Èa[`ÜÊåÜ´Áy@zXÌvëZè·³xTálª;»[´%LÎ[ÜÍóÇí¼ä«´÷éL¸ë|ÍÏ»ì±ôÎuÏÔ8Ïbk¸j~YË|±ÍC%¹GX¹.b9·#·)¸\ÒUȼé
]É_¨·ÀlzIÇýþxHMѶ)»1]Ó3}?
+BÔ>ÔVæÐͪ19¹&/]¾ÀÁDËÛ,ÔKW}1YÀ3hY\½"1ÚÕt`»TÖ-Ài=kýÉË¡lf-×GzÀÒk×Ô×~¨×{ý}í×cݽ}sMØ¥aØ]Ê+ÊØÍüÙípî;pýmÙ¡t=yÝr -Ú©MÜ¥cCÎÚ"ÀÚ¦ÇËLªÛÃz@jÚÚÆéÎS,ØxË÷ÛÉ= gÆÅZYNÌÍÙÅ"Üýv{Ò,w´ÝÓjì!Æ_ÜÝwJÌÊmÞþ`ÌÆ ¼È¼
+µtkÝçÑß¼áZîºUçíßpÌìÍ?Ìø*ZÕü¥ñª°¸ç´È'ÒÉ`Ru¶H=ÆÕýßNémµ¶%[Éä´Â|¯éÇ
+ºÀíÜY+Ïá-.nÈÖ,Ï©õázÛ!
+³*±áÁã©?íâEþÌÍÄÓ·hÇKÔ þÀ"¾XO=+À]å8yå.*7näan®=¡Zåß+æinÆ[aÛáß¿+ j.çA¦-ssçq@ÚÈûæÌç¿gçÀè
ÞçíÙjèu}èqÍþè{ÎþÙé]@éÝhNêU`v§¦dlÎèÔýD©Öæå꯻ýt½©¤ëÁjÙ»ñMÜÕXÁ(ÜÇÁ
+ëÃîÌ]Åö1ÇÏÚåÉ`:Ýþ©MÅF,&Ñ*ÞN|È"ĨI<Þ¬%&ÈíØ.ÅÄNîIÞÜÓ:«ËÊè®1Ò~¨#õÈù\âV¼µ]Êú$åðæ È<à ·ôªÞ<ðXðïÞ¸|ðÁì
*Ëí=ñÎ\í ¬ßèÚà`ð^ÑCKàæù
NöÀ£+"]3{Ñ)ÞνM0¯Ñûñ7?!þÏÎþݤ¶'§ô±]AZ<òÝÕòÌÏ BANñ,ß¾8/õ{ºó%ÊëͪŲ*.Ôl˶\¾ºyëÜÍÎð$[ð Fö»ù¶Õ>õqf4èq.÷wO©X÷÷}ïÕuèì÷£oæNøïØoé®øo*ùE®Ù
+ê¿xùïùÖ/ú£¯¯~¤ú©oPDq¼CÚêÛ¦ú±/ûv§'¾À9å8û»ûH~ì2=å±Õ·ñÆûÇÿù9ÞË!íámà÷üÑßùZüìd]&ýÝÿøÊOËîáþ%Þoþþ<+þÙÿ²P;çÿqïûwKcùP~[cùøeñÏÿRÿkvO
+Çr»reË« GÖLiòeÏA/ʼô ΡQ§Vfti×pN¯=v«×·EÅ®½woqçâxqã¿'W¾ysçÏ¡G>zuêDZg×¾{wïßÁ?|yóçѧW¿>}
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/CustomerOrderProduct.zargo
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/CustomerOrderProduct.zargo (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/CustomerOrderProduct.zargo 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,58 @@
+PK
+'ÑÄ>õ¡}ÏsÎî¨É¥ÀIÔc~³[4éÎ0xuÖ
+?e/˳ßsý;(»ä BSÑínó¶^>W¯;JXö0_9ÜG¨èÉhaú.ó±nPnѪ }qñü0¶¦¿H=WZ´(LY\Õér§c<ÝÃÅÅ-ä}ý
+ôòõüÁ°Çøi£yÞô#æ(ß|~øfÅÕ=J˨Ämxøáá'ôuå%ÊÒbDüß<Áß½xV`^÷Û¶cßáQ¨ï~xhÆ3v;¶ßS-ÞÜ<ÎÒí®Å#ñüC´|
IK7CÌÉDæxDÆü¹û´ªùx·k'$Þ<,¢UÆ»~ÑòÃëö¶<½¯Ve²^%qRþ¹{|KýF·ÐSÙi¥KTaH½'Bômíñh}AùF§Æ£j½ÞýÿYýyÏ>°-rgRÀ£ßÞÛlVtãÃ[»ßüf
+^þå}í7oP´¨ þ0+Ê<)áúëÜ´äõÃëÆ°DóߢU
/óÃá'ºÝ®¨ó¨¶Wàï&;±ÉÄ÷'¾51=o±ãçÓr<oîöó¿=jPOX?YÁ²-õþwm 4^þÑ!Û4éÝ~âʾ¤hþ ßÖ«¨(èõð&IÑMîÇ£ÏI̱#üýºa]0èJÔUENGÈq|Fµé¢:ÇÔÇUwÜx¶
+=J¤TI¬NTJ^ö¯Ð¥s¼×&ßà _Q£¢ÈòÑ¿TQZbýú×77ÂÜZÛ¼Ò¡L4Æ·{Æ
+°dÎkÄe'³ªl*§iÉ4s÷¦¼µ6Ã\m®msu ÍÕÖæúxsu¯Ú\·?J¬Âx5åÓÊ*g£f/v]Øþ§so!Á<ùH
+?ÒÜü6ζ4/I1Nc©©â ¶é¢¼ÀW×:o˼±E«·ê$³¯ðÐ~hÏܦÏ5©ûoE÷JËÒèæä°[È÷MAN½i6¯AÆWüR¡üO Þ|xFþ\ëqí=ng7îxAÍE÷¹Åõès@Í85cO]3þú}N2ÊÌÖQ-£ä¯t?ïj¯$<XTðÒKùû#IçÔÅüÒAèÃÒ#«³Ñ#éç5C¤K´|g}Ú\,«SLavûº²5.KÄ¡EGïßã¼lå÷«
+so³yMÑxë´´Vλyôt͹3ýÏy£9îâë¯ëÓ¸ÆÒha°·Òe-7Íý_ô9È
+ɧþÃ4¾ÝÝnkª£$ü¿RZ¹.X6$õ²Ô]^XA$àfÄíiAyXç̬аNëL»¸Îê°u"³+¼×
ë,w¸æs6áXÍи®)ÉÁuÖqP©©£§»OÝÁùÛéufUy&µaÕpXÍÐjݼfºbÕ?ºbÒtegèø»þpÛä,¦º³ðONÅYl»¶5Õ}^Åå)K¥qç°±÷Oï$Z1öÓZ,cðçêÚc°ÈlXÆàÇZ5» hOÄ]'í«ÀUÂs«óa¦P.P7CÝÙ}Â!"Ǭ±ºYO>!³ÍÔµ(DäØDD0²4"jvaÐ{¨ó×»)ºï;¨0̵R7» a~äcÎó ß0¿ÃiÆQï/Ô
)0ß9³Æö¡ë9%BÛ 6t©sò9ʯ8ÑÝvHdaËÇ£c®ÅH¼ëà¦ÝAzØù±c5à'í'7¹N\©+ðXD×cÇ"jC=Qxöãªð±ØÓ
+Asý²WÔWQ´©îòl@wðNµ©R<Sõúßï]&¾ßãÄ÷kS¥ 2¶_壧jbûOgªgíw©m|mQýì®þLáp`¨~ïBQý®Ss¥¼i«síAò÷øÀ¯ÖfbóÖ
+ürùsÖå¿<ØþsجC9-xCè÷aú#}¾Ûê«áEÃ8âõÍÖRÓ_¿sì~2¿|z¦ ðÔq,8V8¿§Ôü=5lcÂ6¯°Íõum
+¶ùC¾ña |ÄIËÇjmMÉúú>¯/, p §R¼r¶XÍÐÚÛ¼jÒ¶RHG`HÍw}àAïºã³M ná£'âUãï»ú
2kÈóì§gIE£pÞ
+(ä8DþlÕ^´/«;5%oR,µâ&x
+X{&
+<ýÊ úå(¼Bãì¸(¬ÇÞk\ÔÑ~Bàè{
-
+
C¾£ïõh«Þ
+©mþÕaî{ü}¯·J[]Ðp«iýûa¿á~
+÷®÷gæ©à¾QÛ}YevÏ
+«×h¿a>¦\@Há°BT9@¼o°Ä1àGV;42jJ²2+â¡=ÃE¦!$gÃE¦áöF¦r)Q²zRR_Û ÕШ«ÁzEùÚ*4bLiÂlSÕ
+=Ü5éjÎñ~îû^¨ié*e.hÈOôLè«u>Èo:ýüf_¤ã_a¼RÉà'
+a<C2¯¡ü¥Ï:®d¨ë_\¥iÂgOáD«`äÙ$y¶`ɳÇÉÊj&MIùâеÜôuXsbèwù5ÓMÁÙôRa #Ì §:ðÜÚpl
+Ô]ÀY°þ»ÂY}Á
+{®[ºrÛA]¼Â´YÕ+té¶ú¯`h%«×8s?¹x
i÷¡z
iós²ÒI¯º|ÇX;0¤ãƪpz%
+Fä
+õA=§PÏ.£°«)ÔóY0Æ.Ã9SgµCC½¦dOR|jÇë®xB#8fñaq ³¶º yÑ3W
+'©
+0Ððn.Gä¢Èâ¤Í|ἡtg']t^¬ï¼Ä6ãM22zøM¿@RêýOã,MQÌÙ)É×i}¨ðå'{&Å;¼-£ÙJ"3Êò9[Ó%ùªJ7Ð|<Â]ËÑrÇ4K±låd¿¬EµO?âYE¶î¾Xñ^|}¦÷ÕªLÖ¸{øz¼¥dê&:A ¯æ¤U¢~Oë"ÞÌÙÍ
+5ÆoªZ¯·ÿg[©6´E9ZÝeè@Á W´Ì¤ °cBãbXâ¸ø¨,XË_¥ïÏï:gQ±Ûka¾,ù-¾ÆÔUæU·«ù$ÞDvéKß :syÔÌeR3lTîLá K7
+×£ÎÇjÌã´¦«æÓË
+>µVj hzhÎ^«h`Óý«Ö½úY
+óòc$rÕ¼åõä¤NeµB+GÔ¦Fñ1˯
+ÛîvèôªÍ¸íög¹½gÔæì¾Ií«Te²ø¾ º¯¢púnû*7iò®¿*
+É-º¦éÐ¥º:[aó½>Éz_åxAß¡£?üê|Íè9ÛûxW5ÛAò\Îj
"ÊÆíNþ(¥M¶B÷üARbWálòÝÀ_{'Ƥð¯ïß\ùRI]Þ¼½Ì7áÝ`3ÀZ¡¥²ôîÊ,Jú?²ý,*ÐÖ þݧ9óeuÈWs\çaWãü²<(IS}ÚDÆ NQ^VEÝsS9T£Ì§pºÔaËF&9!_^6uY·ÕÌ2°eµç§ÑRZ¯ä«p*'µ,~Ò¶óµ,~y¤SÖl¶,a¬
6ÖÚR?
k
+
+`Ã=kNÝ~ÿSLÐRóæaJòuZ*¤3'Æ'Iñ/"Ëh¶ÚÜ·Ì+Â6 JÒ%ù¦J7Ð|<Â=ÌÑr4KÛÀ¨ò%*L5þ§pºÈ³¿
+0az_Êd{¯å©Á[J¦>n"çúªiN(Tié÷D¸þ âm}Á8ÄBµ^ïþ/o¥Ðåèu]a6
£Àïú¿Àu$Wdß9¿J?%ÞuÞ
+ÚDk°³ÖîðÎ\¢Ì®3WhP3AÍ\%¦®6l.P86ÌÔåg¹ZlhÖÛÿ¶ýE«ÂÍ7/ýþö<§ÜÊl>ãÿPK| 4¹
+Êí¾NÜU-$=$U
+ápÇîÛ<¡§ýy#|+|[>öë(\ÀEõl»ºÞúD8öF#CߤïÓlÿ¼ÊÉMÓw6vçså©ýÛ1yÇO°$¬«®6,¸ú°àÕp;KCªf¦Ò5&Ú^ÒÆzNDiÈ ¤!X;VAÿÅÒqr¯KÝÒQ/
+U R2ê¥!á ¼nT§V¢ñôR2(]HÕ,PI²ÓèB¥1Ö»díñt!ã@]óµ¶fös-mt!"e*u!ç#Gvôµ´ÑF"¢QT]È_À¥T®½ÚuBÛ¸fÑêÇnh08!Þðµf(á´5µ|¥Ù}Í[VcóÖ$Ñuy]pÒÄm!±¡lê¢
2RC^/°Ò"{[è_,d9ÆoýÅA®½6¢y"¤ÖÿXãÑ~ãÇõÑFób ¤Ü¹ä[Säæ±7:{@Rñ|±påFxìóFôfgôºpS4þz'Ûæ-Í`uö)ÜE
+èH<ßãÝÐyK±2S$t"È
+B*Ý ¡
+R8,_ÐËjÕnR/Õn@A¶A"bånU)Ì=Ü
+è:HÆÜrÌ=Þ
+-ÄÄæÌÝWÁ+!´©R¼ vDñJ!ì·äá6ªf,\5ïØ`¿wÛÕg7Àoȧ¡×ªßàÐ
+PÄHþÆIÜ×
+PP.e#sø¤% U
+(Õý¿A«úOsÏõoЪê-¦
+AÁÀ*AÁ}¦Ho:ÛëáÉu] Z'Ý¢¬X:ǾE4
+&(Õ)I
+u !áýÒZFT0¨Ê]Z«µ0çDº]Z«q=¢*vhh¦a²î&V®mTÄ
+¯!<{¨`fX:ÃRôÞfmé>hj¼y ¼¬
8mÚ¶ÐÀ~(¬U襵*
+Ùö|½SdñUqó
+Jú ½oÐ8rÐ;ÉcØ\rôTã²J·®SÊÕߪUß«üoVèrE¦çí}Bï0pY'hãò!Q":áÉSêxÁÄG1ÕüXú`ÄôùAɨ&¦Z^2ȳ8Õ@K ´¤*ÄÑ«¨§Áñzw§%Ð-%u:=úÅ}MìTç
+EëºÎ¸BtEwb¦²b&ÛyPf5ÔdÔQ¨ä&£7©ýà&J¶H_©ÖÎå&ê.}^ïîܤvã&âñIù§ëb'äT
h"¦*?À©#Ï
+ZïÜàpï7îVñèÍN¢«f·
+®ÎþPK
¬&*
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/EmployerEmployee.gif
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/EmployerEmployee.gif (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/EmployerEmployee.gif 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,79 @@
+GIF89a¨Uñ
+Ä¢ñL*̦ó J§ÔªõÍj·Ü®÷Çä²ùN«×ì¶û
+ËçôºýÏë÷ü¾ÿ(8HXhx¨¸ÈØèø)9IYiy©¹ÉÙéù *:JZjzªºÊÚêú
++0K[k{«»ËÛëûKL\l|¬¼Äü-=Mm\SM ð
+.>N^n~®¾Î>0Ü/?O_o¯þäïÿ0 ÀíöÍèG0¡Â
+F@È0¢ÄtÁ@1£Æþ\Ü2¤È×F<i¯£([ÎSÙ
¥Ë49:«3gH-dêüç@s
+ÕB´¨R G}$]
+5깦)J½Zê«XwÂë
+v¦Ö\ÃÅ9ÖDÙ³lÃ¥]ë¯VÁ¥i©Àm)ÝݶèêâØ5ï:À|)ì0Ø·÷*úUªc
Eú½QéËÂ/ȼ³èÀÝ»0µèÔß·6jÈcF=5-Ù_·ÛµìÕ¶1z>ÌùôpoºYÏîý;ºsÕÉÉQ<¨ïÝ¿ÃÎN[ø¾Í©oÞ}¸ôñS#.ýó×Í3ÿùÕëþ«»
ß|øéàyþÁÜ~À[~¾aÅØm¼Hazªé¶M°·D
+bøqgà~7¨_ªH\(¶ döö¡`&NÀa9®X#¼
F í¨bôñÈ |7!¤IDöÈbt?¾ZAg¤&!YJyQî¸Õ^>X_J)Ùù%S¦ø¢IPlq²ÆíF¡sÂMIbdÒèiR÷c
¡þÉè¢Óy(ètZYf£úÈ]¤8¢¥X#Ø)xfX*:JêªÆjª¬J«DÒÄ®ú ªìÃSS¾7þX®cò£¬¬ú4û*
+ÇBÛÔ´³d»í¶
+5íµ5 Û»ò¦Äé¼Jíjo>UD¬¸ïtî¹÷kn¿ßÖe°¶Þ6Ðn¾'ÁËBÃ/)ÄËïÅôü{¿ãlpÈ ®ÀèÀ¿Ãj¬¬J÷`1ËEA|AÌ26êÍ/rÏüóÏ |òu6ëÌPGCûÜÒ,ÓlÁÑN/ê6V_ÝL¸Z-rÐæ
+¶xaWuÙf¶c¯òh¿
+wÜV_#wÝv+cíÔ8]r×%üò¾GýuÆz¦ôÚC÷áò2Þ¸ã#þ.9Õ9RWÚms+-çóf.èGnzhEzÍ©³øç9lþºqõÖå|&E;Hÿ0^¨qiZ{ì¿gàS}áN×íæÍ<ñÊÕºuË~¨³×ûèÆ|N¸Ë
Ï>«öÌÿtüJµBÿ @ÊS«;¾Ïè4V>DGÜr®×?,Rº
+x¾ÆÔëQbNyæ#(û|§{Â0Õ»åÌzÜ#ávDD§¶$PÉ ÁÔ@¦0I»a]²B´°<¡"8¦l/LQ}4!þ`òa¿'ðLøË^þ£þ#'BÐ5ÒØE qulß÷DÛ
N{í³ý(À§¸gÙU^¤ØC:rf6à"Ô4GG%ËK3|3B)ºB"Åÿ-òYD£Y¢È<ZqV\Ó¦,RÄZD/WÆïÑJ7Ú)¿ED3FªL%)اr1 ÂÅN^ê;ù ÅËÝÍÂ3$³Ø8?ÖïtÚ+wª?úÑ$¦rB FØU/iø»Üùsc'èÔÕÝUM½3OÀfmÚÙ¼gþ)¦tÞëY¦yVîMÃ'S`eP¾\3¡C¨äþZ1¢¡½¤?+*ÂÒE¢1à§A9J6*ô¢"-CR·W]iÖèÒ{ÄOt)uGñ¹B;Ý4¦Ñ*(O7vÒðuò§jÛîDTQáèTIª.qWÓx5Õ+KMYÁ8æ1
+dÀ"×TIs2Ðe5]Ý"±¾v;EÐ=eÊÀáµõ¥F
+W¹æ5®.¯KIÉ°Uo³jÛî
+0¡QsjìTÔÐÏ¢oMI&{=lÒô![ßô×r«oÝfÿW¾Í¸¥U«ÐZ×FsaíSqãÍî(ñlaz[SUÖ:GÄ¢
+þãÀ^b0õ#lXÃöY¾ºC$n
+b©BÞIfÔ[
+È·ö*,ϤZq¥»'\Ô÷ÄË@$bï¶|wðÈØA5è²Næz¾D§HnϾtnU·Þïõ¼[)íx¯%6HÂ#2~¡_h×®±}-,å ÀqÏûæ\;T=jò¨Lä'q(L82·Û|l8åнEaÑýYÛ±j6Tàmïh"dÚ¸t×_+[(wË4 ï¾IãÙQÆH¤qyºÊ>ÒU®ò( yâ0
+XbFzô3cm<é¿jøvä37YÞHãÂq5â0áãw
+UÆ[\&j&W«X¨úl±`lå+ÖèR¨í 6ÄbøqúÔo
+³K#cÿi®¥¡Ö ¶TfÍÆO£ÝÈâ%Ç6¶6msÛUýöÞ
+¾Kbx\ä¶U8Ê;'ðµàg9]n¾þB6ÚÝ
+g¶ÌõòÕ.9zû£ÍÏaÓnän:À{¾²¸ì|i¹nkg[VèFÏ\Ü+?¤Ûç¶lØ-TêB]}\¦Ö#ÇtØÞµ «ÄL¼÷nÚ®ÑÆùºY°4¿k\U3½Ð+óJ×ΰKó¹Û¯}gíâýòÍùµØFõØ7ïü%æ1\zùôh&$ÿËxËZîö³K!Ï
+h|^¹HXlÔóL]9j0Dëw!{&~+[ÉW)êH%åfq¤h )uwÙÇW3Wª$bYcø¨{·¤CÉ~l¤Yhg8ww"¸l0p%ä^õJ¢éj9,épy¹DÕ3Ĩ@¬§ if_Wj¹)Ç9MµT ¶øyt\Y`±×HOkh¨8i~N6£à4è?^$ËuLø\þÊkî zäå+XÅ5ùlÅädÑÙÁÉÕIxcgj*¨4Iô´|Ðå©CT·ºù%KV^ÚÈv
+úsJÖÆ/$ÊóÇp¦è&z¢îÃ_åÔ£:3znq7êLÈ£²HC
+Èo¸¤½h¤MZ)z_xB:¤2
+¥&¤!§¤C¡H¥ªS¤a15:U@ê¥9JXJ¦ie¦M
¦Iú -ê Á¢µ¢Å§äÁOl*¡
wø¦*:^ôÄu¨r*XEç¦ÜV§×óè¡1!yØÙþvð
ÙXÃ'©(ZÞ8tlØÐS[r¨êv³up: Û'_(*ªÛé«$éf)J"ùjƪ]÷¬Çºczl9kyvÔ§í´¡
+ë{ªTÌèýJt¤fIJDø:±áú°`· }Ë%K~I·û¨8'56ý¨îI{«¹¬ZÄL8z¹*2ËõWþi¸F/KLÕº±åç®ç'w&éF¹kÄ1P¨ ¯³ø§©IôÇh[;c\FÃ)bv*©i°¶Y{\QÛzFrÊ;eÎ*¾¶"o{µ
+np^¶¨6¶V¶|K±ùÚµO
+¶ ¸£ ±ò§R«e°Ô J®ù
+ÉMï¹C¢rªÍJ¸{ýêÉ«ÿy°·Ûºç
+¹Öë!'µ¹ï¨¯Vº6³èªÁSþzIæ{I¯ªPÍ[+j*¿C¿ÅS¨lqªcö[øÛ¦é£5×¥é±HÀm[: À¬
+ìÀõÁ(Áb$ÀYhÁ,ol£¼¢\¢;êÀì;¥ú:_JFaúÁ Ì"|¦$j1,Ãï%Àg»ªCR§-ˤH¢¿©Ñ¾¿:x:Ê5·×¿®
+è=¹Rµ«W<$é{ª.|+^ü6zÚF
+«ªWË¡+¾Î{mîÈ©&Ç]G«¼k«ÍY»ãº»¸
«|¬¹öA¼:«³_ÇæÇ6xˬ®ëjÇr&þ`¼Í*_Jf
q,¿÷`ºÕ^û^~W»NØü*'óªA¶ ½Gj¦®± ƨÄx¹_»my¹)[EA{²n:r+ÌÕ©h±¹wª¼¿Â}$Ë
©}IÓ²l¼²1ù?;~«Ùz}¥
+ÎÙjÊOj´À·»·ÚzÜÎT{É©M[<v³iɵ²Ì¦+¶ÊI&VK·ßÌBûÍil¼sÕ\·wPÆ,ÊhË°ÊÊ
+[ÏðzµY»ÏpÛ½-¦E¯øl=ÇÙÅå<ªÚ¶¥ÎC»É»°ÙË-°4
+}LÞ³ªÇþƺÿYi:ð¬.$Iä{ÙßYŹ;¼-󴻺ÑÛ»ØÔÄ\̪º&k©¼Ü¼Ä[Ñ.Cî;¡=ÒhìÁ(üfݪq»oKü|ölMa4ËÈ㧨Ã:AÎé¶}]Q
+ÃS¼¾Ý£ý2ÑÙè»Ã<ܹ¥-êí§-©Â¶Ø´ÒúrÄÂxªØù±½mÄäÔOÁMÜb,N4
MꮤEbmwbw
+¤Êg\ÆZgÝmKÑÄXÝþZòØÆrmÀ=ªÓ½©ºÜñÝ+ãÍÛApÝz|Ô|Z¼´<xÝû¬QíßTàÜ»=^»åÅ
ü=È`XÜîmúìeL,MK[gµJk÷
+©IlðÑ3}ѽ·âͨë®ÒOÔâuÙ·¿UaÃìC¼°§ÓÓ5$ýW·üf½Y_ÁÕ«hâøí}»[¬9Îd4ëvy oÍVÞäÕÐ|ÒK ¼Vy&)LÆÑ`Õ4çåhýøË2{àO~â*ÑTÎÕP|¹e¹d>¹G¨
+}{Î
+ºzDèxç»ç#è-Îç Í¢%nÜ[êpãɪ{éZ«æ6PÏ»në7®éw®é0söé"Õ*k zȦÔX´+©»b
+tä½Õ1~k·´àüX)ìºöÑÈ{Ó®L:=çûy½MÔ(4¡½î :Ü
+|ÛÞÍ9)Û¡±îNîúcÛ4ÞÜïÞÌ*U¬]ï,tï§Û¹-¥»ýï
+Û ÌðIêððµ=ð¬Û]ñðíñDZðßñ}tñMòhé+Wò&ÿñøò½òݧ0@ÆóþnÚ'ü¾éÍÜæ®ÜÌíîp§i8ß:2Äã;ò\¬Åo=Ko-¯ÕTôXW³QÐÄ¥_àÖõ
DÏj
e!Ýèm¡Ë-«3ÌÉOoõ~©Þ¥Um5o
+ç)¬U.iot~ ®ä,â÷|üá¹ÍHüÀÎøgç¬Ò]NâÌáÙ$©çù¼|þÉ,ò+¼þºö¡Çéz¬ë®ÜjKõ³¶ìêNíK}È·ã¹z^_fîân\è-æXf¶:d[a÷,ü2ý`2ÉãË ËûªmS¯ÿâZ"áÁ×üò¬@ÎËÙúîíÎo>üþû»Ã[ûJµÌKĽíæc`}¼²
Âûé/¨¯³ÝÜ««ÉbëÑI
+XéÚ¾ñ\ßùÞÿAáKYL%Ò%Rv ¤ÒÙÊdª§cE;âºÙfØ5ÑèíKÙNMßÒ6*\o.O=þn²«Bàä
+ï¾Æ"©V%§Ê25+;=?ACEGwM¹"
+öÿ¨0Ù%ùeÅV7ÏH{M'ãRgý@rÿ`OmÉ!/çòuz}~±mk-¥o«E,Å7ÑÓ³µÙÛÝßá{þ¸)4r¹âÌ¿Âé=ÊMràèÁ
eµ¢=ÊgmW¼OÜìùóFÁ¸zúÄEü Oú¥J¦1¤Ä{
+±qhc^A!ÐÈÊ#yÞÌl:V:è6M=ZIº):¤Mò*ä)T«W]©kWrR
n¥ÔlÙ±fLU»»§ÑÎ; ]u`Ûêko_¿\á-ú6â_Ã,^qcÇ?ö*<¹/ÞÇ4"SÖ¼y³e9ìùriÓlAV½:éÒ©YÇÍÔõ;سq_}wox·s×¼Û1páÇggyó2Ê}GþÐyþuÙÐó2·¾½óTíÜ·c><ïàÑ/Zk{÷ïáÇ?~}û÷ñç׿¿¾÷ôÿÓY¯¼ ¬á<
+Â1¬Â
+9ì³AÔÀÃËûî £^(l¦æëBÄHQÆMôéDëZQ®è®4EÄhq*¯JÒ
+|xÄñBL&RÊ)Û²ì'ª³¥I|Ê1×jIö!&°à¦zäÀ ¦3éócÌpóÎhÔdbúLMÉ,ÔÐxÌ´s£7áÜ@K:rBóQä´SPF¯Àó"¹¢<TÔ! þ§pêÂÓq®)Ì¢E:Í¢M éÉ?§¦QyíÕR¯J/^ù×n¨qØq2}3k-f1_©¥¢`Âè$ôäô¢gõVAG*é¤WÉõjÙm·l±¥FÙt£K½4he?5$±}sõ2TwÝmQZÒåÖS]XÉXFX~P
+ØaB Î`UöÙ=*¾eRpAN8ß,¦d`©å¸X¹ÕvÛ½1egk(gYBÞå«uSQîYÚjHnÅäQÞ' ¡6" M%Òg¡zK Ò´ÆYS8 ÝS5lº7¢NÛP¸ÂÑ?þÇîèX°oÄn¢õUßctÚ¤ÕÕQÉ¿V\ñè?L«ÿzJ|q)ÇÑð+|òÍ«ür´zÄó=ÿ<ÍGO½LÓ#D]õKgÝ:×_¯}¥Øe¯ÌövqÏ9Úw~9ß!¾eâçÄøå/ë=y³g¾Äç©VúëÕâOûí¹ïÞûï±?ÔùêY>üóÑO_øñÉWÍ|õá_þ´Ïú¹ö_ÿýù_j;6¬àÏ/ïëßÀ Z]c*D'öeÈ
+´à18`¹"b{²è%Åî-haLCÎpz`þòZÊä´ò=ôá³Á
+±E-ª¡ *¸E1ùb%TdÅçmãÕX at 7Î@cùÆ:î©»#é¢Ç>ôdYHE.wQ"II®Íä%1©º?V²,Ìä'AI¡éK/ãdTBJUÎâýÀÔENzòWß³å-qK[®JÔÂ¥%¹)XýÚ¤shÙcRL½t¦· ähcÐÛÉâÌD0³|Ïô¦oP6yM3_74â27trStßtþgqZ!í7cZ6uÏDZS4Ú|ç?ßKy¶êH;'3ýÉE~z
+mÛ$HqóT 7Z3Z© ʨCA:¸@0üü(©2G§0Ýå,
Ë\Hað¤±'ÂFé´µ<=SqòB¦Ä¦°*ê.¦EýÍBÑcSªd.!©ÙmÕ¨kZD5êUµ±N¤Úè¦D°ÌÌÃT]"\Ö@=«G¬®ZÝ*K¯²$ùªXÉ¥®FðZhu
aÊÖUºõ
+ë` ÈàÜcyغÖu±«¬eEê8¿N-iäÑ^*XÑ*³°³ãþXëØÇ®¶±,kåºZÖn³çDV¶qÄq£õBKÛ׸g²°5®jaÛZÅV6²$5a±ØßfºÁMËa[\Õn7»ìk+ÛêF÷rÒî%ë:̹4+êÅsO[îB¹à=®v»Yëö¼ý5@³d9õT%5ãÕM|[\Ìf·¾ù/ìÜýZÕ¿¾¥¥fuZnã)u·ª)ÊÃË6f`G×Â"Ãb¢«sði5f³,Fã='+Sñ!YÜbB3UæÚì0T8ÍYUâú±J4¨O)OʹòÍzzì y%eKþ¹¼Ù¥Î¯übû1¹H+\²yb«ÓÌgFs1üD¹#>Z
+ât ´¨,Eã¹½õô] IëÒ®|Ë=iCæM3:Ñ.sz*)UÐË <¡I¥ÔxÍyÕ¬nõlFkª²²q¿ZZ¥êµ¯`K
+1 ír"F±0WÝ|öylæi_ø[lY³@8[ßw´¯èê´ØÆa0Ð*q»ìÞï¾
+´¤¹d·æ Æmç4YsPÐúæ÷oým]H¸;øÃþh"÷RÀ¦ézO'ïzÇx9£³*+ßgL^WxÏ%æ'á/øç
+ë%nê×"Åáëá%ûðpD>s²ÔÜæ&Ãb<p³ÆNú¢^ì.è8ç0OºÒÓt¶YnïrË:NJó ÚÈh¾ö«Bãlí9æûcë^ÕÝ»ój¹îWµûÍ=*âpÛFTü¤z+øÁϽðE
(²µÍgBçÞ´Û®Îs@?+dNÄÈôÊ_Ðy{yp\¯jÆõ^½C[ÿi«À^÷À{?|ûÖ¾°5GÑ ÆWcq¾['òeþfW¤Ä«ñßüÁ®×Ifï=EÕÑ}dR?¤Öß*öAnrcÙÞ¿XIf~Õ¿æG*úÕ÷y±_ú8aÍB,ä诡ìo¡ðKtͺa+ÈFün;æo
+Õã
+½ìÍìØÌíÕúîì(Åí|¯ÍÐÐÔðÌMo8þ¢ÛâPÌÔÍÙ¢¬Êñ±?ò°öñükþÙîÞ"Ñáìðh«ù
+5q3åzæ"
+°¯èUÉtci1ApöÈËEZCiÍjætqq1òXò²Oú:Ç_Ô1b¡'ùÐÂíê¬f§rÍmz²1¶ñJ°aâOªÆh¥
+
+ÎÒ!Ñ"íL+QïæI8!52#þ/8
+.]^ÎÈÝþ¼pÃÐÉþ,"ÿ0D0S DRÿöRÎÆì¯Ñïô±-%³(³2Gæ²$q3«)5ßO3'£G3+J³.çj CÑ
+bRÈÊCï G¯mÞäds6a¤6)÷|1Õ®¦þ$6³:½1:ÁiAg4q¨Þ¡¬:÷¨%Wì%k±ý¤4{1 NMäiÌó<§tÔÍraP
ê1õLÄüÉe.× è¯Ýê³Ð3ø$òæ.Ʊ
+/Gð·æn&²<ÔÐo O
&úpÿ)EáS]s!ôBt±FmôFù#?ñæTRýEýof>Ó"gFy¯HÚN5[Þ8óAHôH©tynsÄÈø`t²&gÂG
S\eáÌ1V@´JÑ´vüm`.6ÓôMÕôþÒEà´NGgDY'íþtO³ç>×OÕüô-µP5OMGO
+uQ«dP Q!µWõs5R-ÕZµ.uSB²ò==+SIõ¦2ýË«TY5H0áTFaÚúzÒ¯Ï=;©U}õ²I¿
+£¥^îñGªÄÏö~µYD
+ñEE}T!¿²ÙïÿÞðäµ[¤ð kíc
ã¦õCeR¼u]\=æ§PTÿ$f;Ã[³*Ù5_#T'1ïÒ¼ôt7[ð%00`·[õ5a»<GCÚÜTa!ö4x±Ë2F5bIuRWc9¶14¾:6dQ#SþePdMv(>NveedIeaö¨\VCb¶f}afiÖfuäSwÏæ´Wwvh1Wß5Úi5hV£ºÍùfUW£=O¦ÖÄjUCeµN´M¥iÅÖ«²ð5uûu_èél{ÆBªÐvWÕviǶnO0ÓÄ0_3[«UXäÕnþªýÔjêí_ÏÔnÜ,5ÿ6$ÐoåD&KεIÍn7s+
+Òrù>W^w¤ã5XTtJ5wue.Ðü8ÿ8Áù`/VK;Âô+X÷wõǺwhëQqÃÍ8iÐx·2nSö7s×¢7q§ª×zqöp³iqô{Á7ºw|É·|Í÷|Ñ7}Õw}7¤
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/EmployerEmployee.zargo
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/EmployerEmployee.zargo (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/EmployerEmployee.zargo 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,79 @@
+PK
+àºQpºÎÅ;¢ÊVÅtÀ*U{ËkìÇñѶJ÷\bÊè
+Ìê"£§(fôgQº<µÀêCØÖ9·þ¢fW
¦ÔbO2ºF³nÔ¨K¸+ Hí¨EÏèeÇ Ñ»þäºl½ZuBÇý[?ó×#<åuhn§rè !
:5¡^Nýê¡Ýº<ósÁÍeÝÕ¹¸Æ*=Õ¢ÃÅB¹
+]}PK÷Fl&
+8(
+
+â,KÙ.«i§'2àìU¹ê3,u«-µôLKe<<Ö
+q»<7`C]þù}MÖm¢4·^Üþv(9Î(êüD«fS|þ¬æÔÁði Bôa©ºk¬QðTo¬NûEU)ÌÑÒF¾¬+Wm§ÉÚpÑÕóWÄ
+
+I>òìx¨ö«ð2EäÙiç) F¡æÕ[çÂKÃe8#!!c~¸FSGqÃ35à°Y¦~ÂùìÊåay%2¯qÛ qk¡.¸ºÆ
Û\{¸ÍÅ¥ï¾ÆmÕ[µÓÃ¥"WWðÖ
+¦^ªÇà
+*ÌÛ=xK¢¿¤CO¨öz°çé²gyÈRÄ2^·TiK¥AK
sïßRCöú9úm,ɧÝë¤ÚhÏå Äp^7ZWíÍFëà ¶?£õ
o³Wm´l£EMs´ÑÞn´2¢ëÎh»(ÄÁô
+ûÞÑ|ñzïÒt?+í÷[ÿ½Ëo0pQÝÓ§YqÝÒÀPSX¡»¬Üãlåõ:e}Ô*±ÎD«ÝB;¯VÀ
+ä½g^àJóX7ugpWUºåi«;¡c¸ªün\U<08CȨiù±Â5
+±ÀP0Æ´ü
+èèõåd¦pΨ{.0|~5PÚ'cá5ßf¦pd)Ýâ5ïeÄ°F¡iEUòË}
¾CñÄ
+¨Y/
+÷Àà
+Ôê3
£¼°Pi#m¦ZµaøYÃи*)¡3Ã4l.{öPYÃÐê[¼gÚa®eMÃaaÓ@MS¸§
+ñ·»r|øTjsFgq@>:giàÖT8Qj¼%}³´1õ«Ö^ÝZ«xuý8Qxíy5§¾ù¼5:&Ô¼º=¯6ÇØoÑ4q.j^]»],×2·è[I|Ålܱ%à.&fz-©ª°@ ä_Àiñ]9MüòFÆyWp/ß/Î3q;4*{óÆb¸=':kçU%eôý9»!¼+&.6jYÃÐÊ]¼_c<D%!±¸i%%S²øÂÿ"±0sPÂõAPèL7Mæ? U>6é>ÒÇÅ#ºãâǦ
f°`Ô?5ÌCÈ4øfÑÀ$öCl[ýØ´\v©Æ§,J³é]ñíò¬ß_Äê<*LâK¾/AÍ7Öe¥Æ|cjÔF[7Z³¸*Q¸I{£µe¨®:ÑÚ@£w«¹6Ùò¬½Eî,`²2ô0íaÊ6Ðq@lÍd1CMÂÍÄLVÆÃ,Ðz at 7 ¡îÿÜÞZ)0±3LËÓzhk¥j(Â]¬UVZëáGÜ^ÌÔ
_¼§m«óRÎ#îÕ8ZrÍðR:ÜÔ0ðE ^w"A
+¢Q¹gIûüÓé¾ÛòlÊãCD¶çx8vÆî\Ô**Ý1Dð.z:yï0ÙEÍ6":¹}8³k1ÙE-çJt8síÚE|²WËxFòé:Ð#a¸§ë6ÍY;óF <]ÔØ
ë3cxòºJX+¢èøjï¸øNʲ.ê Q¸b¾cGÓEÍèéˬah|W1]Í£rq·7À²â3DªÊç@"kZ±«wL\<ÂRO¼ØÆÙÔó_e¢/ªYáî(ô
(Ý})ï¼<C¼ì#¹%$/j¹ÂéIhäÅe
+ÏÖ04Æ«JÞ3ÆØkÀÚ>VHì|ÔX_
kæâ »þÛÏ 4ÒÈì¤ìBããnº(ìüQø¨asݼvãÞö©=gÒ!6¥}\æä3±¡Õº*yÇÅ÷Ø8JBÂâûÂåhæÅ´D¤¥A§ë¤EáDÒÒië6iñÃÒîÀ_×»tùí~yK¼^Å»4Ý
½Íÿ{?ô$Z2®vK]µnm(@Í:+7ÆQö®P{WÎØFÖ04¼ªJ2áUÀJX¾g$ð*ຠûÃN7yxl F+L|N kWØ(ðKDDc£æ6ÚIp®p¼6
+ÇB\
+¸×XÃÐب*)ãjH#~þnÑ [§!.¶vZXÃÐú[¼clrOýaûÐÛ
+<×±½Âùå(Ø>è4]Å¡ËɼçÂ,hjÜ¢^_Uf at z»
+zܬà 8¯»-yâu¨ësæ%Åçö £í¬óÔ¡¤Ì
+Q£g:¶=EG¢æÂF:¶v)2s¸h$Ã2Új#ç°ñ6vÇàñd>|e v¬S¡PNèÎÜN¹·FoLôæÈØxÛ2P#}#
Nb¡7ËpFÞ,5¶6²JYÃÐè*)¡Ã2¨ Øç¹ðoX*t.kí4ù8(ZPKRñÌÕý!ÏRp5gUá'îÑM»l÷°ÌòÎñ¡ýuѧ^8äABõëG:e´=þ7í1âµ%{¤SFk·Ð2@ĸôdrYfpɼOÀ³Í&TVT
Y ¥`T)æ¡QCÂõF*Üû
+YÆ
Z%Ò+YÃÐÀ¨*)ãƨEò×l£®H'uÖnAãú\ËäÈé´,¹s:-3§ªª®(ÁÁõý×»°*ݸ^gtVåABÍètF'®cF§e£ftF:£³víwÀÈæ²ÇþmÉ
+ì4å:0R¸¦=
+0 E÷¥Øj`ÔÜpø®¥ì1¶
°lÜP: ðkU%eÜð¤ËÌK¸áiã:~ÜzÖ0´úV%ï×;\öØ®w¸IgÃãz3»j1¤(AÁõu%9ü°7öüØÜt£(úÛâ˶ÛuÔ s¥Ük¤9o¢ó|}G
+£[0^TÙoRt!%ç+x宾þiÎÀV$¦aJòݪ2»sí§|ÅxfËýÛÉÒ]AÓ9IÕKñÍnµÿÌ&ùý¤äå|ÂÕzËfQúB²:Ó¬^(þÏ×$ºõôÅZ'Ê7>}Ý-³dß]~<ôâ?R2å'ÅÛñ¦¦Å¨x³(-ýK!\¾PQ~ýkó?óÕr·ÙþÿÈa
ÆPT¹É£Ã]øPý
³+¯0ÇqYþþ6Ñ*Þ ÓÏnÁù»ÂW`7©Â{ êk;wU¯MeÏ]./ÃsîrMjî2©¹K©ËEÍ)Y
+ØeBe»eqµ¨Åu¹îiºëIÝP³tªaõ
+·µ¸(â±ô&ÀÇ
+19Q¬p-Õö6·G
+al6´Ù«¬¶ÙºÍb^Æ
+ùC°Y¡n¼6+¼ysÙa·qÆ
+ûgïÁ¤ÉW¾§úª
ìqÖt¯ÃÑk@%¡ð¶H×ÆEP+Ô
áúSîâ\Û/e²xË+¡ØtCèì57»Ú:Õí¯îOjX.´KÃÆcx¨µõ»½áÙHexìJ½Sja ìv(>uzûr°H ÎÕhÁeF7Í®iŶê:!
+£p¬JÁ¶a°R°m ö"@uGÖ0îÞ-]ÕJ²±Ùe<㨵jìõ¦A-ª±Ú·ýÔïgßÎw0ÔÉ/~7x¡VÛÀÁu¡Öv
Z9nËÎ0å³ÖÁ°ÎÖáî(\qÖ£u¸,Hpg
+Cúª¤
+ lêãü5EcÅg¾¶ËzuB}í4Y)ÔÌb¢( Éiç_?KÃWLTO²Â`¯ÐI74KÛ?B. ÍXöae2µeQ¸4c1ÇزÎ6q©¯®çP»
vØí«¼g,Ø.
+xc²â3Ä´
Ë~uÙÚ-hÒR¨ ) Iå¡Ò21Ì*A1àdRôà08ÇIº~ǶÅu»ËÙIÁ¶0u2,²X¢Ê~¢P£CmºCZé¨Ëmó*!v²m[á.C¶Û)¨P¦ÂÂwW
+ÒlÚÇû²Þ¥ËÜr2Ý"|<yõÔÞ17<¥'/Üî
+ìB¼>&¯À=ÒjÅ7÷À(
+"În¬M:¶äð4óï.»ü]Ì~11£_ÌÝàþSJ.£ÂJÍÎOgݹâùêT£zªåi;¨$Ü¿21÷jzPjTÔA¹kBõ6²Êsß
+ض¬í
+;ÑEa?
+?i=?)5pTá³ö&ëÊPÖv© k»@MXm²5EMäS¸çÉÊPv8eAã|ý9Òȸj³¨È\Ô6K Â6+2váüÒNmÖ3Øˬ¶ÙÍz
+vH¯Û¬ÂýÛÛ¬'´Â×f?öPz½`ägû_¶°z.f ¨y.*Ç·/®ÌÙéé´¶r±;M§¿uZ'>î=P&>z¨¡¬ÐÖîÑÑ=w^¬x
+YÃÐ bUIáEâ2äy>´âH æq{e°ªZQ¡ÉajÌÂ1òÉa¼@®ÊZ~L:SÃ;.¼²Ì²¬¨rX
+·tSBïg¡ê=,£Q'µ¨I-³¹ºÚ<⤷Ü7ïgH¥5ßg¡KHÄCÔY¬®£ñp9-!jNËèÛÍf,UÉû
+}`Á®4Ni9AB¸
+fFÊè«tÆÆvUÚÐØí<VC¹¡±c &´Ìî¶
íc -Ð2
+X°¡±]URB'cÐ -Ëæ¬øàeq\òt`
+CëuUòn9c¸
+Þ@¹«¯ÿæ>iè>¥C VÉ+gØêÐ1-
[:&ª?v®pD%N«CÎPmZ*;¸ÂؾS£A«còZD ÎZÒ³jøn¬p.άô1kÕög=üÂ-CL=Âý7ß¿ùçÇÅu²ÌþïüßÿPK¤9X·
+nì°tÚ·/®ÿòæ¯?þöávÐw¿Ý}|ûN[àÕ>Û/Ðù=Lý$<gùÝâ$XyI_ÐIøgzAâWiæe¡¿K³äâg®.áê_ï~yyiú¦8çKk½îré8K,]ßúc}Ø°9¦cÂíÒÕu}ñBË?'ïoùõZyͨ¦¾¡£úÊæÞÇÞ!|w²ð
~=Ü,^ÂÅ[tÚuÄsyïÂ|Ûxè.y%ÿí~§
+h\±(8©á
+©MÅ'EܤHk]×]uåyÍÕÕørue5{E¾\kÑí,0]ð°:'0
'¬Ùñ ëôßñ°NNöïÔ½JÑÕ©"Vu»t·Myû;ÝmyZS9îj+{EU¦
+ÓbmZ\·I
Ú´h?¹®üöº '
+
+z±tC¤W¢.-µrCÜêÍ
+õ«p¬n¸ÒÎ(ÞI¢
+Æ8îçhÏFNEçÈj8G ´fÔt"³`MäYýÎQ%#«ß9RKá`ô¢êõ¨féY
+ïÔÞÖ\
+ç·NëY
+ï©-ÏqÞþrµe5üÞQ®Ûf¥ÛksOó
+Á³
+QÆvd=#4¥¾«4+NPXÀ-c«h¥4ôQî-þ«ßP±D3.
+ºH¨õßâ-Þöö\A')ïÊÇ`»i|}$Ôîÿ/IôðkÕôïâÌâäáÇc|iNØZ£0è¦qQ$ÿQºPQHpha¸78ÒqpÌÈøç³+LòJëËùçôF40å¾\Ú7wÛ:ö.
+ßTï¥`JÁÇó¶Ún}Cz¨ÖJõªl.ºùùôx8J÷|ªùá×%uÛ~¯Kìn¸ãmÚ:Öèõ¶k6t*¾/±{2mQª½jë§äó-¹µeRm)J¾1±erm
+ç I¤Ü
+.°s£þ%IàÉ@Ð_Âïì§HÀ¶Yy®ËtíÁ\QÌϺR×lõ4Ù,F1ùTSÑ#2q«Óô»BÕ¶uúí{LV.Ø¨ç¶ PYÞÚ½t~®i¨çµ¤ú]¥ïÛªhåPCþ*,·®´åàØz¡éà
+Çá8ì9·á8 ÜÔ$ÏЬtdâ&Md8¸ýC%ý·ßoP»2ÃÓk24ñÌ27ÓmxmÐÈNÅûxÓZnÃb`j˱¯ítûH!Wl³Rì¹æfºÁ@Q¦37~(éøToT57ó&i¾@NlÑ+â.°°ÌÎOaND ý{¯ÿU¯+ÉBV0;úºº×Mqé¦äÂgiæC͹.gv97
U®¶,Í6åzÞåÌ®Âvh5³4ªÔKtÑ£+⥰ØÍÓ¬Áï·-vl
+´¢)©ùs!äyûH¹ÂW3S³¾+e[~¸Ý359øjfjþâÉ0?îf~&Á¾«éã×8פþ*4*gOÈB+³Ó4öÃ=¹\<-Ç2èüøøðC õØõÇQF¢~µ}q*{ïasµ7¾>P^Ãkg/»§ãX!d:Î8z¨®+zNï>Î!Ô?Æ`sëhâµe-¨ÑQʳRßv6
+
+
+C¹íNq,½%W1²CÇ î¤ÿ[ú®ÀfCä8t²Î°Ñ¡ÓùÂn%êÒ¢v5B!×W«¿6
W<¸çýG
+B³fW°íÿ¸b:H,ÕLê6±,Q²dÉ,Y Ásüé¥ÆKû¶³åeÉ£¤eé%-kCâÔv¶èä§2uFí@°-%K¿Lø)dz¥8,Ù£dÉ%0gYÂIÀºD./L at RZÆ
+®Ú|uO×æeÏo¦úB¼Ü?Ý\ n/A/]!^óà¥c-Dë.4\鶳åYiʱÒi>ç0\8±oý;颣ÛÿPK|ûóÞ
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/full_cream.gif
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/full_cream.gif (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/full_cream.gif 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,79 @@
+GIF89aâÕ2
+
+
+²²²LLLrrr???YYY&&&ØØØÒÒÒpppßßßxxxËËËåååËËË
+H° A|ú®l;È°¡Ã#Jh0¡
3jÜȱ£Çì,VÁ²¤É(Sªl'
+É0cÊI³â¾8sêÜÉS\Ëÿ)/{
+J´(ÅR]Ê´©ÓyH£(}JµªU«Q¡L½Êµ«×YlýJ¶¬Ya=˶Ûi¬}K·®Ýxq̽˷¯_pyìýK¸ðÛÀJ^̸+â$K¼ô1È3k{s³çÏB-Áº´i¢¶
+¥Òs%´Æ%<L:ÿ\§ÞðHÁ¼njª7
+¢/K'bÌ8ëC8?dºPlO«ê4 @³À¹*ª1h
+lÜôºMÂzûÍÍpÊ[qmJÇîÈ{ÜÈÉÝC7 ÈjdKH°ÀßÉê©ñ 8¡.' ôl:ͱo°ð¿=Bp8úÙ¸Só`$Ø¡o`Ï86ì¢ÿd7Kzmär"Üݲ©1Ùzo7?x¦7ñ·?»]sCë¾Upöþö="Æ-?»Þ¤«Üv
+>x¶9lþ<×£::²zóª<.ôêây"Éñìõ¤nÇùnD
+ÃV
+»±õ1Ï
+Ðf,«âØä×(ÍÐ-¹9ÿ`^zª@=ð=©}6ëÙµä§/x K ãQ"YÑ(i¿B ¥#kÑhph@:$³I^2OÜ"ò7½PnPºaáU©¨SZSÛ£ÞxBN
×Æ@ àüZÉ&UÍO?À>-r']Ïÿ¶klsfü×Ì@®Ä±ëMzX6¥µÄqCUqxt±Ûe I¨Ó^O9Í(D"TwXÈ~0³#{fO¢©Â{<à\ÑâF*`2*ÙpI
+H¥L¦Â<=`¢Kz
+p®ÔõÿpæR*Ï+
+¥DxHÓ¿T:_Aê ÂÓö姤LQz¤ILS´Ô¨Òeªª*GXîzÕ«-µVôR$Õ!gõËXTÖ¤!oåËZå£ÕÄÕ *È 3×øÔU#w-ÊÙtOÝ«Ys2ØV¬õ"UÛªÀ¤±½Pd¥9Y¨ÆIJÁ¬a"¡Ö(à´¨MjWËÚÖºöµ°lgKÛÚÂöM h"ZÈVå ®pKÜâ÷¸ÈM®rËÜæ:·¹u+c ;Ú¬ã¹ØÍ®v·ËÝî"7º®c«;u$à¼èMÿ¯z×ËÞöº÷½ð¯|çKßúη4Ùm at z«ÙßZõ³âÍ,_7û_´¼.)0qÂßûWÁºGL[Íu<À6û¡w,#ç§ÎÈTxCÍ7qxø8 ñDF/í¢,=)±*À;Öi
+A©0£ ãÅÀ±#BcoLlgÜ8qø(:-J=jÀÅôù:¡pÌtü×®é§DÌÅÔõu§|XË18Ü$G4¾43ÀYíãQõPdª+óRÈìò Úá8÷wÎt. [G±ib]c PÕPÌâ±6ÿõÁ©*4£Áåâ8ÒTVq¿·¾K«,³Sñ%dBÌT*qºP%¼7z¼r./¬ARep´©xR ³°¯G1å/ª0²
+
+!«PÞ¢
+ÿ÷'ù»ç/
+õK&Ä1
+(¸q1¦wHÑÛ¶G]·k:³AYb=a3=í'pðÀ2àf185¸{ëàAÖ¦(C(»Ó;v1å#"S>+CGbÐJGlò LXN8Pèy!ñ(Vä#èS#°Ó#)öò
+ñ
+(
+ôH)ÂMIÝ@b2Ïè¿Á(ÿc
+FÉÂ&¥fj!j5"jØYi."ùÓ
+tm¨#åâF*dbmÓDAÁ'ã
+þC(Þà'ÛÀo ñpÞùyHÑhpQ3Ý0#qTó0'Ó6_6 Cr´hÿòXÅ@y
+ì1>RB³KÔ1åú¢ÚŽè q?ß
+
+k[ûiK ëKg
+ûÛ;eëË+cÛ[ùZË!kb%{'[)a+k-K/«`1[¥·3;5[`7+ùA°úä:U j`§}X ×µR;µT[µÆPuØ'lÂ8óªôPA®%$B( ÿ643öÐd' QÐ2 j4ý*¤¶£Ô¶¨ð¶÷$-UómB{R¤g6Ô6ðC3å
+»ioçD¤¿¦ ¿a
·s-ÂV?ª:'ÒiNC"±i¨CJ<ÈtÀÏÑëzGékL$j@tоvLË#NtjïK¤`ÂñHI¥Ja%ò)r¦ÏòÅ
+GCÕ,Ú/Îë¥.½ÄCâ6Ä:¦¡Ë©<)¥ÖƶÁÞ¡x<R,T\Å$®
+dCPPÀ:ÒQ&¬Ap³±ù©´Æ5)!lÜ0t´$pÌ´ µPvIx72(âæ£ø*=êÇÃÖóU°Ë²LÙ`¯<˸Ëÿºü³à OeH13ns&q+»ÄK"Ò1ÜLk0,7,1=BÈÇ"%¹T@,Ý §Ä'M7",»0ºunÁËVC8 ænv¢1ÁÖ!'÷v
%âA-,xrÆôѼÝÐ+ÖBäG!â'G'(¢;m#"¯BÄ9#Hbm"QÜÊélë¼oáÎkS5ÏB"þk3(5çôÒ9ã#:)JÝm:¬Æå º
+SG23PK¸Á×:?ô)$4¹ÉzN-ºj»3Oíº
+^¨Ö¥Õ3QÖõqÖYÖ;\«l-níp:×Ü:ÖDq×M&ÍjÍ=ë׸×<ý`ZÝÎ_M
+MuÝ}ÝÍmÍ~=¡}£]¥Í©m«M]¯½±]³ýµ_
+¹M»í½=·ÁýÃÝÅ-ÇÉíËÍÍýY±+ÝGüÜ;íÝb¶õ (áØ%®@vzäHÓ³|]®Âá:\ÓÞð³öÖ:öýî;Á-zuHAëó/ÿ'F@ëB/lÿ=ÕmV2/õòÂLvQPÒcÀ%p(\²P¢5</a¸.G,H at t(: Ø
+ÕRÁ9yB³"â.'âa&âç´203ãäî
ä¨õvL¶;uRaÛÅ@QO~ÞïmîVN6qO·&BÎt-i2ã¿äA>¾MàBwº0± (Ãâd8 f]s¼×s¾µR&ç
+Á
+Ý3r¾9¥~Y+ó(>f
+ÿ9Gsmô,46d#sÆ2L?ªM#('èÚÅÎbF ¿ß¸±IÁmlGc3+(£9sô*PC?
-0=6Ò>ÜD"8¯nCÉI¶[íÚm?é3ãëD1ëºUëzâ¯[Ï#svn^¬(%ùm5oôMqÄnð\a´>»î&Ç{È1°è¨à³A?/ø¤)0>æ>/2c/ÙüÊ\R;yÒ)0r§&n ÿ
+üN·ñý®
+(è#ra"b(s*ZÃèßÜÜãóCnòÿfÞ+¾±«Ücftg>2å¯'#Þ)ÐöK¼K1ÄÚv÷ûþàáï(."¿iIð)¢9t8÷ÓnÙ ³0
+;¾¤&g?H¶rÆjC uG<¶ýÿâ¡ÝÜÌ*ß_3HüÿÒ
+¨áqù
+hßñùÞ÷˾òøþµî¼!#%ÍØîÞ&13Ãìô:ñ5CÓ(À?ES'ÛU_aÅ*Û.cmå8=ue at o}
ÏX»1gÝ¿rw;{aO蠟
·\±»á·j½
¡Ç_«Û®Ñaµe¸ÛåÁÀeÄçaËÍñCÕ¹ØõÓô.@yõî¥o@
þíy¨àÄy-bØWÆE;zÌTQ¤7%'ml%,[Î!ÙITîySÌKfþüeS(æv½âS) Ma
ÿªæ(´¤MN
óT«(©]ÍTÝuUiV°Äð<OµbÄê"[ÔìÛ1\íFú×Çs|ëòýWp¢½
cÄõ4Wh`Ä1?¦s¸°âh
#,YeÁõ0þ ²
+UÔQõPç*%UÕUY½4ÕVaUÖN?ÕÖ[E54Á×_µôÕ`-6Q]s3VÙea@^¿ðÙiÚkcu61l¹Í6O{íVÜU×\MµàÜu7MÜhÙ×ÕpåÒtíÍ·Qwÿ¥Wß-`}ñØ`~Qõ×à^XÞ&øÛ~áXß->â8á9ã»Ýd=nnä¯]åiM~¹äsYfem¾¹Øu¦aî¹å
¹Ö¢¯ý¹f¢Æé¦w>êe^.ç©e½kXyÞúתýÒÚkrÛÖ®ÍlÄN[Ô¶Ýí¸[]{¥²éfî¼3oRíÖ ï¿GÝðIý>\n\qN
+üÑÄ%ïñ°¯ÓÈ5_òοíÌAóÒýõÉE¿äÕ7=öf¥ÓÀ"ÝöEe]õÝm]ð×´÷Õÿ/ÞPÜÒ]yCG=ùçi?hâ©w4úÒ§ù±Ï~{лWþ{¹Â§~üÎË/þüÅÒ~}ÍÛþýË°ÏÑù¹.
+V;ý1ê~¡ß×
+äÀfYüã¸À
+
+À(ÔGÈd0
+ðC 0
+
+¢Qr¡
+R¶S§ÛYÒ+¨A5Ô&yÞ¤1äÔiLÙEÏCiÕP4tc
+íß?A*KB=±¥Úä.¥´T`AÒW¨ç õE¤
B$ÉfF²~¼l»:Rph^ûMÃ2«Eè2Ù.[Å]§I>Ñç,ÔEÂB
+>Éþ±Ô«U ÿÉ°¥p`4õ)DjÕb,E
+@'mywe®
+\ È!à`(qö¼
+`E7ßpào½Üò.º»ó²ïâ>-ëË;3òÒ¿5¯Ì¶{³ôâ?19QmæÛ¹gÎY}uþòlùL+,cÐò34)hDL7t
+çH_º"ÉéBù9o&§ iiQ:ÓxÞ´¨)MjºÿÉ:n¦fªw©êUÃÖn³5ýpÙ=º×iûuåbÝêÒÛlÇ\²<fÍÙö°9=m¯U[q×Öõªµ½5nÎÛ ÞuÀ}êWsºÜ15¸Ó}ëu_ºÝï&v¼=oI×ûÜÐÃ7²h~÷PáÆÚ¸»ìß~ûÞÑv_Àù<p|jw³ÂÃÌðlÿûÙ³ÄûMq¨Yüϯ´¹ Îk[Ûãù¹EÞ4Úä1GÍ6sº½|×8Îk]ó+Îç=º¯
þ
ÈéMwúÓ¡u©fJúÕ±uO½``ÀÖÁv±½ëÝÐö@Kÿímw»AØþv¹Ï½q§ûÝñî»çï}×ÄÞýxÁI<&ÀáxÅ/ñwüã!yÉOò·üå1yÍoó÷üçAzÑkÞ2ýéQzÕ¯õwýëa{ÙÏöµ·ýíq{Ýï÷½÷ýï|áøÅ7þñ¹P±/ùÍwþó¡}éOúÕwzD<xíoçþ÷Áov×
üåOLöÍþÁ{_ýíÇ;ûÝÿ·Ã_þõG;ýí0á_ÿý¯ÿý/
+0q°0Åý$°%-05°y=0QÿE°-M0U°Û]0±e°m0ou°U}03
°!0 ý
+Ï
+¥°
+á0%
+µP¹°ðÁP
+Å°þ@
+Ð0)XÂ
+)F
+ñ
+`" à
+(@
+NóY
+ #_à@ ÎÐj11 5m1,±8§839±4³9Ã9Ó92:]p:©Só:M0;µS¹³;=ð;ÁSÅs<-°<ÍSÑ3=p=ÙSÝó=
+0>åS
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/full_cream.svg
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/full_cream.svg (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/full_cream.svg 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,429 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+ xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="354.331"
+ height="336.614"
+ id="svg1">
+ <defs
+ id="defs3">
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop128" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop129" />
+ </linearGradient>
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient130"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ <radialGradient
+ cx="0.5"
+ cy="0.5"
+ fx="0.5"
+ fy="0.5"
+ r="0.5"
+ id="radialGradient131"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ </defs>
+ <g
+ transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+ style="font-size:12;"
+ id="g659">
+ <rect
+ width="212.257"
+ height="57.2441"
+ x="17.9576"
+ y="100.132"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect137" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ transform="matrix(0.743454,0,0,0.482981,6.46949,52.2178)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect132" />
+ </g>
+ <rect
+ width="325.86"
+ height="63.6537"
+ x="17.4083"
+ y="15.194"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect136" />
+ <rect
+ width="325.86"
+ height="63.6537"
+ x="13.6713"
+ y="12.4966"
+ style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect126" />
+ <g
+ transform="matrix(1.14345,0,0,0.729078,-1.67818,105.325)"
+ style="font-size:12;"
+ id="g164">
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="16.6979"
+ y="222.966"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect138" />
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="14.7335"
+ y="221.002"
+ transform="translate(-1.30962,-1.30992)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect133" />
+ </g>
+ <text
+ x="170.824753"
+ y="58.402939"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text183">
+ <tspan
+ x="170.824997"
+ y="58.402901"
+ id="tspan360">
+Application</tspan>
+ </text>
+ <text
+ x="178.076340"
+ y="364.281433"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text197">
+ <tspan
+ x="178.076004"
+ y="364.281006"
+ id="tspan421">
+Database</tspan>
+ </text>
+ <text
+ x="68.605331"
+ y="138.524582"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text216">
+ <tspan
+ x="68.605301"
+ y="138.524994"
+ id="tspan384">
+SessionFactory</tspan>
+ </text>
+ <rect
+ width="67.0014"
+ height="101.35"
+ x="196.927"
+ y="89.2389"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect387" />
+ <rect
+ width="67.0014"
+ height="101.35"
+ x="194.633"
+ y="86.4389"
+ style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect388" />
+ <text
+ x="249.108841"
+ y="173.885559"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text389">
+ <tspan
+ x="249.108994"
+ y="173.886002"
+ id="tspan392">
+Session</tspan>
+ </text>
+ <rect
+ width="73.0355"
+ height="101.35"
+ x="270.995"
+ y="90.0018"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect395" />
+ <rect
+ width="73.0355"
+ height="101.35"
+ x="267.869"
+ y="87.2018"
+ style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect396" />
+ <text
+ x="328.593658"
+ y="174.715622"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text397">
+ <tspan
+ x="328.593994"
+ y="174.716003"
+ id="tspan563">
+Transaction</tspan>
+ </text>
+ <g
+ transform="matrix(0.29544,0,0,0.397877,9.70533,103.96)"
+ style="font-size:12;"
+ id="g565">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect566" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect567" />
+ </g>
+ <text
+ x="25.592752"
+ y="204.497803"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text568">
+ <tspan
+ x="25.592800"
+ y="204.498001"
+ id="tspan662">
+TransactionFactory</tspan>
+ </text>
+ <g
+ transform="matrix(0.298082,0,0,0.397877,99.6898,103.96)"
+ style="font-size:12;"
+ id="g573">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect574" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect575" />
+ </g>
+ <text
+ x="134.030670"
+ y="205.532791"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text576">
+ <tspan
+ x="134.031006"
+ y="205.533005"
+ id="tspan664">
+ConnectionProvider</tspan>
+ </text>
+ <g
+ transform="matrix(1.14345,0,0,0.729078,-1.67818,38.9539)"
+ style="font-size:12;"
+ id="g587">
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="16.6979"
+ y="222.966"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect588" />
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="14.7335"
+ y="221.002"
+ transform="translate(-1.30962,-1.30992)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect589" />
+ </g>
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="25.6196"
+ y="206.028"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect594" />
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="24.4229"
+ y="204.135"
+ style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect595" />
+ <text
+ x="85.575645"
+ y="282.300354"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+ id="text596">
+ <tspan
+ x="85.575600"
+ y="282.299988"
+ id="tspan607">
+JNDI</tspan>
+ </text>
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="236.937"
+ y="206.791"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect610" />
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="235.741"
+ y="204.898"
+ style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect611" />
+ <text
+ x="342.093201"
+ y="283.226410"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+ id="text612">
+ <tspan
+ x="342.092987"
+ y="283.226013"
+ id="tspan621">
+JTA</tspan>
+ </text>
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="130.134"
+ y="206.791"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect616" />
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="128.937"
+ y="204.898"
+ style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect617" />
+ <text
+ x="212.445343"
+ y="283.226410"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+ id="text618">
+ <tspan
+ x="212.445007"
+ y="283.226013"
+ id="tspan623">
+JDBC</tspan>
+ </text>
+ <g
+ transform="matrix(0.823795,0,0,0.823795,0.120302,6.19341)"
+ style="font-size:12;"
+ id="g637">
+ <g
+ transform="matrix(0.499515,0,0,0.415467,-0.237339,5.61339)"
+ id="g167">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect134" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect135" />
+ </g>
+ <text
+ x="33.749969"
+ y="50.589706"
+ style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text188">
+ <tspan
+ x="33.750000"
+ y="50.589699"
+ id="tspan635">
+Transient Objects</tspan>
+ </text>
+ </g>
+ <g
+ transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+ style="font-size:12;"
+ id="g644">
+ <g
+ transform="matrix(0.297486,0,0,0.516482,230.251,36.9178)"
+ id="g364">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect365" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect366" />
+ </g>
+ <text
+ x="277.123230"
+ y="85.155571"
+ style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+ id="text367">
+ <tspan
+ x="277.122986"
+ y="85.155602"
+ id="tspan631">
+Persistent</tspan>
+ <tspan
+ x="277.122986"
+ y="96.155602"
+ id="tspan633">
+Objects</tspan>
+ </text>
+ </g>
+</svg>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/hibernate_logo_a.png
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/hibernate_logo_a.png (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/hibernate_logo_a.png 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,212 @@
+PNG
+
+
+IHDR
+Ü:
+uu
+õ«£(ª©®n^wo¨
+
²tYÕtajëΧC¡ôôÅú觡®®¡nu'V¤6TyÏæ/æòùØKÿÀ¡ÏþWËç³c>óųãã£cñýò¾]Û¶lýæ¦_ÿ7ݺeS¤B+¥\¾00<:EÑ/æë¿6>Þc}ò[ÍÀðð\|ßóK侦u5ÕÕ
+õ«kª«gË3¿§ÁÕüd!7:ÅKV¼gmèå$æÿµõb;+å&Ç.::
+_Sï\)NAüzö,N+ïi\²tyèeé>ú(tkimkk?¼úî;ÿàáÐYïÿwÏù7÷ÿêó¸ýû?ðÔþ8O¬H³ßc;nÛÍß|ác;.ßûÁßt÷öÅv)±¢¦ºyݺÙ'×Íëîm¨¯«°N4¾sßýþC§H¿ýO:Âòk#úÇά¹éÞæu÷67Ó×
³ç;C§o÷ÿÆ[óÄÇúnlg¥ÙÔû#§þk°ïÿKUíùÿ÷P§Ç£ëø'²ý¡SU
+·ï~6æCý§Çfn,í²ãf½^ºüavª¦ae.t"æè?ÛþÐ*êa+
+RÓ¥]Ëk¯_ÿãïýÑï®þèÃéyçòdÆoÈ
+³%ýõo;÷5ÛºeÓÖ-ÊhU&i"Ûïm )<6ÀD¶ß× @eÓ¥ZOß¹·Ît]ÿÓékÑ;#nü͸þ³í
+Ûìä½Jíø˯¼¯iݮ۷nÙdï"P:ï
+¿;4<»äó;¶77Ûµc»½ÀÛ@Ò,é|SÑh¦{óÌS¾*n,ÕZ^k÷W:ßlÞWWt5Hnhfº0t¾sÃO
+ÚlIÖÒúú®Û·nÞ´kÇöÐXÁó
+ÛVÞ³6tÕµ«a/».éÖT°;C \¾p¨ãð
+ÿÖ
L¾ðÁÊóðz»ZCG
+
+¹Ð)nl4Ó¨<º±´¾øæÑÛ5Uøhh|yÑó°HÞ@Å»Ë÷û?<rìDè @Z¼u¦ë{?ø¡¡ÕÄÊ»:Df0¯Kx<
+Ï|PĤ(ú϶_¹:
+æ+ä&.íëj~r"[Í*7
+>:
+~XvüRv|¼§÷\vl|`øbÙµe&Vh"ÛÍô44n
+nUYßÚ5éöà ÜéÆ*Ê¡7b~[u¬;÷
mwÅy"É>
+
+u«¯·Éå=½}³Ý|¿áÌ2±LýgÛW5l´D²ÍôÌLB§X¸Bnbêý÷¬
+dáÖ4n»ûÆÐ)hf¦õÖ·ÆæKë'BªjV
Prw×6n|p_èÁ¬,Û¯åàtc#/ê8ó¡2ù]¿½¶ê®©ÏåæìÓ
+
+Ù÷¿ýÒWyzM}]è87p%?rìDè@üã7?ûç}lÏîÐq>Õ\þd,]s[Ïw^ÍONáÚÌÕ²¾llVÔ{
+ÙcÇCGà¼$ù*£U.d3=¡S
+ñÊ«-O?úöØw.O*ä&.í
+æÈön&3ë6¼Ò© µtcàä®î ¾:w5`
+æ.ôm
+sôô(¡];¶'ê{NE'Ïtåò
Ð)ofº0t¾3t
+¸±
+¸iìã/ÝXÙkim"¢èÓÙÐ/3pjêýÐ)
+
+tceìPû¡#ÜÀß÷L~xgUèÌQÈM¸
+¹ ×û#ÝX¹:rìDw"ï¾9ù2§¬ÀRk^wïÞG_<ÖÓç!5¤ÈO|qÛÍa3hålð|§§ö$ÄÄX§Ü]Ûxwmc}\fÐZEò£+K¹|áPÇáÐ)>ÕÏ/䦣ß9f¦>0
+æ¸<<:
+ÝX99rìÄ»CáSܽ>?8ç;¯æ'C§
+·5Ü
+Ô¹¼<笯R¼;önìòdÆÃ2¢+¹|¡¥õõÐ)n[ïP®ðÁÊÐ)¯¿Ç ´¶nÙ:.5ÕUíÙäè+¹|._rt¹½Û
+
+ï´ceb¦Zº¬jå=k¯ÿéõýqçZ5
+¹©÷Gb>
ÑW^m aQÞ<=rÇËB§`Bn®y
+n¬±9£cJ£l;?Ù¬ûʱ(Þd
+æ³k
+ÁvVÕ¬Z^];ï/ÎÛ²ØþX$ÝX(÷¡±Y'z&?NÁ3Ó
¡ó¡S
+³SH³ºP7åõØqZ^]ѱÌà©«ùÉÐ)¨pÙLÏÌtLw Þp}âÊ{Ö.]VOëf¦ÙLOÌ°
+ïô
+*ÜÄXlg¼çÆëb¿r,÷Ó%Z._8Ôq8t¢¹ÉÿòW+B§`>»æ DBMoÔTÇýi 9´ãÉTÈMD ÍtO]umæjf ¾í¼llÖÝÒTfà,
+0:6ªH<ÝXrµ¼Ö:BI}{ì;
NÁÞ@Å°N
+¨©Ðçòµò¤¤sëXä
+jJãj~2Îrèæã«ê´ÑÙ~_Y
+"H!W¦5:Ù¬H ÄYUÕ¬Z^]{Ðh©Ñ1Ó%TKkeÍúù
ÜL´"t
+æ.ج
+ïzßt"Îh鲪µëºªÕ$n,²ãÚÚÓ846ëÒå³S5¡S0_ÿY£c
+%ÒåȨ́ý¤EÞ² ×f®ÆY-`GâÚõ-]àÕD¶ß½
+r.
+ ¢\¾ÿB×(×ÿд¼º6iõØåÉÌÐ;GC§ é¦Þ¹<í¸E[+ïY[U³ªXanÝÌt!éÿ\
+-ÎËƪjV¼gí"_$ÔÝ~SfäÐ
ÑÓw®;Ä%ÉeaúZôÃNÁ|>-
+Çî®Ûã?´Lr·òÃ8:8eÍ>frìÂ-þÚ.¢|-¯®½»¶qñ¯³
+C§cfºÐ×Õ:É2íó¸â{
úså@BèÆb50|ñÍ£ÇC§(S
ÆNÁ|FÇ
+¹g;B§
+_²tùÆ·Yq4Óí³)o¡bUͪ÷¬-Ñ76ªu»¹l¦ûÚ;D
+[=¶g÷ÖÍH¡Æ«6N1_oWkè3õþH!7Ûq%íZ^]{wmcé^ÿÓÌL²njIè
+-ÖTá£ó6þfèÌ5x¾³¡qÛ¥ËCb:y¦ëä®ë?N1Ì:rìDKkÈÖ(VÔTa
+bãûNe:Å
ÜÄ
³|"t¹Ô)õhWCã¶8ïN»n"Û¿výCñÀ,ÝXÉj#t
+ñ÷=Í¿YWdä<A
+¹¡óÞPrùÂÉ3]ÃÃ'Ït%gâ_1DQË^yõ`
+ûç¾rÀw¤ VÞ³vý&mýàùÎÆæË«kC!nq^6vwmc©5®ßä
+½ÑL÷Æü>_A
+À'
+_Ìåó=½çrùüÀÐÅ°wöÜÜc{v?÷¡ST¬gºzzÏ
Nºº½<:·m`øbËkm iîWÔT?÷oJ!-Yº¼éGL·ÜÄD¶?éihÜ:ñëó¸R^6vݪAº±¬navÍo豲ī(tc%t¨ãpròTïýÁÃ5¡S0Çh¦»qlgmýÐA
+ÝB×f®ÆyÙظ.8_»þ¡þ³íñÏe^ÌL½?²òµ1¦HÚÚáRÓ
n¬T²ãÚÚNQ.]þ0;UÓ°2:sômè:
+eÇ/<ÓuòLWw½Þ×´Î×ä¨ßÐؼ3ÈüpuzLdã[¨¸tYUë:×êÆF3ݪe tc%ÑÓw.iô«$Ó×¢þpËo
ÎÁ\ýgÛâZw
+¹ ö¡+×ÚBG¨p'z&øú»¢«¡ðOf¦6i
+æ°I
+]¢hëæME{Áá¹|~`è×ÿ;0<|%/ÖÚWyºÿ*(¢¦û÷d3Ý'3¡ÌÑ÷vëªVT°lCcU5«â¿
«±ygn,éÞøà>_;
+î
+33ż!¬¶~CcóÎÌ@¬;î>ÓàùÎÆmñû±56ǽPqVC㶠Ù~Ý@Ìî ¢dÇ/µµÏTá£_®ùz»ZCG
+u«Cgø+jª¿þü³[7o
+ÛÐtÿl¦;È
+¸è?ÛÞиÍûÁJ·¶iÔNÍZÕ°1HMÍt7Ý¿'þsRK£P4-m¡#¤ÔÏ/äf"·%ËÌtÁ&
+
+ at lÌA._8rìxè©6ré_þÊèXâë®äòoé:øÚë/|륿û:ÞÈ_
+
+ Ú¿ïñoÿé¿Qµî2ærs}o·@qLõÇvÖÒeU
+[c;îÓ¸r
+tcEÐÒúú\>t´ëxë½Ðo"ÛÍôN
+³ñÁ}¡#Ì73]°i¿ÜMdã«jªjV%ç¶Ææ0-]6ÓQnlQ;ÑÝÛ:¿6}-:s.w×Ï
ÂÁSWó¡S
+-¯®
+293]yV µPÞúúý/Y
+5üζÇU¯9þkÇù½§¾:
+,ÒúºOí7+K.ozàÑþd1¼<zçhÓý{JôúµõJôÊÄ9ÀtwmãòêÚØ»ëwùjÍtoÌïKÚ¿
+Êc§â¢ì}äám[6NÁ¯5Ôþâî]¡S0G._8ôw'"7óÀí{whø[ßùVÿ
+,ж-ÿô_ûþ·ÿL1M÷ï ²îæÎwºB©ì\ÍOÆ95Õ¸>YCcQ-Yº<ÔÇ'ö
+nOf Ö=I
+IºlìºU
+ëÊ1èÆkëæMíÙ:ÑÖÍv~þ¿
+9²ãì¹þ§>ö
+I»·)¢ÑL÷ä+ÛËI£Kk·-Yº<¶ãnÝÚõ-]Vÿ¹'3Wóñ*º±"xòÇWÔTNvÿóïï
+ù^þ?ÿÿéèظz
+qà©ý'ÏtF5ÕUÿbÿÿ:ó½rðÿùä_¼Ëê8üÜWÄ
+¹É±µõb> =ÌͧöRÿò÷ø\õÐ)ãàßþ$ûþþ7ïé;s
+uuþÿ*Ãúºººæ¦{£(ÚºeSMuµ2¬òÄ9sÝÆ÷e3ÝA¾Þ®Ö÷»6s5Îq¥P#Y·eyuíݵño(.^»þ¡ÏH ÝX15¯»÷±=»ß<z<t´ØºyÓö;¡S0ÇÀðÅ#oöÊÄÖ×wíØ^S]C$
+ÛÞkZ÷Ávfî´3u;³¹3nw¦³sÓÍv:½Ùnsí¢Ýfí"¶3øM¼öÚîØîØ2®ùãg2¸6G"À&÷½qDqôûüÎ9¯×#ÛÎ÷aÞ¿Ïç[Û÷ì *ÕÖMÖ¯NQö^zå5[P=ò¹ÜR¬ÛýÑÒèÇ_föíÙÙ÷;³§Þ,ÇÍØsÿòOþôÇ×C7ëáÛßЩù\.:×qæììW¾úõßûí
+ÔqϦéÃ!?ÖÿÓ'_îèÙ\S[«%94vgC[}®!±ãnE[ç}!óéýÇýNvgC[
+¯Ø$ýtc%ÏeGö<½7:HåûåÏ~¦å®Îè,ðâÏ9}æ?xjÿ-7øY^EZ¢qW#G¯? ÜBsS¡¹éGÿ{uâôG=rôø³³ÙnÜ
âÜî''ý<ýfuu¬òGisøè±Ég¦<=ÆRè^;òêÙbËæ_ÿoûKuR6ß8_<WªrçÎy=±ãÚ:Ëch,ÉÔÔÖ·¶
+$YþÐôÉ;îÙü¹PFjj³®±d> okmiNQáò¹ìÛ~>:çæ'ÿfßM}ʤ4éj_5:¼m×ç'¾üÄ¿ø?üÒÃ;¶ßÝÑêú=¶ïÙoE§
+Ôв:
ë¦O¼|þì?䥲ùƼ w?
r¸lìÝ!ç&¼å zèÆÄ®Ñ*ÜCß[¦þæé,ÞÔ§¼øÊkG
+ÍM£ÃÛxüwþíÿø×w>òlÏÓ{O~3:PÏøíÌè^;R[ºíN~÷ÛÑX ɦµm ¼V®ì¼7ä7Ñ»ç§/ÎOþ\§[ý½kúz£ST¬BsÓ¶[£S°ÀÌìÛ^zu8ùôTÉÃ
+ïb97óú['ÿ.:xï·¼®¼ÆÞyúÄË!çT6ÝØR1:¶t¾ðk¾¶©3õÍ_¼xiøÆ©ÓÖ@P
+ÍMãc_~"¥
+?R¡Tò¹l컹3gg¿òÕ¯ Rì¼7j)ÜG8ùÝo_¹|1:L²CcµuÙB[bÇJkP7rÏ@ÅÓ-BsÓØÈPt
+Ôß»¦«ÇL^º9vüÐkGýéû=àÁX
+^
+GÇæçNÙ¬I0å84ÉdZV\n7_<WªËù
+ÍM»>yñØ
âÜW¾úu»R)ÚúnV>ñ²q±¬^¢F¯J¢>×pgC[òç^¾4ÿÖÉ¿Kþ\
+¦[r;Æ¢#Tßxh¼.·<:L}s²ø½Ë%y©ÃG9v¼$/
+·¯»rùbÈÑ
+QõØôÉCΨHº±$¶lLËåhýºÁöOD§`ÃÿêKÇOüe=÷¼5P
+Óѳ¹¶.]ãVóÅs§¾ûíèU'ÉÆ2q K+j+i¿X
+ÔÔÖ'vÜÒ)´
+TËï¾8w>ùs*n,!ù\vt8øIÃ2µã?³¼¹5:L=ýÍ,.ÑüÎó ÜmÙø@ìÉÁïÅ{,úBÁ7NÞýäÀ
+GÇN~÷Û&cäMcµuÙB[bÇ-µÆ^9É_2ʦKÔèȶèeæ×Æ>S[¦&¿Q¼xiI8|ôçPîò¹ìc>àÄéÓ§CEZ¿n0üⱩý,M¥¯XÙÙ³9:ÅÕNKJCH34ö¾B[6ßü¹óÅsçÏþCòçTÝX¢ú{×lÝ´!:EÙèï]3¸þè,03ûö¾$pÐä3S6APîºÚW~ïçAX
+£ÃCww´ÇføÊW¿>3ûvl*IGÏæ>Âô%à½wÞ/K츶Îû;+AmÑ1Ð%mb|{ìú2ò{0:WûÚÿY29;»ïÙÉ
+¤À+Ç®\¾r4@ŨP¥Ö¯èë=|ôXt4*47mÛº5:çæ½ôjÈÑOO=ñøï
+
+'Ù[ó];
+2¦4:<¾¡>m~ëWÀÕ¦þz26À
âܾgÄf
+
+¡ã¸º±`£ÃÛZ[£S¤B>ÝöO¢S°@qn>=[Oï
+åsÙ4<õèâ1Jeeç½
îè2:V*n¨ª0¦
+;¶GGö
_ÉUö|ã//E§XàÌÙÙ}Ï~+:
+ë£S°@qn~rïßF§¸ÝONFG
+&£«}Õ}÷ÿ\t
+}{ßó¯F§¸!nP
+éÑÕ¾jld(:
Ç(ÍÙ|ct¹uìf¹ªâñKptc©ShnÚ²±òGǶl| ½çÑ)Xàðß¿zäÍè7áÐsÏçlK lÌÌÎ&h>W]A:M
+ôõF§pñ%PS[ß½v$:Åݬs3*V¸ùâ¹÷Þy+:@9Ñ¥ÑèðPønú%ÏeÙ«íÞó×ÑnÎ
âÜä3{£S
+9x_¡¹i×ç'¢SdÞ8uz÷SÑ)({}ãÑ>tfúðù³ÿ¢<(ƪÍ
+üFñâ¥ètøè1oòH¿#Gcͼ©ÊÅÄøö»;Ú£Sd&Ù5ÃJÅèèÙêÜÌë?«ÍÆIsçß=?èAnn,½ºÚW¥áéÂÒêï]Ó÷ÉOE§`§ßÜ÷Ry?X´ïÙŹùè
+éoÝCß[öüÕS3ï\NQ2/¾òÚcÇ£S
+*I>Ýõùø÷w.ãÖuôlÎæ£S|àäw¿5©b½^urÉÀÐþÞ5iؼq+
+ÍMÛ¶nNÁ3³ozéÕè%6ùôTt
+q«
+mýéÖ²<ðÇ«ZóÅsï½óVt
+´ÓBsS-\þÞ5]÷ø¹Lº9vüÐßWæúÁÉgöZ@zÌ̾}ð;1ÝX~ò\S>ݵs"
+}íÉ=.ãVô
+GGø©«\¹|ÑðP5Ó\n¬l¥á½Ó"<ö«¿«MýÇÿa©\(Îí{ö@t
+
+Úµóá4lyñ×ö=ûè«Úúîµ#Ñ)XàâÜùs3¯'ybkÛ@ÇÀ;ù|4ÝXØ1á&<ôàp]nyt
+úæäÌ?£S,¹ÃG9VªP.;nhøhù\6%[{Þëâ1ÐÖX
+Ëóß¿x,:åª>×ÐÙ³9:L&óÞ;o½{~:ÉM
+~´Àѱé/G
+~º±òShnJÉs
aýºÁ®Þè,päØñN¨}Ïðè+
+ë£S°@qn~rïßF§3ùôTt
+9 åtceltd[tkø_GksË£S°ÀÔä7ß»"Ìá£Ç^zåµè
+=£ST¯/sÓØüZ%üo@¹Ð±þÞ5[7¥ë2þÞ5÷ÝÿsÑ)X`föí}/NÌ{
+ÍMÛ¶n
+À+ÎÍïûÏ/D§H}û¿2vè¹¾øÿgJnûQ}½nÊ31¾=
+;B2Ìî§&í'gV¯lªÊŹóïNòD§ë¾¨£^¹ ~º±
+1±#òIáß|èOçöü»¯¿w9:Eê>zìÐs*C
+±ß
+K$Ë>öè#Ñ)2qlVLFòµG`ÇSÖ"¯yýâÜù¨ÓRH7V!ºÚWE-Üèï]Ó÷ÉO
ÍOrâôþ¿ïF§H©}Ï(ÎÍG§
+*ÎÍOþ;èe`òé½)¹¼L&sæìì¿þ7Ù,ËçºÚÛ3LWÇ{ûû>(Ìò¹Ü-.}{fv6É8õfqnîÄ©7gfgË«ûQïØn"T|.»ëóÿ:7~½ñØÿNtÊÌêµÃg¦'<ÛT=^g¡â-ªÏ5´¶
+D7>¬xn¬ÒìÚ9ñG_þÓdÎzèÁá;rË94õ7OÏüc1:Exñ׶;n¡@
+](ν¿:ìĦöøI<Ð×{Ý,Îͽqêt©â¥ÇýëG·E§
+ÊLwÿHm?¼JéÊå _6ÖÚ6PS[䩦¶>ðζäûTtÒU BsÓØÈÐÑß»¦«çú+HÒcǽv4:E|foqn>:
+ÝIWÁ¿Ó'^¾rùbÔé
+ Ìèð¶¹j1o:=ùÌÞèÕk³ùÆèãÜ
åªÐ68Fð¸!@:éÆ*S>_ªÇ ù³YÖTX¢gq<xäôLt²4µÿÀÌìÛÑ)
+ ^>}ìÑG¢S|ÀÅcܬÕ7-Ué/'|¢¡±Òjl [«xnæõsç£NH ÝX%Ø1Vò×üß?÷Ku¹å%YnÅÔ7'ß»¢>zìȱãÑ)
+mý¿èÆ*YïûKzEWûª°Æ']ffßÞ÷ü«Ñ)ÊÑ1
+7±£·ýæç,á«Q{¾ñÑ*Á³³ûýVt
+
+-«fÊÚ{ï¼5_<äv`.ÀßÓ'Uªn¬òåsÙ[pÇ/~fyskIòP*SOóÄÌùèåàw÷¬+
+GG('ÉúX¨¸ÔÚº"§'_Ñ º±*21¾}kèíÁ-K[ñµ?ÿ³èìÌÙÙ}ÏN@ùá¸=ÀxìÑG\<F9jhYm2é]¹|qú
¦>×pgC[Ôégtc@µÒU|.»eãÍýÂÏol»çKÅyñ
ç¼9¢ÂzîùÙ·£S
+~p>ý±_\Ò<,ÂäÞÿ¡ò](Î`©mÝ´áÇ×íb@ mÙøÀýë£S|`ÏÓ{;òPkhëÔÁ\ß¹¤*éKFì×ÙèPtcUçÆþòÐÃwä-inÖ¿zjæÑ)ªÂÁï<ï<
+ò_ú½ßþç®ZWûª±¡è8|ôØä3SÑ)(
+-«mðûÉ÷øåHRlit¨Bº±jtÝwJý½kú>ù©Äòp#N~óÐß[ñ´ÉgöZÀhmi²AHØÄøØìIÆÔþÖsºûGjë²Ñ)ÒèâÜùwÏO'ybkÛ
Iª©,#]9T!ÝXZÏý¤ÿõ7>÷`a¸{þÒ*
+FãÛ=~æl*¶PLí?ÐÕ¾ÊL-×Õвºë¾ä·¦ÖôI«E¡m êê¯Ëæg¦¯ì¼7ätäéƪZï¾ÞÃG½ÿ·
æ¦m[·ÆF"Éd¾ÿ?2»ýý¿}ûÐK¯ÆÆ!ÉL>=õÄã¿xww´÷÷)47÷÷1¤_>}ìÑG~ÿÿ8:Èv?5ÙÕÑî¿\W÷ÚéÃ/¹¦.Édf-Kjë²
+(
¶þÚºlÔ¿ùçf^÷KTÝXµÛµsâ·ÿKïÿõ~--Ëè«ÝÇnÿÁ¥ùÛê²Lfêÿ¾xñRt 2o:½ïÙoo@Òúz-M
ææ®U]ííæòÓÕ¾êáÛ÷¤cOøûyì목ïèÙüúýÑAâÍLI¸)qÓX¬BÛ@ÔÐäéÃÝs#õ¹Ó¦«v
榱¡©ýú{×tõôFÇáºü½L]öȱã^;
ì{öÀüH ÝÝÑÏåº:Ve2þ¾5ù\®«}Ut(Þväèñ®õÆ©ÓÏLME!í:îÙ43}øÝóÓÑA%<4Éd[,TÔØÒ¸PôÌôá{6E¤Û~ðDg Xqnþð¥ÿë÷ÿeM
è,|èóïþÁý«3ç£ð¡±!ïá~hföíÙºÀæÈÑã7òa'N½¹¨³×¼Gg ïÚýäsÙBKóûÝÕ¾*Ïe2J
+
+
+-«[Û¢S°@ÓûæèUg×Îè
+
+w^¹û.ó|Kktx(sß
+-«ÛºîNÁ˳·ïoNQ±&vEG
+ö÷®N
+4±c{t
+ÍMÑ)
+X½mmW>:EÙÙ
+
+
+º1J¬{íHmÍuéÒóñ¹\öèaî_7Øß»&:
+¸»p©°":E-7¢S
+¨«Éôµß¢Ä&v
+øT×÷W,NQ2c#C]í«¢S
+X½m}kt[²kçDt
+
+XÙtû`ïÇ£S\ÃèðP>ç:
+
+
+Ü5 µ¥ybÜMc
+
+
+
+~ðò9Ã
+-«[Û¢S°@Ó[ßßzÝÛµs"0
+w^¹û®«çùFò9÷Ã
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/lite.gif
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/lite.gif (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/lite.gif 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,71 @@
+GIF89aÆ'Õ$
+¨/Á*\(m~#JH¡Ã&+jÜȱ£¸L2zI²¤Éb <ɲ¥K)¬|I³¦Í1̼ɳ§Oÿu9ìüI´¨Ñ*]ÊYÐ#CJºô©¨T³j½iµÖ`ÃìJä«Ø³h'b6Û·×
+i·®ÝzrIн˷oº¼{ý
+¼
+0áÃÏ&`ãÇ;%Ülñ°ÀY1SÞlYæ©7'î,tÓ*hÍZi`¦2 `BëÛ¾^ÿ½tvmÜÀuéöÅ[©oÛÁïUüèñäÊü:îå¼n½5ö]Úrï.ú»®ðDǧl>úê×:mäòÙÓßmÿ·u$ÐLÜ 2à
+ðrÀ
+ ª#:
+§l(
+í'Á¼®q7BÙm¯Ebik
+
+¥9×ô»ã'üÙçÔ6Ö¸§·)¦L'ª«z]N1§æ&ëÂÿ¦"4
+ÏnE"ÛÓÖ´
+`p¬ÃøÖ®ù wO,ã<q¥
+KÓ*Ç (¹)s*Ñårñ±ÎÿQ^7r9:á°8¡xì×¾
+o%XJT 5BºH
+U M*oâtÈ®Y à
+¯t¯Û[¿þ»ÙÿævÅËÞöº÷½Ê%ï Þàj·³QÐJ
+»U¦ÓªÀ8
+aã8I N]Ûõqæ_#Í(5y
+ºL¶VdJÉ"£pX:Þmlcý°S'L`x^ºÙ(eòßBÖ§A×3ÓñwÀæ%
+¼gÙ°Ôûþ÷À¾ðO|Ôs È?Qì]ÐE+-_ÁB á$ÿûàÿ+9ö.rÅfx¥z&`ý¸ î Ö.'ZO
+BvIà`9Bx;8
+§r88h[¹ÕNø µ`Ð
+F&Z´áªG`OØ pSØ
F
+§h»ø
+½HÏßáØã8Rox^Å°ë°íï8ÓhóHTæfÁê ÞxÂøñÈ)bõHÀ`éx¨Ò¨|ñÊ@è`àøuÁÈ
+ê)ìYùIiBSÑ@ !NVÇÐ8öuÞÐSÿ
+Z'ý
+ÿù
+ÎÃñÒUX<ÅàiÁ dØ
+"Ú
+ZâÉ¡9b5
+:E7/c²®¾R"\â¡X7-mòò922¢x·@
+ÄSN"{lÄ¥®I2óa66FËäFËx¬½0gç|?B¤!Gò*jC¶fC¯ó¢:
+hB«b+#®»(ÍT7jq ½rO>b ì4" }B5KÒ27¶':)¢²
+oÒ,s"eò´ }7\òK.»8ÿYrV° ×7Á.ûÓ°÷úT*ºÚ¶WbutÂ$q+;ª< À°LM29¸Ð3ÖâÏZýF+L!ämU+?æ&L3'/% ¢DûIfÃ%$-ER)ë0 tVICï# òÓ3s²EhGÛ°!ëÒ1P»&T7bg(æà#ò§\²FM».RBtª Û$,²bt¤®KCHi×
+ºª+$Ó¶;h- ª¦¼À°Ë7ÃË$"+uAYª6Σ9¹nÞ¢/`pS<¹U~tB¾
+¬é"9f{³¼Ô§>myÁÐ¥<xë7«Ú3ÇÓEob²Þ»íW9#:lûdâkC&:&R,}'p.#Â(ICGZv' H*æBüË¿"á¿ÀåÒ#³¸¬
+·C'&!ÖTlYR"
+0ÄÛ$ìDÆrÄîÉÛxtRB}3e¶Ç9"ü Î:]
+ÇtC=$*¶'ÀjǸðºðÇHdÆ`Cº18åÍÒM¹Ûd°µ t1ʱü)kº^%ÁøË»ã-æ»O2©ÛÈy<w%ÍR
ó*%w£:TÄ ÿ°æ«{V]{C3¼ÄÆ,
+ )¬È##%ì9}D¸Ì$#,«êÌ4>Tnjd¸4\7¨:/ünÇB¶·'³7½X¬»Ð3
+Ð2Ì61b+>÷4±,-F â"ÃÌ%#d(«-JüI¾PÊ¿<
+Pò+
+
+O»ÐS ¢N+Û)¢{&U"ê´§"9º¤m&n)ö$24)¶m ;ÕÄC1ËÆA}:ÚÃí9ú*¶Úm¨{¹î!§ÐÀi¯ Ƚ ³¤¨öÓMÆ× 0 àñÍà|ÔªÜ&
:
+©= Káa¸,Ñní1z
+ºº
+Ì
+
¹¹BÈOÅ|QßÓpßn,¸6êFñ?þýßMßÿÉ{²{öêü~.
+
+ù]ÐiÀÝ
+Þæß^!Î#
+%¼û]+¾-þ/Á'îá.5®7î9nÌ;X)N?~AÞCÒE
+3NInKÎMÝO¢GþS^U¾Wþnä=]N_®aîcå[ÞSËâqÞm®åegþiknçY~
+Qþ{î}Îw.èo.uäs^¾y¾
Þ~NénéîýNåþ£~Þ¾nn~1þ
+îÎÿ¯^±êHá!·~¹N»¾®ÁnÃ>Å~ì¡~Ë^Í.ÏnÑ
+µÞÕN×>§nì³î
+ÝÎßþáN½ãíÇÎí>ínè¥ó~ïþ «n^ëþÙïåÞ
+çV÷ëõî?Û®ï¿þÏì ¡_ù^¤PÀg¸ñ·DòAEÀ
!¿ $¿"ïñJøò0ó2?ó4_ó6ó8ó:¿ó<ßó>ÿó@ôB?ôD_ôFôP|J¿ôLßôNÿôPõR?õT_õ¿w|É~vZ¿¿õ^?Óþõÿboñ>öf/ û~öj/T¿ön]ÿöroY?÷vöi÷zïë!±÷~?qÿ÷`e?øßÖ}ø/ã
¿øø÷ùs?ùÿöùkùößùcÿù ÿõ¢?ú[_ú¦v¨úö¶ú¬oj®ÿúû²d_ûû¸¿ùº¿ûßû¾úÀü¤?üÄúÆüªüÊßúÌßü°ÿüÐ?ûÒ?ý¶_÷Ø¥ î$¤Î¼û´¡»ØÂ0kÄáÔ£þvq0à
+Àjà
+Á 2
+E""(
+F (CùLOQSU¿Üæ\á
+8G ,±ê6/w/=!¨.mÁÃÅõZ_]sÇÓÕ×»pÛyEJGþ(|às²OÄ®XI
+@Á
+M
+ø±°X' ÝFÖ¨v-dÉ×ùqð÷0
+ÓZë"AQD +üiÄQL1²ç¸PÅÿa±?ÑÆqT
Æ8\ÌÑÇìÐCX,ÒÈ#ÛH$l2ÆtRÊ)A-*±Ì2B+IèQË/ÁK/Ã,ÓLÆ<SÍ5wJÍ7áTÇÍ8é¬S9íÌSÏ<ðÜÓÏ?ÍèÐA RI2MôMAm4OFNH%ôLJ-ÍôKL5ítJN=
+IPE-HRMMõFTUmõEV]uDXeuCZmÍD%¯ÔÕ×qýUØðÖXÌ=VÙ¶]ÖÙ ¸Ül½i©ÖÚk±ÍVÛm¹íÖÛoÁ
+WÜqÉ-×ÜsÑMWÝuÙýË^áWÞyé×Þ{ñÍWß}ùí×ßXà .ØàNXá
nØá!Xâ)®Øâ1ÎXã9îØãAYäI.ÙäQNYåYnÙåaYæi®ÙæqÎYçyîÙçZè¡.Úè£NZé¥nÚ駡Zê©©®Ú꫱ÎZë¹îÚë¯Á[ì±É.Ûl~
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/lite.svg
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/lite.svg (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/lite.svg 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,334 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+ xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="318.898"
+ height="248.031"
+ id="svg1">
+ <defs
+ id="defs3">
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop128" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop129" />
+ </linearGradient>
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient130"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ <radialGradient
+ cx="0.5"
+ cy="0.5"
+ fx="0.5"
+ fy="0.5"
+ r="0.5"
+ id="radialGradient131"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ </defs>
+ <rect
+ width="291.837"
+ height="57.0074"
+ x="17.3169"
+ y="18.646"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect136" />
+ <rect
+ width="291.837"
+ height="57.0074"
+ x="13.9703"
+ y="16.2302"
+ style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect126" />
+ <g
+ transform="matrix(0.326107,0,0,0.765831,9.59261,8.98517)"
+ style="font-size:12;"
+ id="g161">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect137" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect132" />
+ </g>
+ <g
+ transform="matrix(1.02406,0,0,0.652953,0.223384,39.9254)"
+ style="font-size:12;"
+ id="g164">
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="16.6979"
+ y="222.966"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect138" />
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="14.7335"
+ y="221.002"
+ transform="translate(-1.30962,-1.30992)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect133" />
+ </g>
+ <g
+ transform="matrix(0.449834,0,0,0.338463,-3.15909,9.73319)"
+ style="font-size:12;"
+ id="g167">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect134" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect135" />
+ </g>
+ <text
+ x="302.277679"
+ y="65.943230"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text183">
+ <tspan
+ x="302.277954"
+ y="65.943184"
+ id="tspan360">
+Application</tspan>
+ </text>
+ <text
+ x="36.235924"
+ y="63.796055"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text188">
+ <tspan
+ x="36.235950"
+ y="63.796051"
+ id="tspan427">
+Transient Objects</tspan>
+ </text>
+ <text
+ x="180.416245"
+ y="290.543701"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text197">
+ <tspan
+ x="180.415939"
+ y="290.543549"
+ id="tspan421">
+Database</tspan>
+ </text>
+ <text
+ x="25.037701"
+ y="179.154755"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text216">
+ <tspan
+ x="25.037655"
+ y="179.154648"
+ id="tspan384">
+SessionFactory</tspan>
+ </text>
+ <g
+ transform="matrix(0.252763,0,0,0.765831,109.104,8.98517)"
+ style="font-size:12;"
+ id="g386">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect387" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect388" />
+ </g>
+ <g
+ transform="matrix(0.297394,0,0,0.572692,101.502,21.6359)"
+ style="font-size:12;"
+ id="g364">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect365" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect366" />
+ </g>
+ <text
+ x="202.746506"
+ y="102.992203"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+ id="text367">
+ <tspan
+ x="202.746948"
+ y="102.992249"
+ id="tspan423">
+Persistent</tspan>
+ <tspan
+ x="202.746948"
+ y="116.992355"
+ id="tspan425">
+Objects</tspan>
+ </text>
+ <text
+ x="174.458496"
+ y="180.080795"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text389">
+ <tspan
+ x="174.458618"
+ y="180.080338"
+ id="tspan392">
+Session</tspan>
+ </text>
+ <g
+ transform="matrix(0.127369,0,0,0.765831,188.675,8.98517)"
+ style="font-size:12;"
+ id="g394">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect395" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect396" />
+ </g>
+ <text
+ x="260.413269"
+ y="179.154739"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text397">
+ <tspan
+ x="260.412964"
+ y="179.154343"
+ id="tspan400">
+JDBC</tspan>
+ </text>
+ <g
+ transform="matrix(0.127369,0,0,0.765831,229.156,8.98517)"
+ style="font-size:12;"
+ id="g405">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect406" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect407" />
+ </g>
+ <text
+ x="320.606903"
+ y="179.154739"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text408">
+ <tspan
+ x="320.606964"
+ y="179.154343"
+ id="tspan417">
+JNDI</tspan>
+ </text>
+ <g
+ transform="matrix(0.127369,0,0,0.765831,269.281,8.98517)"
+ style="font-size:12;"
+ id="g411">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect412" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect413" />
+ </g>
+ <text
+ x="377.096313"
+ y="179.154739"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text414">
+ <tspan
+ x="377.096008"
+ y="179.154999"
+ id="tspan145">
+JTA</tspan>
+ </text>
+</svg>
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/overview.gif
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/overview.gif (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/overview.gif 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,81 @@
+GIF89aT|æR
+H° Á ¥¡Ã#JH±¢Å3jÜȱ£Ç C `áÈ(Sª\ɲ¥ËKb³¦Í8sêÔ)Í@
+JôfÏQ?*]Ê´©Ó£¢:JµªUPCI½Êµ«×¯YAmýJ¶¬Y¡a?=˶Ûiÿ=}K·®Ýq;ͽ˷ïÛ¼öúL¸+àM+^¼ô°¦Ä#KÎé8äÉ3¯¬é²æÏ =r¾ä9´éÓG[*ºukÕX»
+6%Ù´sO¶= ·îßyKò
+¼x_á_N9$åÌ£uþºôë^©;²½{Uí¸{Ï<#ñäÓ5¿½ú÷<MÂO½"÷ôó·´¿þÿXÉà Hàhà)Èà0ñVPhá¢ávXÈ >("!$¸à¤¨â,
+ââÆ(Å4þg#9æ·£t¼P
+0
+5Úu6ä¨
+à28Ä%AçK6BÉ:
+P
+ØÊyÀ
+wFA½Wkq@A¯1 ¯Hé
+æBÀ
+`îÆD@Å» ¥É¸@
+¥Oã
+/4pA(
+ìCÑ
7ÛÐØÄ{ô"þm¯p\ç¢
+Áßæ`¼¶ÕïmÀ¹
+-*àÂÂ._(Vdp0 _#Ðhà is:
+Ö¾L~ªÓWð!ºÚ$ L Z½x
+l¹¶Ø¬H !(ÂÕ¾«\qÀ~ÆFÕuP¿]nh à=
+ Ò>à¬
+ ÿxÃR. ¼©1PÀ°Kf«¢T6ŵòsö»Ø$²Ë$Òé%DéKÒ;Ä4VÄ)cvG¦4IÈLÑ
+©HGJÒô¤(5©fÕÂsÕȨâÒÀ4¦éTjêâÔ"púâħ?¥H
+®pgÛÒu¸ÈM®rgfoסt}G)
+;²%æE¨étJ"øóà?Wo"¯ÉâD]颰²C|å
+´à»'ùÝu¹çêûB@P@AÞLF;®r0$ÀÿRÒ^÷¾pF!W¦´È.'ýJ+ÈÀÞd íbðDfYKL
+ìm«
EáGAðP,ç_GäV0þÞ
+¼ÅÐo$Þ±'z .³ÄR®âT
+¾¥ÑøRÐs
+)fI+ Í-ÀЬ<s)²9AåoÜÀj¿ó"R°¾æ ÈaÒ/PÐC¤«AÁP
+(Á¿-SzÊ] PKdøH×ç´õ qKì@@¦CýNmu"0ª
|Q
+h¡ÿ
+à
+héØK22£ ½ôx& ð³>Xïj×z¨%×
+@2°ÉÖÈ¥;ÅI(ï"à@R&XëaðzP\v/=ÇÇ¥NMäx'ùDF|4Ä2®Àt?¼ÉçTmÁê[:#¥]æ{ªù»Ï¯ÜÏ{+E¨¼ø¶d~y1«!·GÀ
+Âï¼³î÷uwÛ
+ß:¿ÉQ ;48Ûòyô×,Éä9¯DCp
+¸'p=6Ù µ¥6ª¦4@'%Fte#'?£±CÆ6 8bo"B74p
+&÷1:·æà0
+2#À. at 6_2÷@Í":P°>( È&ÜEZèX}Uÿðå!
+±-)Ãz Ö.î¸$Úâ
+
+âCü$8a(aùF±}q5ZJõEBÁöä6¡'ó¤5Á#áðx%LH¦
r©x8Ya/!"Aí.¡!Áêäûá}i\ÅÚgA!çD, áäaa*!Q*p0ôYöyøú¹üÙþù
+;7 @ØjH¶*d(TwÐ
+)c³äy§ ªÒÚu/»©Rd2_¥#,ÂW·ßåÿ´ÆB·àjd`t˸QÀª¤,Ôjµ*ëkª]k«UK¸®_~®D¹+EØjÃ6% .0¹Z¹fÏÓºqµWѹ\³*@&|Ó4_W>íº/¤ºª:bÐDK¶L˼þ]𹡻VÁ»ª*¦K;4ç³y>Y³9¼Ã4»m»$#+P[`лy Á3êôÂØ[Ú©¾ëEà
+»òÅc`«2)§¡¨z¨§ZlK//g?3$g@5|æBBmHR
+Ó3Þº+[ggÜ·úÑ!2*±TEMË*ù+¨½ÉÁP¼O<Åp¹¹V¨XÅ*Å\ìUüŹÅb<ÐZÆÆh|^¼Æ|{ÆnÌ¥dÇNHÄt¦m|ÇÓ1ÇzÜvÜÇw¡Æ|ÚR|ÈÈQÑüÈÉl½Ú
+!ÐMÐÝÐþ¬ÐQÀл,
+
+
+ÝPÐ }ÞÉÊmÜ/ ÞHÝ`;PÓ ×`Þç;íË×Ý߬Ý
+ÚÌÝÉßÉáÐIPÜ$0Ù½ÝÉëÐí-Ü<$pÉ$Ú:ÉÐ}Ô×ü
+50û-ã«ÝÊBp
+2¹ïañH!ª,WC´øu¡Ü_,pº TXPÑJÿ×èB!a64( Þ`ñrê·bE gôึ©YåZÖ¬$´c³¿JÊ»*\Cd«Ð³(Ñè5U¯´Õ
+<Ár3l
+,p@lð69$Ìà3@3XÀPxp\eÊɶ6¶ÁÝHÂFµYØi§â)Þ)Òb*%HPÀS%<7U$U¥§ã¥¥Ão p Èl6B¡
+
+byÀ_¡ä=4¦áäi=³e!]j£_
,Ú
+ùÜ_wùâO®Ôÿynvçc¢¸éj^:ë]£º«Ãîµë¶GÞ6´³$/üðÄoüñÈ'¯üòÌ[ö$L0/ýôÔWo=õ*ìÎpïª?ïý÷à/þøäoþùè§osØ©®þûðÇ/ÿüô×?>û»oÿþü÷ïÿÿ
+ÁWB±p
0¡·7@]ï8Ì¡wÈÃúð@$À
+Û¤'GIJõRZ¢,¥*WÉBF²ò°ü¤+cIËZr¶Ì¥.[9ÄTîò<%ª| ÌbBR{"¦1CdòÐü¥3Ó£ÌhZÿÓDO5¯ÉÍ fÓaÝç*¿*qsä|Ú9×iÉtNðt¤;áÏz6ö̧çÙ7}ú3üÈ6ÿIÐûá³ ÅäAÊÐ
+h:6ZÔ¥ÜE7J¿nb ½¨G}ÒÞ²&M)úF ª4¡,íÞKgJÁ
Òô¦Ö)qÊÓOév=
+*iljM(à¨H|j#ª
+
+@ka«Ú(ÌÈ
+0
+
+È7³
+Gq·KÔhjxÞ
@$ÿ`YÔ¸®«]rSìÛx¼1Xh¬[ÖL
+d±l
+@2`W"£´´áxÅÀÆY
²Wb¤TÆ«$¼T@)Éjg[@¹NP¢Õ¶¹îæ%ZD+p@Jð^KÊ
+ ÐØpгºËT±
+8
+ÎKlÊ3ÓÜÜ´(Ø; &6õx6ÔKg
+)èv\nüNÓEæU'0#q8 -Èl
+l@Ú%@&ôýV ¸EQàÝ
+t}êQ}Á
+hè
+À³8 øBð Ǹ¢%àHZ
+¸ØøiöS&àXx¸Øø "8$X&x(è&
\ No newline at end of file
Added: trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/overview.svg
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/overview.svg (rev 0)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/fr-FR/src/main/resources/shared/images/overview.svg 2007-05-24 19:01:51 UTC (rev 11558)
@@ -0,0 +1,250 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+ xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="248.031"
+ height="248.031"
+ id="svg1">
+ <defs
+ id="defs3">
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop128" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop129" />
+ </linearGradient>
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient130"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ <radialGradient
+ cx="0.5"
+ cy="0.5"
+ fx="0.5"
+ fy="0.5"
+ r="0.5"
+ id="radialGradient131"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ </defs>
+ <g
+ transform="matrix(0.771934,0,0,0.771934,4.36019,-3.02123)"
+ style="font-size:12;"
+ id="g158">
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="16.6979"
+ y="17.3527"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect136" />
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="14.7335"
+ y="15.3883"
+ transform="translate(-1.30962,-1.30992)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect126" />
+ </g>
+ <g
+ transform="matrix(0.771934,0,0,0.771934,4.36019,3.04452)"
+ style="font-size:12;"
+ id="g161">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect137" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect132" />
+ </g>
+ <g
+ transform="matrix(0.771934,0,0,0.771934,4.36019,8.0993)"
+ style="font-size:12;"
+ id="g164">
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="16.6979"
+ y="222.966"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect138" />
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="14.7335"
+ y="221.002"
+ transform="translate(-1.30962,-1.30992)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect133" />
+ </g>
+ <g
+ transform="matrix(0.771934,0,0,0.543505,2.59104,21.1103)"
+ style="font-size:12;"
+ id="g167">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect134" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect135" />
+ </g>
+ <text
+ x="105.392174"
+ y="56.568123"
+ transform="scale(0.771934,0.771934)"
+ style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text183">
+ <tspan
+ x="105.392273"
+ y="56.568146"
+ id="tspan186">
+Application</tspan>
+ </text>
+ <text
+ x="81.820183"
+ y="103.149330"
+ transform="scale(0.771934,0.771934)"
+ style="font-size:20;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text188">
+ <tspan
+ x="81.820213"
+ y="103.149727"
+ id="tspan206">
+Persistent Objects</tspan>
+ </text>
+ <text
+ x="111.548180"
+ y="278.927887"
+ transform="scale(0.771934,0.771934)"
+ style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text197">
+ <tspan
+ x="111.547874"
+ y="278.927551"
+ id="tspan200">
+Database</tspan>
+ </text>
+ <text
+ x="94.436180"
+ y="153.805740"
+ transform="scale(0.771934,0.771934)"
+ style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text216">
+ <tspan
+ x="94.436180"
+ y="153.805740"
+ id="tspan221">
+HIBERNATE</tspan>
+ </text>
+ <g
+ transform="matrix(0.771934,0,0,0.771934,2.59083,1.02261)"
+ style="font-size:12;"
+ id="g254">
+ <g
+ transform="translate(4.58374,2.61928)"
+ id="g176">
+ <g
+ transform="matrix(0.571429,0,0,0.67347,-10.6174,117.093)"
+ id="g170">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect171" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect172" />
+ </g>
+ <g
+ transform="matrix(0.571429,0,0,0.67347,138.682,117.093)"
+ id="g173">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect174" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect175" />
+ </g>
+ </g>
+ <text
+ x="47.259438"
+ y="182.367538"
+ style="font-weight:bold;stroke-width:1pt;font-family:Courier;"
+ id="text191">
+ <tspan
+ x="47.259399"
+ y="182.367996"
+ id="tspan212">
+hibernate.</tspan>
+ <tspan
+ x="47.259399"
+ y="194.367996"
+ id="tspan214">
+properties</tspan>
+ </text>
+ <text
+ x="198.523010"
+ y="188.260941"
+ style="font-weight:normal;stroke-width:1pt;font-family:helvetica;"
+ id="text194">
+ <tspan
+ id="tspan195">
+XML Mapping</tspan>
+ </text>
+ </g>
+</svg>
Modified: trunk/sandbox/maven-poc/Hibernate3/documentation/pom.xml
===================================================================
--- trunk/sandbox/maven-poc/Hibernate3/documentation/pom.xml 2007-05-24 18:58:25 UTC (rev 11557)
+++ trunk/sandbox/maven-poc/Hibernate3/documentation/pom.xml 2007-05-24 19:01:51 UTC (rev 11558)
@@ -1,113 +1,100 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.hibernate</groupId>
- <artifactId>hibernate-core-project</artifactId>
- <version>3.3.0.beta1</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <artifactId>hibernate-manual</artifactId>
- <packaging>pom</packaging>
- <name>Hibernate Manual</name>
- <description>The Hibernate reference manual</description>
-
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.jboss.maven.plugin</groupId>
- <artifactId>jboss-docbook-plugin</artifactId>
- <version>1.0</version>
- </dependency>
- </dependencies>
- </dependencyManagement>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.jboss.maven.plugin</groupId>
- <artifactId>jboss-docbook-plugin</artifactId>
- <executions>
- <execution>
- <goals>
- <goal>generate</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <xincludeSupported>true</xincludeSupported>
- <sourceIncludes>
- <include>master.xml</include>
- </sourceIncludes>
- <formats>
- <format>
- <formatName>pdf</formatName>
- <stylesheet>fopdf.xsl</stylesheet>
- <finalNameMap>
- <master.xml>hibernate_reference.pdf</master.xml>
- </finalNameMap>
- </format>
- <format>
- <formatName>html</formatName>
- <stylesheet>html.xsl</stylesheet>
- <relativeFormatDirectory>html_single</relativeFormatDirectory>
- <finalNameMap>
- <master.xml>index.html</master.xml>
- </finalNameMap>
- </format>
- <format>
- <formatName>html</formatName>
- <chunkedOutput>true</chunkedOutput>
- <stylesheet>html_chunk.xsl</stylesheet>
- <finalNameMap>
- <master.xml>index.html</master.xml>
- </finalNameMap>
- </format>
- </formats>
- <entities>
- <entity>
- <name>release</name>
- <value>${version}</value>
- </entity>
- </entities>
- <translations>
- <translation>
- <language>en</language>
- </translation>
- <translation>
- <language>fr</language>
- </translation>
- </translations>
- <transformerParameters>
- <property>
- <name>custom.titlepage.img</name>
- <value>${basedir}/src/main/docbook/standard/resources/shared/images/hibernate_logo_a.png</value>
- </property>
- </transformerParameters>
- </configuration>
- <dependencies>
- <dependency>
- <groupId>org.docbook</groupId>
- <artifactId>docbook-xml</artifactId>
- <version>4.4</version>
- <scope>runtime</scope>
- </dependency>
- </dependencies>
- </plugin>
- </plugins>
- </build>
-
- <reporting>
- <plugins>
- <plugin>
- <groupId>org.jboss.maven.plugin</groupId>
- <artifactId>jboss-docbook-plugin</artifactId>
- </plugin>
- </plugins>
- </reporting>
-
-</project>
\ No newline at end of file
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-core-project</artifactId>
+ <version>3.3.0.beta1</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>hibernate-manual</artifactId>
+ <packaging>pom</packaging>
+ <name>Hibernate Manual</name>
+ <description>The Hibernate reference manual</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.maven.plugins</groupId>
+ <artifactId>maven-jboss-docbook-plugin</artifactId>
+ <version>1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-docbook-xslt</artifactId>
+ <version>0.1</version>
+ </dependency>
+ </dependencies>
+
+ <modules>
+ <module>en-US</module>
+ <module>fr-FR</module>
+ </modules>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.jboss.maven.plugins</groupId>
+ <artifactId>maven-jboss-docbook-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-docbook-xslt</artifactId>
+ <version>0.1</version>
+ </dependency>
+ </dependencies>
+ <configuration>
+ <sourceDocumentName>master.xml</sourceDocumentName>
+ <formats>
+ <format>
+ <formatName>pdf</formatName>
+ <stylesheetResource>/standard/fopdf.xsl</stylesheetResource>
+ <finalName>hibernate_reference.pdf</finalName>
+ </format>
+ <format>
+ <formatName>html</formatName>
+ <stylesheetResource>/standard/html.xsl</stylesheetResource>
+ <finalName>index.html</finalName>
+ </format>
+ </formats>
+ <xincludeSupported>true</xincludeSupported>
+ <options>
+ <xincludeSupported>true</xincludeSupported>
+ <xmlTransformerType>saxon</xmlTransformerType>
+ <transformerParameters>
+ <property>
+ <name>custom.titlepage.img</name>
+ <value>${basedir}/src/main/docbook/standard/resources/shared/images/hibernate_logo_a.png</value>
+ </property>
+ </transformerParameters>
+ </options>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+<!-- report plugin is currently hosed
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.jboss.maven.plugin</groupId>
+ <artifactId>jboss-docbook-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </reporting>
+-->
+ <properties>
+ <materTranslation>en-US</materTranslation>
+ </properties>
+
+</project>
More information about the hibernate-commits
mailing list