Hibernate SVN: r15497 - in core/trunk/documentation: envers and 4 other directories.
by hibernate-commits@lists.jboss.org
Author: adamw
Date: 2008-11-04 12:06:23 -0500 (Tue, 04 Nov 2008)
New Revision: 15497
Added:
core/trunk/documentation/envers/
core/trunk/documentation/envers/src/main/docbook/en-US/Envers_Reference.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/configuration.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/example.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/exceptions.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/quickstart.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/revisionlog.xml
Removed:
core/trunk/documentation/envers/old/
core/trunk/documentation/envers/src/main/docbook/en-US/Hibernate_Reference.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/architecture.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/association_mapping.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/basic_mapping.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/batch.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/best_practices.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/collection_mapping.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/component_mapping.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/configuration.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/events.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/example_mappings.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/example_parentchild.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/example_weblog.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/filters.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/inheritance_mapping.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/performance.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/persistent_classes.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/query_criteria.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/query_hql.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/query_sql.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/session_api.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/toolset_guide.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/transactions.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/tutorial.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/xml.xml
core/trunk/documentation/envers/src/main/docbook/en-US/images/AuthorWork.png
core/trunk/documentation/envers/src/main/docbook/en-US/images/AuthorWork.zargo
core/trunk/documentation/envers/src/main/docbook/en-US/images/CustomerOrderProduct.png
core/trunk/documentation/envers/src/main/docbook/en-US/images/CustomerOrderProduct.zargo
core/trunk/documentation/envers/src/main/docbook/en-US/images/EmployerEmployee.png
core/trunk/documentation/envers/src/main/docbook/en-US/images/EmployerEmployee.zargo
core/trunk/documentation/envers/src/main/docbook/en-US/images/full_cream.png
core/trunk/documentation/envers/src/main/docbook/en-US/images/full_cream.svg
core/trunk/documentation/envers/src/main/docbook/en-US/images/hibernate_logo_a.png
core/trunk/documentation/envers/src/main/docbook/en-US/images/lite.png
core/trunk/documentation/envers/src/main/docbook/en-US/images/lite.svg
core/trunk/documentation/envers/src/main/docbook/en-US/images/overview.png
core/trunk/documentation/envers/src/main/docbook/en-US/images/overview.svg
core/trunk/documentation/envers/src/main/docbook/en-US/translators.xml
core/trunk/documentation/envers/src/main/docbook/es-ES/
core/trunk/documentation/envers/src/main/docbook/fr-FR/
core/trunk/documentation/envers/src/main/docbook/ja-JP/
core/trunk/documentation/envers/src/main/docbook/ko-KR/
core/trunk/documentation/envers/src/main/docbook/pot/
core/trunk/documentation/envers/src/main/docbook/pt-BR/
core/trunk/documentation/envers/src/main/docbook/zh-CN/
Modified:
core/trunk/documentation/envers/pom.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/preface.xml
core/trunk/documentation/pom.xml
Log:
HHH-3556: Envers documentation partially migrated
Copied: core/trunk/documentation/envers (from rev 15494, core/trunk/documentation/manual)
Modified: core/trunk/documentation/envers/pom.xml
===================================================================
--- core/trunk/documentation/manual/pom.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/pom.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -10,11 +10,11 @@
</parent>
<groupId>org.hibernate</groupId>
- <artifactId>hibernate-manual</artifactId>
+ <artifactId>hibernate-envers-manual</artifactId>
<packaging>jdocbook</packaging>
- <name>Hibernate Manual</name>
- <description>The Hibernate reference manual</description>
+ <name>Hibernate Envers Manual</name>
+ <description>The Hibernate Envers reference manual</description>
<build>
<plugins>
@@ -23,19 +23,6 @@
<artifactId>maven-jdocbook-plugin</artifactId>
<version>2.1.2</version>
<extensions>true</extensions>
- <executions>
- <execution>
- <!--
- here we are attaching the translate goal so that the translations are processed
- before compilation so that the transated XML is also transformed during
- generation
- -->
- <phase>process-resources</phase>
- <goals>
- <goal>translate</goal>
- </goals>
- </execution>
- </executions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
@@ -45,20 +32,8 @@
</dependency>
</dependencies>
<configuration>
- <sourceDocumentName>Hibernate_Reference.xml</sourceDocumentName>
+ <sourceDocumentName>Envers_Reference.xml</sourceDocumentName>
<masterTranslation>en-US</masterTranslation>
- <translations>
-<!--
- <translation>es-ES</translation>
--->
- <translation>fr-FR</translation>
- <translation>ja-JP</translation>
- <translation>ko-KR</translation>
-<!--
- <translation>pt-BR</translation>
--->
- <translation>zh-CN</translation>
- </translations>
<imageResource>
<directory>${basedir}/src/main/docbook/en-US</directory>
<excludes>
@@ -98,4 +73,4 @@
</plugins>
</build>
-</project>
\ No newline at end of file
+</project>
Added: core/trunk/documentation/envers/src/main/docbook/en-US/Envers_Reference.xml
===================================================================
--- core/trunk/documentation/envers/src/main/docbook/en-US/Envers_Reference.xml (rev 0)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/Envers_Reference.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -0,0 +1,56 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!--
+ ~ Hibernate, Relational Persistence for Idiomatic Java
+ ~
+ ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ ~ indicated by the @author tags or express copyright attribution
+ ~ statements applied by the authors. All third-party contributions are
+ ~ distributed under license by Red Hat Middleware LLC.
+ ~
+ ~ This copyrighted material is made available to anyone wishing to use, modify,
+ ~ copy, or redistribute it subject to the terms and conditions of the GNU
+ ~ Lesser General Public License, as published by the Free Software Foundation.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+ <!ENTITY versionNumber "3.3.0.GA">
+ <!ENTITY copyrightYear "2004">
+ <!ENTITY copyrightHolder "Red Hat Middleware, LLC.">
+]>
+
+<book>
+
+ <bookinfo>
+ <title>Hibernate Envers - Easy Entity Auditing</title>
+ <subtitle>Hibernate Envers Reference Documentation</subtitle>
+ <releaseinfo>&versionNumber;</releaseinfo>
+ <productnumber>&versionNumber;</productnumber>
+ <issuenum>1</issuenum>
+ <copyright>
+ <year>©rightYear;</year>
+ <holder>©rightHolder;</holder>
+ </copyright>
+ <xi:include href="legal_notice.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <!-- include translators... -->
+ </bookinfo>
+
+ <toc/>
+
+ <xi:include href="content/preface.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/quickstart.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/example.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/configuration.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/revisionlog.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/exceptions.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+</book>
+
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/Hibernate_Reference.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/Hibernate_Reference.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/Hibernate_Reference.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,95 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
- <!ENTITY versionNumber "3.3.0.GA">
- <!ENTITY copyrightYear "2004">
- <!ENTITY copyrightHolder "Red Hat Middleware, LLC.">
-]>
-
-<book>
-
- <bookinfo>
- <title>HIBERNATE - Relational Persistence for Idiomatic Java</title>
- <subtitle>Hibernate Reference Documentation</subtitle>
- <releaseinfo>&versionNumber;</releaseinfo>
- <productnumber>&versionNumber;</productnumber>
- <issuenum>1</issuenum>
- <mediaobject>
- <imageobject role="fo">
- <imagedata fileref="images/hibernate_logo_a.png" align="center" />
- </imageobject>
- <imageobject role="html">
- <imagedata fileref="images/hibernate_logo_a.png" depth="3cm" />
- </imageobject>
- </mediaobject>
- <copyright>
- <year>©rightYear;</year>
- <holder>©rightHolder;</holder>
- </copyright>
- <xi:include href="legal_notice.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
- <!-- include translators... -->
- </bookinfo>
-
- <toc/>
-
- <xi:include href="content/preface.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
-
- <xi:include href="content/tutorial.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
-
- <xi:include href="content/architecture.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
-
- <xi:include href="content/configuration.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
-
- <xi:include href="content/persistent_classes.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
-
- <xi:include href="content/basic_mapping.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
- <xi:include href="content/collection_mapping.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
- <xi:include href="content/association_mapping.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
- <xi:include href="content/component_mapping.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
- <xi:include href="content/inheritance_mapping.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
-
- <xi:include href="content/session_api.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
- <xi:include href="content/transactions.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
- <xi:include href="content/events.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
- <xi:include href="content/batch.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
-
- <xi:include href="content/query_hql.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
- <xi:include href="content/query_criteria.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
- <xi:include href="content/query_sql.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
- <xi:include href="content/filters.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
- <xi:include href="content/xml.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
-
- <xi:include href="content/performance.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
-
- <xi:include href="content/toolset_guide.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
-
- <xi:include href="content/example_parentchild.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
- <xi:include href="content/example_weblog.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
- <xi:include href="content/example_mappings.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
-
- <xi:include href="content/best_practices.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
-
-</book>
-
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/architecture.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/architecture.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/architecture.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,382 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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="../images/overview.svg" format="SVG" align="center"/>
- </imageobject>
- <imageobject role="html">
- <imagedata fileref="../images/overview.png" format="PNG" 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="../images/lite.svg" format="SVG" align="center"/>
- </imageobject>
- <imageobject role="html">
- <imagedata fileref="../images/lite.png" format="PNG" 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="../images/full_cream.svg" format="SVG" align="center"/>
- </imageobject>
- <imageobject role="html">
- <imagedata fileref="../images/full_cream.png" format="PNG" 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 corresponding 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 life cycle
- 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 programmatic transaction demarcation in plain JSE without JTA, you are advised 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 three corresponding
- short names, "jta", "thread", and "managed".
- </para>
-
- </sect1>
-
-</chapter>
-
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/association_mapping.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/association_mapping.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/association_mapping.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,650 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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>
-
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/basic_mapping.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/basic_mapping.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/basic_mapping.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,3587 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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 <link linkend="mapping-types-custom">typedef</link>.
- </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 "Initializing collections and proxies" 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 <link linkend="mapping-generated">generated properties</link>.
- </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 detect 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 <link linkend="mapping-generated">generated properties</link>.
- </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 <link linkend="mapping-generated">generated properties</link>.
- </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>
- <callout arearefs="manytoone16">
- <para>
- <literal>formula</literal> (optional): an SQL expression that defines the value for a
- <emphasis>computed</emphasis> foreign key.
- </para>
- </callout>
- </calloutlist>
- </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 <link linkend="mapping-declaration-version">versions</link>,
- <link linkend="mapping-declaration-timestamp">timestamps</link>, and
- <link linkend="mapping-declaration-property">simple properties</link> 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
- <link linkend="mapping-declaration-version">version</link> and
- <link linkend="mapping-declaration-timestamp">timestamp</link> 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>
-
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/batch.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/batch.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/batch.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,374 +0,0 @@
-<?xml version='1.0' encoding="iso-8859-1"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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 id="disablebatching" revision="1">
- Note that Hibernate disables insert batching at the JDBC level transparently if you
- use an <literal>identiy</literal> identifier generator.
- </para>
-
- <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 life cycle 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 (<link linkend="queryhql">HQL</link>).
- </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 <link linkend="queryhql-joins-forms">joins</link> (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
- <link linkend="mapping-declaration-version">version</link>
- or the <link linkend="mapping-declaration-timestamp">timestamp</link> 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>
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/best_practices.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/best_practices.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/best_practices.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,250 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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 life cycle 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>
-
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/collection_mapping.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/collection_mapping.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/collection_mapping.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,1260 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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>
-
- <tip>
- <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>
- </tip>
-
- <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 life cycle fully depends on the collection owner) or it might be a
- reference to another entity, with its own life cycle. 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>
-
- <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="ITEM_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>
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/component_mapping.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/component_mapping.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/component_mapping.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,429 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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>
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/configuration.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/configuration.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/configuration.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,1759 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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 <classname>org.hibernate.cfg.Configuration</classname> represents an entire set of mappings
- of an application's Java types to an SQL database. The <classname>org.hibernate.cfg.Configuration</classname>
- is used to build an (immutable) <interfacename>org.hibernate.SessionFactory</interfacename>. The mappings
- are compiled from various XML mapping files.
- </para>
-
- <para>
- You may obtain a <classname>org.hibernate.cfg.Configuration</classname> 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 <filename>/org/hibernate/auction/Item.hbm.xml</filename>
- and <filename>/org/hibernate/auction/Bid.hbm.xml</filename> in the classpath. This approach eliminates any
- hardcoded filenames.
- </para>
-
- <para>
- A <classname>org.hibernate.cfg.Configuration</classname> 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 <classname>java.util.Properties</classname> to
- <literal>Configuration.setProperties()</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- Place a file named <filename>hibernate.properties</filename> 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>
- <filename>hibernate.properties</filename> is the easiest approach if you want to get started quickly.
- </para>
-
- <para>
- The <classname>org.hibernate.cfg.Configuration</classname> 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 <classname>org.hibernate.cfg.Configuration</classname>,
- the application must obtain a factory for <interfacename>org.hibernate.Session</interfacename> 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
- <interfacename>org.hibernate.SessionFactory</interfacename>. 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 <interfacename>org.hibernate.SessionFactory</interfacename> create and pool
- JDBC connections for you. If you take this approach, opening a <interfacename>org.hibernate.Session</interfacename>
- 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 <classname>org.hibernate.cfg.Environment</classname>. We will
- now describe the most important settings for JDBC connection configuration.
- </para>
-
- <para>
- Hibernate will obtain (and pool) connections using <classname>java.sql.DriverManager</classname>
- 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>
- <property>hibernate.connection.driver_class</property>
- </entry>
- <entry>
- <emphasis>JDBC driver class</emphasis>
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.connection.url</property>
- </entry>
- <entry>
- <emphasis>JDBC URL</emphasis>
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.connection.username</property>
- </entry>
- <entry>
- <emphasis>database user</emphasis>
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.connection.password</property>
- </entry>
- <entry>
- <emphasis>database user password</emphasis>
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.connection.pool_size</property>
- </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
- <property>hibernate.connection.pool_size</property> 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 <filename>lib</filename>
- directory. Hibernate will use its <classname>org.hibernate.connection.C3P0ConnectionProvider</classname>
- for connection pooling if you set <property>hibernate.c3p0.*</property> properties. If you'd like to use Proxool
- refer to the packaged <filename>hibernate.properties</filename> and the Hibernate web site for more
- information.
- </para>
-
- <para>
- Here is an example <filename>hibernate.properties</filename> 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 <interfacename>javax.sql.Datasource</interfacename> 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>Property name</entry>
- <entry>Purpose</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- <property>hibernate.connection.datasource</property>
- </entry>
- <entry>
- <emphasis>datasource JNDI name</emphasis>
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.jndi.url</property>
- </entry>
- <entry>
- <emphasis>URL of the JNDI provider</emphasis> (optional)
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.jndi.class</property>
- </entry>
- <entry>
- <emphasis>class of the JNDI <literal>InitialContextFactory</literal></emphasis> (optional)
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.connection.username</property>
- </entry>
- <entry>
- <emphasis>database user</emphasis> (optional)
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.connection.password</property>
- </entry>
- <entry>
- <emphasis>database user password</emphasis> (optional)
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>
- Here's an example <filename>hibernate.properties</filename> 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.connection</literal>" to the
- connection property name. For example, you may specify a <property>charSet</property>
- connection property using <property>hibernate.connection.charSet</property>.
- </para>
-
- <para>
- You may define your own plugin strategy for obtaining JDBC connections by implementing the
- interface <interfacename>org.hibernate.connection.ConnectionProvider</interfacename>, and specifying your
- custom implementation via the <property>hibernate.connection.provider_class</property> property.
- </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 <filename>hibernate.properties</filename>. 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>
- <property>hibernate.dialect</property>
- </entry>
- <entry>
- The classname of a Hibernate <classname>org.hibernate.dialect.Dialect</classname> 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>
- <para>
- In most cases Hibernate will actually be able to chose the correct
- <classname>org.hibernate.dialect.Dialect</classname> implementation to use based on the
- <literal>JDBC metadata</literal> returned by the JDBC driver.
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.show_sql</property>
- </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>
- <property>hibernate.format_sql</property>
- </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>
- <property>hibernate.default_schema</property>
- </entry>
- <entry>
- Qualify unqualified table names with the given schema/tablespace
- in generated SQL.
- <para>
- <emphasis role="strong">eg.</emphasis>
- <literal>SCHEMA_NAME</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.default_catalog</property>
- </entry>
- <entry>
- Qualify unqualified table names with the given catalog
- in generated SQL.
- <para>
- <emphasis role="strong">eg.</emphasis>
- <literal>CATALOG_NAME</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.session_factory_name</property>
- </entry>
- <entry>
- The <interfacename>org.hibernate.SessionFactory</interfacename> 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>
- <property>hibernate.max_fetch_depth</property>
- </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>
- <property>hibernate.default_batch_fetch_size</property>
- </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>
- <property>hibernate.default_entity_mode</property>
- </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>
- <property>hibernate.order_updates</property>
- </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>
- <property>hibernate.generate_statistics</property>
- </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>
- <property>hibernate.use_identifier_rollback</property>
- </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>
- <property>hibernate.use_sql_comments</property>
- </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>
- <property>hibernate.jdbc.fetch_size</property>
- </entry>
- <entry>
- A non-zero value determines the JDBC fetch size (calls
- <literal>Statement.setFetchSize()</literal>).
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.jdbc.batch_size</property>
- </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>
- <property>hibernate.jdbc.batch_versioned_data</property>
- </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>
- <property>hibernate.jdbc.factory_class</property>
- </entry>
- <entry>
- Select a custom <interfacename>org.hibernate.jdbc.Batcher</interfacename>. Most applications
- will not need this configuration property.
- <para>
- <emphasis role="strong">eg.</emphasis>
- <literal>classname.of.BatcherFactory</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.jdbc.use_scrollable_resultset</property>
- </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>
- <property>hibernate.jdbc.use_streams_for_binary</property>
- </entry>
- <entry>
- Use streams when writing/reading <literal>binary</literal> or <literal>serializable</literal>
- types to/from JDBC. <emphasis>*system-level property*</emphasis>
- <para>
- <emphasis role="strong">eg.</emphasis>
- <literal>true</literal> | <literal>false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.jdbc.use_get_generated_keys</property>
- </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 capabilities
- using connection metadata.
- <para>
- <emphasis role="strong">eg.</emphasis>
- <literal>true|false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.connection.provider_class</property>
- </entry>
- <entry>
- The classname of a custom <interfacename>org.hibernate.connection.ConnectionProvider</interfacename>
- which provides JDBC connections to Hibernate.
- <para>
- <emphasis role="strong">eg.</emphasis>
- <literal>classname.of.ConnectionProvider</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.connection.isolation</property>
- </entry>
- <entry>
- Set the JDBC transaction isolation level. Check <interfacename>java.sql.Connection</interfacename>
- for meaningful values but note that most databases do not support all isolation levels and some
- define additional, non-standard isolations.
- <para>
- <emphasis role="strong">eg.</emphasis>
- <literal>1, 2, 4, 8</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.connection.autocommit</property>
- </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>
- <property>hibernate.connection.release_mode</property>
- </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>
- <property>hibernate.connection.</property><emphasis><propertyName></emphasis>
- </entry>
- <entry>
- Pass the JDBC property <emphasis><propertyName></emphasis>
- to <literal>DriverManager.getConnection()</literal>.
- </entry>
- </row>
- <row>
- <entry>
- <property>hibernate.jndi.</property><emphasis><propertyName></emphasis>
- </entry>
- <entry>
- Pass the property <emphasis><propertyName></emphasis> 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 utilizes <ulink url="http://www.slf4j.org/">Simple Logging Facade for Java</ulink>
- (SLF4J) in order to log various system events. SLF4J can direct your logging output to
- several logging frameworks (NOP, Simple, log4j version 1.2, JDK 1.4 logging, JCL or logback) depending on your
- chosen binding. In order to setup logging properly you will need <filename>slf4j-api.jar</filename> in
- your classpath together with the jar file for your preferred binding - <filename>slf4j-log4j12.jar</filename>
- in the case of Log4J. See the SLF4J <ulink url="http://www.slf4j.org/manual.html">documentation</ulink> for more detail.
- To use Log4j you will also need to place a <filename>log4j.properties</filename> 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 programmatically (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 managed 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 <link linkend="architecture-current-session">current sessions</link>.
- 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 life cycle 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: core/trunk/documentation/envers/src/main/docbook/en-US/content/configuration.xml
===================================================================
--- core/trunk/documentation/envers/src/main/docbook/en-US/content/configuration.xml (rev 0)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/configuration.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -0,0 +1,208 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!--
+ ~ Hibernate, Relational Persistence for Idiomatic Java
+ ~
+ ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ ~ indicated by the @author tags or express copyright attribution
+ ~ statements applied by the authors. All third-party contributions are
+ ~ distributed under license by Red Hat Middleware LLC.
+ ~
+ ~ This copyrighted material is made available to anyone wishing to use, modify,
+ ~ copy, or redistribute it subject to the terms and conditions of the GNU
+ ~ Lesser General Public License, as published by the Free Software Foundation.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<chapter id="configuration">
+
+ <title>Configuration</title>
+
+ <para>
+ To start working with Envers, all configuration that you must do is add the event
+ listeners to persistence.xml, as described in the <xref linkend="quickstart"/>.
+ </para>
+
+ <para>
+ However, as Envers generates some tables, it is possible to set the prefix and suffix
+ that is added to the entity name to create a versions table for an entity, as well
+ as set the names of the fields that are generated.
+ </para>
+
+ <para>
+ In more detail, here are the properites that you can set:
+ </para>
+
+ <table frame="topbot">
+ <title>Envers Configuration Properties</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Property name</entry>
+ <entry>Default value</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <property>org.hibernate.envers.auditTablePrefix</property>
+ </entry>
+ <entry>
+
+ </entry>
+ <entry>
+ String that will be prepended to the name of an audited entity to create
+ the name of the entity, that will hold audit information.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <property>org.hibernate.envers.auditTableSuffix</property>
+ </entry>
+ <entry>
+ _audit
+ </entry>
+ <entry>
+ String that will be appended to the name of an audited entity to create
+ the name of the entity, that will hold audit information. If you
+ audit an entity with a table name Person, in the default setting Envers
+ will generate a <literal>Person_audit</literal> table to store historical data.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <property>org.hibernate.envers.revisionFieldName</property>
+ </entry>
+ <entry>
+ REV
+ </entry>
+ <entry>
+ Name of a field in the audit entity that will hold the revision number.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <property>org.hibernate.envers.revisionTypeFieldName</property>
+ </entry>
+ <entry>
+ REVTYPE
+ </entry>
+ <entry>
+ Name of a field in the aduit entity that will hold the type of the
+ revision (currently, this can be: add, mod, del).
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <property>org.hibernate.envers.revisionOnCollectionChange</property>
+ </entry>
+ <entry>
+ true
+ </entry>
+ <entry>
+ Should a revision be generated when a not-owned relation field changes
+ (this can be either a collection in a one-to-many relation, or the field
+ using "mappedBy" attribute in a one-to-one relation).
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <property>org.hibernate.envers.warnOnUnsupportedTypes</property>
+ </entry>
+ <entry>
+ false
+ </entry>
+ <entry>
+ TODO: remove
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <property>org.hibernate.envers.doNotAuditOptimisticLockingField</property>
+ </entry>
+ <entry>
+ true
+ </entry>
+ <entry>
+ When true, properties to be used for optimistic locking, annotated with
+ <literal>@Version</literal>, will be automatically not audited
+ (their history won't be stored; it normally doesn't make sense to store it).
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ To change the name of the revision table and its fields (the table, in which the
+ numbers of revisions and their timestamps are stored), you can use the
+ <literal>@RevisionEntity</literal> annotation.
+ For more information, see <xref linkend="revisionlog"/>.
+ </para>
+
+ <para>
+ To set the value of any of the properties described above, simply add an entry to
+ your <literal>persistence.xml</literal>. For example:
+ </para>
+
+ <programlisting><![CDATA[<persistence-unit ...>
+<provider>org.hibernate.ejb.HibernatePersistence</provider>
+<class>...</class>
+<properties>
+ <property name="hibernate.dialect" ... />
+ <!-- other hibernate properties -->
+
+ <property name="hibernate.ejb.event.post-insert"
+ value="org.hibernate.envers.event.VersionsEventListener" />
+ <property name="hibernate.ejb.event.post-update"
+ value="org.hibernate.envers.event.VersionsEventListener" />
+ <property name="hibernate.ejb.event.post-delete"
+ value="org.hibernate.envers.event.VersionsEventListener" />
+ <property name="hibernate.ejb.event.pre-collection-update"
+ value="org.hibernate.envers.event.VersionsEventListener" />
+ <property name="hibernate.ejb.event.pre-collection-remove"
+ value="org.hibernate.envers.event.VersionsEventListener" />
+ <property name="hibernate.ejb.event.post-collection-recreate"
+ value="org.hibernate.envers.event.VersionsEventListener" />
+
+ <property name="org.hibernate.envers.versionsTableSuffix" value="_V" />
+ <property name="org.hibernate.envers.revisionFieldName" value="ver_rev" />
+ <!-- other envers properties -->
+</properties>
+</persistence-unit>]]></programlisting>
+
+ <para>
+ You can also set the name of the versions table on a per-entity basis, using the
+ <literal>@AuditTable</literal> annotation (see also in the javadoc). It may be tedious to add this
+ annotation to every audited entity, so if possible, it's better to use a prefix/suffix.
+ </para>
+
+ <para>
+ If you have a mapping with secondary tables, version tables for them will be generated in
+ the same way (by adding the prefix and suffix). If you wish to overwrite this behaviour,
+ you can use the <literal>@SecondaryAuditTable</literal> and
+ <literal>@SecondaryAuditTables</literal> annotations.
+ </para>
+
+ <para>
+ If you want to audit a relation mapped with <literal>@OneToMany+@JoinColumn</literal>,
+ please see <xref linkend="exceptions"/> for a description of the additional
+ <literal>@AuditJoinTable</literal> annotation that you'll probably want to use.
+ </para>
+</chapter>
+
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/events.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/events.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/events.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,292 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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: core/trunk/documentation/envers/src/main/docbook/en-US/content/example.xml
===================================================================
--- core/trunk/documentation/envers/src/main/docbook/en-US/content/example.xml (rev 0)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/example.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -0,0 +1,87 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!--
+ ~ Hibernate, Relational Persistence for Idiomatic Java
+ ~
+ ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ ~ indicated by the @author tags or express copyright attribution
+ ~ statements applied by the authors. All third-party contributions are
+ ~ distributed under license by Red Hat Middleware LLC.
+ ~
+ ~ This copyrighted material is made available to anyone wishing to use, modify,
+ ~ copy, or redistribute it subject to the terms and conditions of the GNU
+ ~ Lesser General Public License, as published by the Free Software Foundation.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<chapter id="example">
+
+ <title>Short example</title>
+
+ <para>
+ For example, using the entities defined above, the following code will generate
+ revision number 1, which will contain two new <literal>Person</literal> and
+ two new <literal>Address</literal> entities:
+ </para>
+
+ <programlisting><![CDATA[entityManager.getTransaction().begin();
+
+Address address1 = new Address("Privet Drive", 4);
+Person person1 = new Person("Harry", "Potter", address1);
+
+Address address2 = new Address("Grimmauld Place", 12);
+Person person2 = new Person("Hermione", "Granger", address2);
+
+entityManager.persist(address1);
+entityManager.persist(address2);
+entityManager.persist(person1);
+entityManager.persist(person2);
+
+entityManager.getTransaction().commit();]]></programlisting>
+
+ <para>
+ Now we change some entities. This will generate revision number 2, which will contain
+ modifications of one person entity and two address entities (as the collection of
+ persons living at <literal>address2</literal> and <literal>address1</literal> changes):
+ </para>
+
+ <programlisting><![CDATA[entityManager.getTransaction().begin();
+
+Address address1 = entityManager.find(Address.class, address1.getId());
+Person person2 = entityManager.find(Person.class, person2.getId());
+
+// Changing the address's house number
+address1.setHouseNumber(5)
+
+// And moving Hermione to Harry
+person2.setAddress(address1);
+
+entityManager.getTransaction().commit();]]></programlisting>
+
+ <para>
+ We can retrieve the old versions (the audit) easily:
+ </para>
+
+ <programlisting><![CDATA[AuditReader reader = AuditReaderFactory.get(entityManager);
+
+Person person2_rev1 = reader.find(Person.class, person2.getId(), 1);
+assert person2_rev1.getAddress().equals(new Address("Grimmauld Place", 12));
+
+Address address1_rev1 = reader.find(Address.class, address1.getId(), 1);
+assert address1_rev1.getPersons().getSize() == 1;
+
+// and so on]]></programlisting>
+
+</chapter>
+
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/example_mappings.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/example_mappings.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/example_mappings.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,685 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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="html">
- <imagedata fileref="../images/EmployerEmployee.png" format="PNG" align="center" />
- </imageobject>
- <imageobject role="fo">
- <imagedata fileref="../images/EmployerEmployee.png" format="PNG" align="center" width="17cm" />
- </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="html">
- <imagedata fileref="../images/AuthorWork.png" format="PNG" align="center" />
- </imageobject>
- <imageobject role="fo">
- <imagedata fileref="../images/AuthorWork.png" format="PNG" align="center" width="17cm" />
- </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="html">
- <imagedata fileref="../images/CustomerOrderProduct.png" format="PNG" align="center" />
- </imageobject>
- <imageobject role="fo">
- <imagedata fileref="../images/CustomerOrderProduct.png" format="PNG" align="center" width="17cm" />
- </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>
-
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/example_parentchild.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/example_parentchild.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/example_parentchild.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,388 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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 life cycle 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 life cycle</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>
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/example_weblog.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/example_weblog.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/example_weblog.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,457 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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: core/trunk/documentation/envers/src/main/docbook/en-US/content/exceptions.xml
===================================================================
--- core/trunk/documentation/envers/src/main/docbook/en-US/content/exceptions.xml (rev 0)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/exceptions.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -0,0 +1,106 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!--
+ ~ Hibernate, Relational Persistence for Idiomatic Java
+ ~
+ ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ ~ indicated by the @author tags or express copyright attribution
+ ~ statements applied by the authors. All third-party contributions are
+ ~ distributed under license by Red Hat Middleware LLC.
+ ~
+ ~ This copyrighted material is made available to anyone wishing to use, modify,
+ ~ copy, or redistribute it subject to the terms and conditions of the GNU
+ ~ Lesser General Public License, as published by the Free Software Foundation.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<chapter id="exceptions">
+ <title>Mapping exceptions</title>
+
+ <sect1 id="exceptions-wontbesupported">
+
+ <title>What isn't and will not be supported</title>
+
+ <para>
+ Bags (the corresponding Java type is List), as they can contain non-unique elements.
+ The reason is that persisting, for example a bag of String-s, violates a principle
+ of relational databases: that each table is a set of tuples. In case of bags,
+ however (which require a join table), if there is a duplicate element, the two
+ tuples corresponding to the elements will be the same. Hibernate allows this,
+ however Envers (or more precisely: the database connector) will throw an exception
+ when trying to persist two identical elements, because of a unique constraint violation.
+ </para>
+
+ <para>
+ There are at least two ways out if you need bag semantics:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>
+ use an indexed collection, with the <literal>@IndexColumn</literal> annotation, or
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ provide a unique id for your elements with the <literal>@CollectionId</literal> annotation.
+ </para>
+ </listitem>
+ </orderedlist>
+
+ </sect1>
+
+ <sect1 id="exceptions-willbesupported" revision="2">
+
+ <title>What isn't and <emphasis>will</emphasis> be supported</title>
+
+ <orderedlist>
+ <listitem>
+ <para>
+ collections of components
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ relations in components
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ joined and table-per-class inheritance
+ </para>
+ </listitem>
+ </orderedlist>
+
+ </sect1>
+
+ <sect1 id="exceptions-onetomanyjoincolumn" revision="3">
+
+ <title><literal>@OneToMany</literal>+<literal>@JoinColumn</literal></title>
+
+ <para>
+ When a collection is mapped using these two annotations, Hibernate doesn't
+ generate a join table. Envers, however, has to do this, so that when you read the
+ revisions in which the related entity has changed, you don't get false results.
+ </para>
+ <para>
+ To be able to name the additional join table, there is a special annotation:
+ <literal>@AuditJoinTable</literal>, which has similar semantics to JPA's
+ <literal>@JoinTable</literal>.
+ </para>
+
+ </sect1>
+
+</chapter>
+
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/filters.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/filters.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/filters.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,173 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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.enableFilter()</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.enableFilter("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>
-
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/inheritance_mapping.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/inheritance_mapping.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/inheritance_mapping.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,518 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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>
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/performance.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/performance.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/performance.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,1439 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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.createQuery("from CatImpl as cat where cat.name='fritz'").iterate();
-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>Session</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 3, 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 preferred 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 Cache 1.x</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>
- <row>
- <entry>JBoss Cache 2</entry>
- <entry><literal>org.hibernate.cache.jbc2.JBossCacheRegionFactory</literal></entry>
- <entry>clustered (ip multicast), transactional</entry>
- <entry>yes (replication or invalidation)</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 (preferably?), 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>
-
- <sect2 id="performance-cache-compat-matrix">
- <title>Cache-provider/concurrency-strategy compatibility</title>
-
- <important>
- <para>
- None of the cache providers support all of the cache concurrency strategies.
- </para>
- </important>
-
- <para>
- 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 Cache 1.x</entry>
- <entry>yes</entry>
- <entry></entry>
- <entry></entry>
- <entry>yes</entry>
- </row>
- <row>
- <entry>JBoss Cache 2</entry>
- <entry>yes</entry>
- <entry></entry>
- <entry></entry>
- <entry>yes</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- </sect2>
-
- </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 efficiently. 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 programmatically 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 example, 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>
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/persistent_classes.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/persistent_classes.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/persistent_classes.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,561 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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 proxying 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>
-
- <sect1 id="persistent-classes-extensions">
- <title>Extentsions</title>
- <para>
- TODO: Document user-extension framework in the property and proxy packages
- </para>
- </sect1>
-
-</chapter>
-
Modified: core/trunk/documentation/envers/src/main/docbook/en-US/content/preface.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/preface.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/preface.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -29,104 +29,56 @@
<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.
+ The Envers project aims to enable easy auditing of persistent classes. All that you
+ have to do is annotate your persistent class or some of its properties, that you
+ want to audit, with <literal>@Audited</literal>. For each audited entity, a table
+ will be created, which will hold the history of changes made to the entity. You
+ can then retrieve and query historical data without much effort.
</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.
+ Similarly to Subversion, the library has a concept of revisions. Basically, one
+ transaction is one revision (unless the transaction didn't modify any audited entities).
+ As the revisions are global, having a revision number, you can query for various
+ entities at that revision, retrieving a (partial) view of the database at that
+ revision. You can find a revision number having a date, and the other way round,
+ you can get the date at which a revision was commited.
</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.
+ The library works with Hibernate and Hibernate Annotations or Entity Manager.
+ For the auditing to work properly, the entities must have immutable unique
+ identifiers (primary keys). You can use Envers wherever Hibernate works:
+ standalone, inside JBoss AS, with JBoss Seam or Spring.
</para>
<para>
- If you are new to Hibernate and Object/Relational Mapping or even Java,
- please follow these steps:
+ Some of the features:
</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.
+ versioning of all mappings defined by the JPA specification, except joined and
+ table-per-class inheritance
</para>
</listitem>
<listitem>
<para>
- Read <xref linkend="architecture"/> to understand the environments where
- Hibernate can be used.
+ versioning of some Hibernate mappings, which extend JPA, like custom types and
+ collections/maps of "simple" types (Strings, Integers, etc.)
+ (see <xref linkend="exceptions"/> for one exception)
</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>.
+ logging data for each revision using a "revision entity"
</para>
</listitem>
<listitem>
<para>
- Use this reference documentation as your primary source of information.
- Consider reading <emphasis>Java Persistence with Hibernate</emphasis>
- (http://www.manning.com/bauer2) 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 Java Persistence with Hibernate.
+ querying historical data
</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>
-
+ </orderedlist>
</preface>
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/query_criteria.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/query_criteria.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/query_criteria.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,463 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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>
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/query_hql.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/query_hql.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/query_hql.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,1261 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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-components"/> 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.createQuery("select count(*) from ....").iterate().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.createQuery("select count(*) from ....").iterate().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 Person p]]></programlisting>
- <programlisting><![CDATA[select p.name.first 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 Person p where p.name = :name]]></programlisting>
- <programlisting><![CDATA[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 Person p order by p.name]]></programlisting>
- <programlisting><![CDATA[from Person p order by p.name.first]]></programlisting>
-
- <para>
- Another common use of components is in <link linkend="queryhql-tuple">row value constructors</link>.
- </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 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>
-
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/query_sql.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/query_sql.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/query_sql.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,784 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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>ResultSetMetadata</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>
-
- <para>
- 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.
- </para>
- </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 specified 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 explicitly, 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},
- address.STREET AS {address.street},
- address.CITY AS {address.city},
- address.STATE AS {address.state},
- address.ZIP AS {address.zip}
- FROM PERSON person
- JOIN ADDRESS address
- 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 across
- 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},
- address.STREET AS {address.street},
- address.CITY AS {address.city},
- address.STATE AS {address.state},
- address.ZIP AS {address.zip}
- FROM PERSON person
- JOIN ADDRESS address
- 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: core/trunk/documentation/envers/src/main/docbook/en-US/content/quickstart.xml
===================================================================
--- core/trunk/documentation/envers/src/main/docbook/en-US/content/quickstart.xml (rev 0)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/quickstart.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -0,0 +1,148 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!--
+ ~ Hibernate, Relational Persistence for Idiomatic Java
+ ~
+ ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ ~ indicated by the @author tags or express copyright attribution
+ ~ statements applied by the authors. All third-party contributions are
+ ~ distributed under license by Red Hat Middleware LLC.
+ ~
+ ~ This copyrighted material is made available to anyone wishing to use, modify,
+ ~ copy, or redistribute it subject to the terms and conditions of the GNU
+ ~ Lesser General Public License, as published by the Free Software Foundation.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<chapter id="quickstart">
+ <title>Quickstart</title>
+
+ <para>
+ When configuring your persistence unit (the persistence.xml file), add the following event
+ listeners: (this will allow Envers to check if any audited entities were modified)
+ </para>
+
+ <programlisting><![CDATA[<persistence-unit ...>
+<provider>org.hibernate.ejb.HibernatePersistence</provider>
+<class>...</class>
+<properties>
+ <property name="hibernate.dialect" ... />
+ <!-- other hibernate properties -->
+
+ <property name="hibernate.ejb.event.post-insert"
+ value="org.hibernate.envers.event.VersionsEventListener" />
+ <property name="hibernate.ejb.event.post-update"
+ value="org.hibernate.envers.event.VersionsEventListener" />
+ <property name="hibernate.ejb.event.post-delete"
+ value="org.hibernate.envers.event.VersionsEventListener" />
+ <property name="hibernate.ejb.event.pre-collection-update"
+ value="org.hibernate.envers.event.VersionsEventListener" />
+ <property name="hibernate.ejb.event.pre-collection-remove"
+ value="org.hibernate.envers.event.VersionsEventListener" />
+ <property name="hibernate.ejb.event.post-collection-recreate"
+ value="org.hibernate.envers.event.VersionsEventListener" />
+</properties>
+</persistence-unit>]]></programlisting>
+
+ <para>
+ Then, annotate your persistent class with <literal>@Audited</literal> - this will make all
+ properties versioned. For example:
+ </para>
+
+ <programlisting><![CDATA[import org.hibernate.envers.Audited;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Column;
+
+@Entity
+@Audited // that's the important part :)
+public class Person {
+ @Id
+ @GeneratedValue
+ private int id;
+
+ private String name;
+
+ private String surname;
+
+ @ManyToOne
+ private Address address;
+
+ // add getters, setters, constructors, equals and hashCode here
+}]]></programlisting>
+
+ <para>
+ And the referenced entity:
+ </para>
+
+ <programlisting><![CDATA[@Entity
+@Audited
+public class Address {
+ @Id
+ @GeneratedValue
+ private int id;
+
+ private String streetName;
+
+ private Integer houseNumber;
+
+ private Integer flatNumber;
+
+ @OneToMany(mappedBy = "address")
+ private Set<Person> persons;
+
+ // add getters, setters, constructors, equals and hashCode here
+}
+]]></programlisting>
+
+ <para>
+ And that's it! You create, modify and delete the entites as always. If you look
+ at the generated schema, you will notice that it is unchanged by adding auditing
+ for the Address and Person entities. Also, the data they hold is the same. There are,
+ however, two new tables - <literal>Address_audit</literal> and <literal>Person_audit</literal>,
+ which store the historical data, whenever you commit a transaction.
+ </para>
+
+ <para>
+ Instead of annotating the whole class and auditing all properties, you can annotate
+ only some persistent properties with <literal>@Audited</literal>. This will cause only
+ these properties to be audited.
+ </para>
+
+ <para>
+ You can access the audit of an entity using the <literal>AuditReader</literal> interface, which you
+ can obtain when having an open EntityManager. See also the javadocs.
+ </para>
+
+ <programlisting><![CDATA[AuditReader reader = AuditReaderFactory.get(entityManager);
+Person oldPerson = reader.find(Person.class, personId, revision)
+]]></programlisting>
+
+ <para>
+ The <literal>T find(Class<T> cls, Object primaryKey, Number revision)</literal>
+ method returns an entity with the given primary key, with the data it contained at
+ the given revision. If the entity didn't exist at this revision, <literal>null</literal>
+ is returned. Only the audited properties will be set on the returned entity.
+ The rest will be <literal>null</literal>.
+ </para>
+
+ <para>
+ You can also get a list of revisions at which an entity was modified using the
+ <literal>getRevisions</literal> method, as well as retrieve the date,
+ at which a revision was created using the <literal>getRevisionDate</literal> method.
+ </para>
+</chapter>
+
Added: core/trunk/documentation/envers/src/main/docbook/en-US/content/revisionlog.xml
===================================================================
--- core/trunk/documentation/envers/src/main/docbook/en-US/content/revisionlog.xml (rev 0)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/revisionlog.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -0,0 +1,155 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!--
+ ~ Hibernate, Relational Persistence for Idiomatic Java
+ ~
+ ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ ~ indicated by the @author tags or express copyright attribution
+ ~ statements applied by the authors. All third-party contributions are
+ ~ distributed under license by Red Hat Middleware LLC.
+ ~
+ ~ This copyrighted material is made available to anyone wishing to use, modify,
+ ~ copy, or redistribute it subject to the terms and conditions of the GNU
+ ~ Lesser General Public License, as published by the Free Software Foundation.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ ~ for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<chapter id="revisionlog">
+
+ <title>Logging data for revisions</title>
+
+ <para>
+ Envers provides an easy way to log additional data for each revision. You simply need
+ to annotate one entity with <literal>@RevisionEntity</literal>, and a new instance of
+ this entity will be persisted when a new revision is created (that is, whenever an
+ audited entity is modified). As revisions are global, you can have at most one revisions entity.
+ </para>
+
+ <para>
+ This entity must have at least two properties:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>
+ an integer- or long-valued property, annotated with <literal>@RevisionNumber</literal>. Most
+ often, this will be an auto-generated primary key.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ a long-valued property, annotated with <literal>@RevisionTimestamp</literal>. Value of
+ this property will be automatically set by Envers.
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ You can either add these properties to your entity, or extend
+ <literal>org.hibernate.envers.DefaultRevisionEntity</literal>, which already has those two properties.
+ </para>
+
+ <para>
+ To fill the entity with additional data, you'll need to implement the
+ <literal>org.jboss.envers.RevisionListener</literal> interface. Its newRevision method will
+ be called when a new revision is created, before persisting the revision entity.
+ The implementation should be stateless and thread-safe. The listener then has to be
+ attached to the revisions entity by specifying it as a parameter to the
+ <literal>@RevisionEntity</literal> annotation.
+ </para>
+
+ <para>
+ A simplest example of a revisions entity, which with each revision associates the
+ username of the user making the change is:
+ </para>
+
+ <programlisting><![CDATA[package org.jboss.envers.example;
+
+import org.hibernate.envers.RevisionEntity;
+import org.hibernate.envers.DefaultRevisionEntity;
+
+import javax.persistence.Entity;
+
+@Entity
+(a)RevisionEntity(ExampleListener.class)
+public class ExampleRevEntity extends DefaultRevisionEntity {
+ private String username;
+
+ public String getUsername() { return username; }
+ public void setUsername(String username) { this.username = username; }
+}]]></programlisting>
+
+ <para>
+ Or, if you don't want to extend any class:
+ </para>
+
+ <programlisting><![CDATA[package org.hibernate.envers.example;
+
+import org.hibernate.envers.RevisionNumber;
+import org.hibernate.envers.RevisionTimestamp;
+import org.hibernate.envers.RevisionEntity;
+
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Entity;
+
+@Entity
+(a)RevisionEntity(ExampleListener.class)
+public class ExampleRevEntity {
+ @Id
+ @GeneratedValue
+ @RevisionNumber
+ private int id;
+
+ @RevisionTimestamp
+ private long timestamp;
+
+ private String username;
+
+ // Getters, setters, equals, hashCode ...
+}]]></programlisting>
+
+ <para>
+ An example listener, which, if used in a JBoss Seam application, stores the
+ currently logged in user username:
+ </para>
+
+ <programlisting><![CDATA[package org.hibernate.envers.example;
+
+import org.hibernate.envers.RevisionListener;
+import org.jboss.seam.security.Identity;
+import org.jboss.seam.Component;
+
+public class ExampleListener implements RevisionListener {
+ public void newRevision(Object revisionEntity) {
+ ExampleRevEntity exampleRevEntity = (ExampleRevEntity) revisionEntity;
+ Identity identity = (Identity) Component.getInstance("org.jboss.seam.security.identity");
+
+ exampleRevEntity.setUsername(identity.getUsername());
+ }
+}]]></programlisting>
+
+ <para>
+ Having an "empty" revision entity - that is, with no additional properties except the
+ two mandatory ones - is also an easy way to change the names of the table and of the
+ properties in the revisions table automatically generated by Envers.
+ </para>
+
+ <para>
+ In case there is no entity annotated with <literal>@RevisionEntity</literal>, a default
+ table will be generated, with the name <literal>REVINFO</literal>.
+ </para>
+
+</chapter>
+
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/session_api.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/session_api.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/session_api.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,1287 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>persist()</literal> makes a transient instance persistent.
- However, it doesn't guarantee that the identifier value will be assigned to
- the persistent instance immediately, the assignment might happen at flush time.
- <literal>persist()</literal> also guarantees that it will not execute an
- <literal>INSERT</literal> statement if it is called outside of transaction
- boundaries. This is useful in long-running conversations with an extended
- Session/persistence context.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>save()</literal> does guarantee to return an identifier. If an INSERT
- has to be executed to get the identifier ( e.g. "identity" generator, not
- "sequence"), this INSERT happens immediately, no matter if you are inside or
- outside of a transaction. This is problematic in a long-running conversation
- with an extended Session/persistence context.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- 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 = (Cat) tuple[0];
- Cat mother = (Cat) 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( Restrictions.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")
- .addEntity("cat", Cat.class)
-.list();]]></programlisting>
-
- <programlisting><![CDATA[List cats = session.createSQLQuery(
- "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
- "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
- "FROM CAT {cat} WHERE ROWNUM<10")
- .addEntity("cat", Cat.class)
-.list()]]></programlisting>
-
- <para>
- 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 life cycle 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 life cycle, 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 parent
- object, make it a <emphasis>life cycle 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>
-
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/toolset_guide.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/toolset_guide.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/toolset_guide.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,631 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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>
- </schemavalidator>
-</target>]]></programlisting>
-
- </sect2>
-
- </sect1>
-
-</chapter>
-
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/transactions.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/transactions.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/transactions.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,1136 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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 sent 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 sent 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 conversation.
- 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 occurred 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 explicitly.
- </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>
- Database (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 demarcation. 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 <link linkend="objectstate-flushing">FlushMode</link> 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 programmatically,
- 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
- compatibility), 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> explicitly 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 exception
- into a more meaningful 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 functionality 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 objects 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.MANUAL</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 occurred.
- </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 conceptually 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 unnecessary 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 worrying about locking strategies. It's 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 obtains 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>
-
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/tutorial.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/tutorial.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/tutorial.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,1617 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
- <!ENTITY mdash "-">
-]>
-
- <!-- todo : need searate sections, one for each tutorial -->
-
-<chapter id="tutorial">
- <title>Introduction to Hibernate</title>
-
- <sect1 id="tutorial-intro">
- <title>Preface</title>
-
- <para>
- This chapter is an introduction to Hibernate by way of a tutorial,
- intended for new users of Hibernate. We start with a simple
- application using an in-memory database. We build the
- application in small, easy to understand steps. The tutorial is
- based on another, earlier one developed by Michael Gloegl. All
- code is contained in the <filename>tutorials/web</filename> directory
- of the project source.
- </para>
-
- </sect1>
-
- <important>
- <para>
- This tutorial expects the user have knowledge of both Java and
- SQL. If you are new or uncomfortable with either, it is advised
- that you start with a good introduction to that technology prior
- to attempting to learn Hibernate. It will save time and effort
- in the long run.
- </para>
- </important>
-
- <note>
- <para>
- There is another tutorial/example application in the
- <filename>/tutorials/eg</filename> directory of the project source.
- That example is console based and as such would not have the
- dependency on a servlet container to execute. The basic setup is
- the same as the instructions below.
- </para>
- </note>
-
- <sect1 id="tutorial-firstapp">
- <title>Part 1 - The first Hibernate Application</title>
-
- <para>
- Let's assume we need a small database application that can store
- events we want to attend, and information about the host(s) of
- these events. We will use an in-memory, Java database named HSQLDB
- to avoid describing installation/setup of any particular database
- servers. Feel free to tweak this tutorial to use whatever database
- you feel comfortable using.
- </para>
-
- <para>
- The first thing we need to do is set up our development environment,
- and specifically to setup all the required dependencies to Hibernate
- as well as other libraries. Hibernate is built using Maven which
- amongst other features provides <literal>dependecy management</literal>;
- moreover it provides <emphasis>transitive</emphasis>
- <literal>dependecy management</literal> which simply means that to use
- Hibernate we can simply define our dependency on Hibernate, Hibernate
- itself defines the dependencies it needs which then become transitive
- dependencies of our project.
- </para>
-
- <programlisting><![CDATA[.
-<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">
-
- ...
-
- <dependencies>
- <dependency>
- <groupId>${groupId}</groupId>
- <artifactId>hibernate-core</artifactId>
- </dependency>
-
- <!-- Because this is a web app, we also have a dependency on the servlet api. -->
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- </dependency>
- </dependencies>
-
-</project>]]></programlisting>
-
- <note>
- <para>
- Essentially we are describing here the
- <filename>/tutorials/web/pom.xml</filename> file. See the
- <ulink url="http://maven.org">Maven</ulink> site for more information.
- </para>
- </note>
-
- <tip>
- <para>
- While not strictly necessary, most IDEs have integration with Maven
- to read these POM files and automatically set up a project for you
- which can save lots of time and effort.
- </para>
- </tip>
-
- <para>
- Next we create a class that represents the event we want to store in database.
- </para>
-
- <sect2 id="tutorial-firstapp-firstclass">
- <title>The first class</title>
-
- <para>
- Our first persistent class is a simple JavaBean class with some properties:
- </para>
-
- <programlisting><![CDATA[package org.hibernate.tutorial.domain;
-
-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">
- <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 identifier 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(http://hsqldb.org/). 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="5">
- <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 current unit of work is bound to the current Java thread that executes our application.
- However, this is not the full picture, you also have to consider scope, when a unit of work
- begins and when it ends.
- </para>
-
- <para>
- 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 through commit or rollback, Hibernate automatically
- 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, as it allows flexible layering of your code (transaction
- demarcation code can be separated from data access code, we'll do this later in this tutorial).
- </para>
-
- <para>
- Related to the unit of work scope, should the Hibernate <literal>Session</literal> be used to
- execute one or several database operations? The above example uses one <literal>Session</literal>
- for one operation. This is pure coincidence, the example is just not complex enough to show any
- other approach. The scope of a Hibernate <literal>Session</literal> is flexible but you should
- never design your application to use a new Hibernate <literal>Session</literal> for
- <emphasis>every</emphasis> database operation. So even if you see it a few more times in
- the following (very trivial) examples, consider <emphasis>session-per-operation</emphasis>
- an anti-pattern. A real (web) application is shown later in this tutorial.
- </para>
-
- <para>
- 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 continuous 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="2">
- <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 didn't 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 defensively and create 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>
-
- </sect1>
-
- <sect1 id="tutorial-webapp">
- <title>Part 3 - The EventManager web application</title>
-
- <para>
- Let's turn the following discussion into a small web application...
- </para>
-
- <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="2">
- <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>
- Do <emphasis>not</emphasis> use a new Hibernate <literal>Session</literal> for
- every database operation. Use one Hibernate <literal>Session</literal> that is
- scoped to the whole request. Use <literal>getCurrentSession()</literal>, so that
- it is automatically bound to the current Java thread.
- </para>
-
- <para>
- 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 occurred 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
- objects 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 compilation 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>
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/content/xml.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/xml.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/xml.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,313 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<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>
-
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/images/AuthorWork.png
===================================================================
(Binary files differ)
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/images/AuthorWork.zargo
===================================================================
(Binary files differ)
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/images/CustomerOrderProduct.png
===================================================================
(Binary files differ)
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/images/CustomerOrderProduct.zargo
===================================================================
(Binary files differ)
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/images/EmployerEmployee.png
===================================================================
(Binary files differ)
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/images/EmployerEmployee.zargo
===================================================================
(Binary files differ)
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/images/full_cream.png
===================================================================
(Binary files differ)
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/images/full_cream.svg
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/images/full_cream.svg 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/images/full_cream.svg 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,429 +0,0 @@
-<?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>
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/images/hibernate_logo_a.png
===================================================================
(Binary files differ)
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/images/lite.png
===================================================================
(Binary files differ)
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/images/lite.svg
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/images/lite.svg 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/images/lite.svg 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,334 +0,0 @@
-<?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>
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/images/overview.png
===================================================================
(Binary files differ)
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/images/overview.svg
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/images/overview.svg 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/images/overview.svg 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,250 +0,0 @@
-<?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>
Deleted: core/trunk/documentation/envers/src/main/docbook/en-US/translators.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/translators.xml 2008-11-04 03:12:55 UTC (rev 15494)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/translators.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -1,154 +0,0 @@
-<?xml version='1.0' encoding="UTF-8"?>
-<!--
- ~ Hibernate, Relational Persistence for Idiomatic Java
- ~
- ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
- ~ indicated by the @author tags or express copyright attribution
- ~ statements applied by the authors. All third-party contributions are
- ~ distributed under license by Red Hat Middleware LLC.
- ~
- ~ This copyrighted material is made available to anyone wishing to use, modify,
- ~ copy, or redistribute it subject to the terms and conditions of the GNU
- ~ Lesser General Public License, as published by the Free Software Foundation.
- ~
- ~ This program is distributed in the hope that it will be useful,
- ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- ~ for more details.
- ~
- ~ You should have received a copy of the GNU Lesser General Public License
- ~ along with this distribution; if not, write to:
- ~ Free Software Foundation, Inc.
- ~ 51 Franklin Street, Fifth Floor
- ~ Boston, MA 02110-1301 USA
- -->
-
-<!DOCTYPE authorgroup PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<authorgroup id="AuthorGroup">
-
- <!--
- #######################################################################
- # Spanish
- #######################################################################
- -->
- <othercredit class="translator" lang="es-ES">
- <othername><![CDATA[Bernardo Antonio Buffa Colomé]]></othername>
- <email>kreimer(a)bbs.frc.utn.edu.ar</email>
- </othercredit>
-
- <!--
- #######################################################################
- # French
- #######################################################################
- -->
- <othercredit class="translator" lang="fr-FR">
- <firstname>Vincent</firstname>
- <surname>Ricard</surname>
- </othercredit>
- <othercredit class="translator" lang="fr-FR">
- <firstname>Sebastien</firstname>
- <surname>Cesbron</surname>
- </othercredit>
- <othercredit class="translator" lang="fr-FR">
- <firstname>Michael</firstname>
- <surname>Courcy</surname>
- </othercredit>
- <othercredit class="translator" lang="fr-FR">
- <firstname>Vincent</firstname>
- <surname>Giguère</surname>
- </othercredit>
- <othercredit class="translator" lang="fr-FR">
- <firstname>Baptiste</firstname>
- <surname>Mathus</surname>
- </othercredit>
- <othercredit class="translator" lang="fr-FR">
- <firstname>Emmanuel</firstname>
- <surname>Bernard</surname>
- </othercredit>
- <othercredit class="translator" lang="fr-FR">
- <firstname>Anthony</firstname>
- <surname>Patricio</surname>
- </othercredit>
-
- <!--
- #######################################################################
- # Portugese
- #######################################################################
- -->
- <othercredit class="translator" lang="pt-BR">
- <firstname>Alvaro</firstname>
- <surname>Netto</surname>
- <email>alvaronetto(a)cetip.com.br</email>
- </othercredit>
- <othercredit class="translator" lang="pt-BR">
- <firstname>Anderson</firstname>
- <surname>Braulio</surname>
- <email>andersonbraulio(a)gmail.com</email>
- </othercredit>
- <othercredit class="translator" lang="pt-BR">
- <firstname>Daniel Vieira</firstname>
- <surname>Costa</surname>
- <email>danielvc(a)gmail.com</email>
- </othercredit>
- <othercredit class="translator" lang="pt-BR">
- <firstname>Francisco</firstname>
- <surname>gamarra</surname>
- <email>francisco.gamarra(a)gmail.com</email>
- </othercredit>
- <othercredit class="translator" lang="pt-BR">
- <firstname>Gamarra</firstname>
- <email>mauricio.gamarra(a)gmail.com</email>
- </othercredit>
- <othercredit class="translator" lang="pt-BR">
- <firstname>Luiz Carlos</firstname>
- <surname>Rodrigues</surname>
- <email>luizcarlos_rodrigues(a)yahoo.com.br</email>
- </othercredit>
- <othercredit class="translator" lang="pt-BR">
- <firstname>Marcel</firstname>
- <surname>Castelo</surname>
- <email>marcel.castelo(a)gmail.com</email>
- </othercredit>
- <othercredit class="translator" lang="pt-BR">
- <firstname>Paulo</firstname>
- <surname>César</surname>
- <email>paulocol(a)gmail.com</email>
- </othercredit>
- <othercredit class="translator" lang="pt-BR">
- <firstname>Pablo L.</firstname>
- <surname>de Miranda</surname>
- <email>pablolmiranda(a)gmail.com</email>
- </othercredit>
- <othercredit class="translator" lang="pt-BR">
- <firstname>Renato</firstname>
- <surname>Deggau</surname>
- <email>rdeggau(a)gmail.com</email>
- </othercredit>
- <othercredit class="translator" lang="pt-BR">
- <firstname>Rogério</firstname>
- <surname>Araújo</surname>
- <email>rgildoaraujo(a)yahoo.com.br</email>
- </othercredit>
- <othercredit class="translator" lang="pt-BR">
- <firstname>Wanderson</firstname>
- <surname>Siqueira</surname>
- <email>wandersonxs(a)gmail.com</email>
- </othercredit>
-
- <!--
- #######################################################################
- # Chinese
- #######################################################################
- -->
- <othercredit class="translator" lang="zh-CN">
- <firstname>Cao</firstname>
- <surname>Xiaogang</surname>
- <affiliation>
- <orgname>RedSaga</orgname>
- </affiliation>
- <contrib>Translation Lead</contrib>
- <email>caoxg(a)yahoo.com</email>
- </othercredit>
-
-</authorgroup>
Modified: core/trunk/documentation/pom.xml
===================================================================
--- core/trunk/documentation/pom.xml 2008-11-04 15:59:43 UTC (rev 15496)
+++ core/trunk/documentation/pom.xml 2008-11-04 17:06:23 UTC (rev 15497)
@@ -19,6 +19,7 @@
<modules>
<module>releasenotes</module>
<module>manual</module>
+ <module>envers</module>
<!--
<module>jbosscache2</module>
-->
16 years, 2 months
Hibernate SVN: r15496 - in search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker: duplication and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: anthonyHib
Date: 2008-11-04 10:59:43 -0500 (Tue, 04 Nov 2008)
New Revision: 15496
Added:
search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/
search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/EmailAddress.java
search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/Person.java
search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/SpecialPerson.java
search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/WorkDuplicationTest.java
Log:
JBPAPP-1361 port of HSEARCH-257 Ignore delete operation when Core does update then delete on the same entity
Added: search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/EmailAddress.java
===================================================================
--- search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/EmailAddress.java (rev 0)
+++ search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/EmailAddress.java 2008-11-04 15:59:43 UTC (rev 15496)
@@ -0,0 +1,57 @@
+// $Id:$
+package org.hibernate.search.test.worker.duplication;
+
+import java.io.Serializable;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+import org.hibernate.search.annotations.DocumentId;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Index;
+import org.hibernate.search.annotations.Store;
+
+/**
+ * Test entity for HSEARCH-257.
+ *
+ * @author Hardy Ferentschik
+ */
+@Entity
+public class EmailAddress implements Serializable {
+ @Id
+ @GeneratedValue
+ @DocumentId
+ private int id;
+
+ private boolean isDefaultAddress;
+
+ @Field(store = Store.YES, index = Index.NO)
+ private String address;
+
+ public EmailAddress() {
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public boolean isDefaultAddress() {
+ return isDefaultAddress;
+ }
+
+ public void setDefaultAddress(boolean isDefault) {
+ isDefaultAddress = isDefault;
+ }
+}
Added: search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/Person.java
===================================================================
--- search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/Person.java (rev 0)
+++ search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/Person.java 2008-11-04 15:59:43 UTC (rev 15496)
@@ -0,0 +1,82 @@
+// $Id:$
+package org.hibernate.search.test.worker.duplication;
+
+import javax.persistence.DiscriminatorColumn;
+import javax.persistence.DiscriminatorType;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.Table;
+import javax.persistence.OneToOne;
+import javax.persistence.JoinColumn;
+import javax.persistence.CascadeType;
+import javax.persistence.FetchType;
+
+import org.hibernate.search.annotations.DocumentId;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Index;
+
+/**
+ * Test entity for HSEARCH-257.
+ *
+ * @author Marina Vatkina
+ * @author Hardy Ferentschik
+ */
+@Entity
+@Table
+@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
+@DiscriminatorColumn(name = "DISC", discriminatorType = DiscriminatorType.STRING)
+public class Person {
+
+ @Id
+ @GeneratedValue
+ @DocumentId
+ private int id;
+
+ @Field(index = Index.TOKENIZED, name = "Content")
+ private String name;
+
+ @OneToOne(fetch = FetchType.EAGER, cascade = {
+ CascadeType.MERGE,
+ CascadeType.PERSIST
+ })
+ @JoinColumn(name = "DEFAULT_EMAILADDRESS_FK")
+ private EmailAddress defaultEmailAddress;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * This function return the value of defaultEmailAddress.
+ *
+ * @return the defaultEmailAddress
+ */
+
+ public EmailAddress getDefaultEmailAddress() {
+ return defaultEmailAddress;
+ }
+
+ /**
+ * This function sets the value of the defaultEmailAddress.
+ *
+ * @param defaultEmailAddress the defaultEmailAddress to set
+ */
+ protected void setDefaultEmailAddress(EmailAddress defaultEmailAddress) {
+ this.defaultEmailAddress = defaultEmailAddress;
+ }
+}
Added: search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/SpecialPerson.java
===================================================================
--- search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/SpecialPerson.java (rev 0)
+++ search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/SpecialPerson.java 2008-11-04 15:59:43 UTC (rev 15496)
@@ -0,0 +1,127 @@
+// $Id:$
+package org.hibernate.search.test.worker.duplication;
+
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.CascadeType;
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToMany;
+
+import org.hibernate.annotations.Cascade;
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.IndexedEmbedded;
+
+/**
+ * Test entity for HSEARCH-257.
+ *
+ * @author Hardy Ferentschik
+ */
+@Entity
+@Indexed
+@DiscriminatorValue("SpecialPerson")
+public class SpecialPerson extends Person {
+
+ @OneToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL })
+ @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
+ @JoinColumn(name = "SPECIALPERSON_FK")
+ @IndexedEmbedded
+ private Set<EmailAddress> emailAddressSet = new HashSet<EmailAddress>();
+
+ public Set<EmailAddress> getEmailAddressSet() {
+ return emailAddressSet;
+ }
+
+ public void setEmailAddressSet(Set<EmailAddress> emailAddresses) {
+ EmailAddress defaultVal = getDefaultEmailAddressFromList( emailAddresses );
+
+ super.setDefaultEmailAddress( defaultVal );
+
+ emailAddressSet = emailAddresses;
+ }
+
+ /**
+ * This function add the provided emailAddress to the existing set.
+ *
+ * @param emailAddress EmailAddress to add the the set
+ */
+ public void addEmailAddress(EmailAddress emailAddress) {
+ if ( emailAddress != null ) {
+ if ( emailAddressSet == null ) {
+ emailAddressSet = new HashSet<EmailAddress>();
+ }
+
+ // We cannot add another default address to the list. Check if
+ // default
+ // address has been set before.
+ if ( emailAddress.isDefaultAddress() ) {
+ // Replace old default address with new one.
+ processDefaultEmailAddress( emailAddress, emailAddressSet );
+
+ super.setDefaultEmailAddress( emailAddress );
+ }
+ else {
+ emailAddressSet.add( emailAddress );
+ }
+ }
+ }
+
+ private void processDefaultEmailAddress(EmailAddress defaultVal,
+ Set<EmailAddress> list) {
+ if ( defaultVal != null ) {
+ boolean addToList = true;
+
+ for ( EmailAddress aList : list ) {
+
+ if ( defaultVal.equals( aList ) ) {
+ aList.setDefaultAddress( true );
+ addToList = false;
+ }
+ else if ( aList.isDefaultAddress() ) {
+ // Reset default value.
+ aList.setDefaultAddress( false );
+ }
+ }
+
+ // Add Email Address to the list if list does not contain it.
+ if ( addToList ) {
+ list.add( defaultVal );
+ }
+ }
+ }
+
+ private EmailAddress getDefaultEmailAddressFromList(
+ Set<EmailAddress> list) {
+ EmailAddress address = null;
+ EmailAddress firstAddressInList = null;
+ boolean found = false;
+
+ if ( list != null ) {
+ for ( EmailAddress aList : list ) {
+ address = aList;
+
+ if ( address != null ) {
+ if ( firstAddressInList == null ) {
+ firstAddressInList = address;
+ }
+
+ if ( address.isDefaultAddress() ) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if ( !found && firstAddressInList != null ) {
+ // If default address was not found we set the first one as
+ // default.
+ firstAddressInList.setDefaultAddress( true );
+ address = firstAddressInList;
+ }
+ }
+
+ return address;
+ }
+}
Added: search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/WorkDuplicationTest.java
===================================================================
--- search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/WorkDuplicationTest.java (rev 0)
+++ search/branches/Branch_3_0_1_GA_CP/src/test/org/hibernate/search/test/worker/duplication/WorkDuplicationTest.java 2008-11-04 15:59:43 UTC (rev 15496)
@@ -0,0 +1,92 @@
+// $Id: WorkDuplicationTest.java 15438 2008-10-29 16:52:19Z hardy.ferentschik $
+package org.hibernate.search.test.worker.duplication;
+
+import java.util.List;
+
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.TopDocs;
+
+import org.hibernate.Transaction;
+import org.hibernate.search.FullTextQuery;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.reader.ReaderProvider;
+import org.hibernate.search.store.DirectoryProvider;
+import org.hibernate.search.test.SearchTestCase;
+
+/**
+ * Testcase for HSEARCH-257.
+ */
+public class WorkDuplicationTest extends SearchTestCase {
+
+ /**
+ * This test assures that HSEARCH-257. Before the fix Search would issue another <code>AddLuceneWork</code> after
+ * the <code>DeleteLuceneWork</code>. This lead to the fact that after the deletion there was still a Lucene document
+ * in the index.
+ *
+ * @throws Exception in case the test fails.
+ */
+ public void testNoWorkDuplication() throws Exception {
+
+ FullTextSession s = org.hibernate.search.Search.createFullTextSession( openSession() );
+ Transaction tx = s.beginTransaction();
+
+ // create new customer
+ SpecialPerson person = new SpecialPerson();
+ person.setName( "Joe Smith" );
+
+ EmailAddress emailAddress = new EmailAddress();
+ emailAddress.setAddress( "foo(a)foobar.com" );
+ emailAddress.setDefaultAddress(true);
+
+ person.addEmailAddress( emailAddress );
+
+ // persist the customer
+ s.persist( person );
+ tx.commit();
+
+ // search if the record made it into the index
+ tx = s.beginTransaction();
+ String searchQuery = "Joe";
+ QueryParser parser = new QueryParser( "Content", new StandardAnalyzer() );
+ Query luceneQuery = parser.parse( searchQuery );
+ FullTextQuery query = s.createFullTextQuery( luceneQuery );
+ List results = query.list();
+ assertTrue( "We should have a hit", results.size() == 1 );
+ tx.commit();
+
+ // Now try to delete
+ tx = s.beginTransaction();
+ int id = person.getId();
+ person = ( SpecialPerson ) s.get( SpecialPerson.class, id );
+ s.delete( person );
+ tx.commit();
+
+ // Search and the record via Lucene directly
+ tx = s.beginTransaction();
+
+ DirectoryProvider directoryProvider = s.getSearchFactory().getDirectoryProviders( SpecialPerson.class )[0];
+ ReaderProvider readerProvider = s.getSearchFactory().getReaderProvider();
+ IndexReader reader = readerProvider.openReader( directoryProvider );
+ IndexSearcher searcher = new IndexSearcher( reader );
+
+ try {
+ // we have to test using Lucene directly since query loaders will ignore hits for which there is no
+ // database entry
+ TopDocs topDocs = searcher.search( luceneQuery, null, 1 );
+ assertTrue( "We should have no hit", topDocs.totalHits == 0 );
+ }
+ finally {
+ readerProvider.closeReader( reader );
+ }
+ tx.commit();
+ s.close();
+ }
+
+ protected Class[] getMappings() {
+ return new Class[] { Person.class, EmailAddress.class, SpecialPerson.class };
+ }
+}
16 years, 2 months
Hibernate SVN: r15495 - search/branches/Branch_3_0_1_GA_CP/src/java/org/hibernate/search/engine.
by hibernate-commits@lists.jboss.org
Author: anthonyHib
Date: 2008-11-04 10:58:44 -0500 (Tue, 04 Nov 2008)
New Revision: 15495
Modified:
search/branches/Branch_3_0_1_GA_CP/src/java/org/hibernate/search/engine/DocumentBuilder.java
Log:
JBPAPP-1361 port of HSEARCH-257 Ignore delete operation when Core does update then delete on the same entity
Modified: search/branches/Branch_3_0_1_GA_CP/src/java/org/hibernate/search/engine/DocumentBuilder.java
===================================================================
--- search/branches/Branch_3_0_1_GA_CP/src/java/org/hibernate/search/engine/DocumentBuilder.java 2008-11-04 03:12:55 UTC (rev 15494)
+++ search/branches/Branch_3_0_1_GA_CP/src/java/org/hibernate/search/engine/DocumentBuilder.java 2008-11-04 15:58:44 UTC (rev 15495)
@@ -3,13 +3,7 @@
import java.io.Serializable;
import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -399,18 +393,39 @@
//TODO could we use T instead of EntityClass?
public void addWorkToQueue(Class entityClass, T entity, Serializable id, WorkType workType, List<LuceneWork> queue, SearchFactoryImplementor searchFactoryImplementor) {
//TODO with the caller loop we are in a n^2: optimize it using a HashMap for work recognition
+ List<LuceneWork> toDelete = new ArrayList<LuceneWork>();
+ boolean duplicateDelete = false;
for (LuceneWork luceneWork : queue) {
- //any work on the same entity should be ignored
- if ( luceneWork.getEntityClass() == entityClass
- ) {
+ //avoid unecessary duplicated work
+ if ( luceneWork.getEntityClass() == entityClass ) {
Serializable currentId = luceneWork.getId();
- if ( currentId != null && currentId.equals( id ) ) { //find a way to use Type.equals(x,y)
- return;
+ //currentId != null => either ADD or Delete work
+ if ( currentId != null && currentId.equals( id ) ) { //find a way to use Type.equals(x,y)
+ if (workType == WorkType.DELETE) { //TODO add PURGE?
+ //DELETE should have precedence over any update before (HSEARCH-257)
+ //if an Add work is here, remove it
+ //if an other delete is here remember but still search for Add
+ if (luceneWork instanceof AddLuceneWork) {
+ toDelete.add( luceneWork );
+ }
+ else if (luceneWork instanceof DeleteLuceneWork) {
+ duplicateDelete = true;
+ }
+ }
+ else {
+ //we can safely say we are out, the other work is an ADD
+ return;
+ }
}
//TODO do something to avoid multiple PURGE ALL and OPTIMIZE
}
+ }
+ for (LuceneWork luceneWork : toDelete) {
+ queue.remove( luceneWork );
}
+ if (duplicateDelete) return;
+
boolean searchForContainers = false;
String idInString = idBridge.objectToString( id );
if ( workType == WorkType.ADD ) {
16 years, 2 months
Hibernate SVN: r15494 - in validator/trunk: validation-api/src/main/java/javax/validation and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2008-11-03 22:12:55 -0500 (Mon, 03 Nov 2008)
New Revision: 15494
Removed:
validator/trunk/validation-api/src/main/java/javax/validation/StandardConstraint.java
validator/trunk/validation-api/src/main/java/javax/validation/StandardConstraintDescriptor.java
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/constraints/LengthConstraint.java
Log:
Remove obsolete StandardConstraint(Descriptor)
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/constraints/LengthConstraint.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/constraints/LengthConstraint.java 2008-11-04 02:37:22 UTC (rev 15493)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/constraints/LengthConstraint.java 2008-11-04 03:12:55 UTC (rev 15494)
@@ -18,8 +18,6 @@
package org.hibernate.validation.constraints;
import javax.validation.Constraint;
-import javax.validation.StandardConstraint;
-import javax.validation.StandardConstraintDescriptor;
import javax.validation.ConstraintContext;
/**
@@ -28,7 +26,7 @@
* @author Emmanuel Bernard
* @author Gavin King
*/
-public class LengthConstraint implements Constraint<Length>, StandardConstraint {
+public class LengthConstraint implements Constraint<Length> {
private int min;
private int max;
@@ -49,16 +47,4 @@
return length >= min && length <= max;
}
- public StandardConstraintDescriptor getStandardConstraints() {
- return new StandardConstraintDescriptor() {
- public Integer getLength() {
- if ( max == Integer.MAX_VALUE ) {
- return null;
- }
- else {
- return max;
- }
- }
- };
- }
}
Deleted: validator/trunk/validation-api/src/main/java/javax/validation/StandardConstraint.java
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/StandardConstraint.java 2008-11-04 02:37:22 UTC (rev 15493)
+++ validator/trunk/validation-api/src/main/java/javax/validation/StandardConstraint.java 2008-11-04 03:12:55 UTC (rev 15494)
@@ -1,32 +0,0 @@
-// $Id$
-/*
-* JBoss, Home of Professional Open Source
-* Copyright 2008, Red Hat Middleware LLC, and individual contributors
-* by the @authors tag. See the copyright.txt in the distribution for a
-* full listing of individual contributors.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-* http://www.apache.org/licenses/LICENSE-2.0
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-package javax.validation;
-
-/**
- * Define the constraint influence on standard constraint dimensions
- *
- * @author Emmanuel Bernard
- * @author Hardy Ferentschik
- */
-public interface StandardConstraint {
- /**
- * returns the StandardConstraintDescriptor initialized according to the
- * constraint validator
- */
- StandardConstraintDescriptor getStandardConstraints();
-}
Deleted: validator/trunk/validation-api/src/main/java/javax/validation/StandardConstraintDescriptor.java
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/StandardConstraintDescriptor.java 2008-11-04 02:37:22 UTC (rev 15493)
+++ validator/trunk/validation-api/src/main/java/javax/validation/StandardConstraintDescriptor.java 2008-11-04 03:12:55 UTC (rev 15494)
@@ -1,63 +0,0 @@
-// $Id$
-/*
-* JBoss, Home of Professional Open Source
-* Copyright 2008, Red Hat Middleware LLC, and individual contributors
-* by the @authors tag. See the copyright.txt in the distribution for a
-* full listing of individual contributors.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-* http://www.apache.org/licenses/LICENSE-2.0
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-package javax.validation;
-
-/**
- * Describe how the current constraint influences the standard constraints.
- *
- * @author Emmanuel Bernard
- * @author Hardy Ferentschik
- */
-public class StandardConstraintDescriptor {
- /**
- * Defines the object nullability.
- *
- * @return <code>TRUE<code> if the object is nullable, <code>FALSE</code> if object is not
- * nullable and <code>null</code> if nullabiltiy does not apply.
- */
- public Boolean getNullability() {
- return null;
- }
-
- /**
- * Defines the precision if the validated object is a number.
- *
- * @return the number's precision or <code>null</code> if precision does not apply.
- */
- public Integer getPrecision() {
- return null;
- }
-
- /**
- * Defines the scale if the validated object is a number.
- *
- * @return the number's scale or <code>null</code> if scale does not apply.
- */
- public Integer getScale() {
- return null;
- }
-
- /**
- * Defines the length if the validated object is a string.
- *
- * @return the strings's length or <code>null</code> if length does not apply.
- */
- public Integer getLength() {
- return null;
- }
-}
16 years, 2 months
Hibernate SVN: r15493 - in validator/trunk: validation-api/src/main/java/javax/validation/spi and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2008-11-03 21:37:22 -0500 (Mon, 03 Nov 2008)
New Revision: 15493
Added:
validator/trunk/validation-api/src/main/java/javax/validation/spi/ValidatorFactoryConfiguration.java
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/HibernateValidationProvider.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryBuilderImpl.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryImpl.java
validator/trunk/validation-api/src/main/java/javax/validation/spi/ValidationProvider.java
Log:
BVAL-63 Rename ValidatorBuilderImplementor to ValidatorFactoryConfiguration
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/HibernateValidationProvider.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/HibernateValidationProvider.java 2008-11-04 02:26:44 UTC (rev 15492)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/HibernateValidationProvider.java 2008-11-04 02:37:22 UTC (rev 15493)
@@ -21,7 +21,7 @@
import javax.validation.ValidatorFactoryBuilder;
import javax.validation.ValidatorFactory;
import javax.validation.spi.ValidationProvider;
-import javax.validation.spi.ValidatorBuilderImplementor;
+import javax.validation.spi.ValidatorFactoryConfiguration;
import javax.validation.spi.BootstrapState;
import org.hibernate.validation.HibernateValidatorFactoryBuilder;
@@ -59,7 +59,7 @@
/**
* {@inheritDoc}
*/
- public ValidatorFactory buildValidatorFactory(ValidatorBuilderImplementor validatorBuilder) {
- return new ValidatorFactoryImpl( validatorBuilder );
+ public ValidatorFactory buildValidatorFactory(ValidatorFactoryConfiguration configuration) {
+ return new ValidatorFactoryImpl( configuration );
}
}
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryBuilderImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryBuilderImpl.java 2008-11-04 02:26:44 UTC (rev 15492)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryBuilderImpl.java 2008-11-04 02:37:22 UTC (rev 15493)
@@ -27,7 +27,7 @@
import javax.validation.ValidatorFactory;
import javax.validation.bootstrap.DefaultValidationProviderResolver;
import javax.validation.spi.ValidationProvider;
-import javax.validation.spi.ValidatorBuilderImplementor;
+import javax.validation.spi.ValidatorFactoryConfiguration;
import javax.validation.spi.BootstrapState;
import org.hibernate.validation.HibernateValidatorFactoryBuilder;
@@ -35,7 +35,7 @@
/**
* @author Emmanuel Bernard
*/
-public class ValidatorFactoryBuilderImpl implements HibernateValidatorFactoryBuilder, ValidatorBuilderImplementor {
+public class ValidatorFactoryBuilderImpl implements HibernateValidatorFactoryBuilder, ValidatorFactoryConfiguration {
private MessageResolver messageResolver = new ResourceBundleMessageResolver();
private ConstraintFactory constraintFactory = new ConstraintFactoryImpl();
private String configurationFile = "META-INF/validation.xml";
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryImpl.java 2008-11-04 02:26:44 UTC (rev 15492)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryImpl.java 2008-11-04 02:37:22 UTC (rev 15493)
@@ -21,7 +21,7 @@
import javax.validation.MessageResolver;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
-import javax.validation.spi.ValidatorBuilderImplementor;
+import javax.validation.spi.ValidatorFactoryConfiguration;
import org.hibernate.validation.engine.ValidatorImpl;
@@ -35,9 +35,9 @@
private final ConstraintFactory constraintFactory;
- public ValidatorFactoryImpl(ValidatorBuilderImplementor validatorBuilder) {
- this.messageResolver = validatorBuilder.getMessageResolver();
- this.constraintFactory = validatorBuilder.getConstraintFactory();
+ public ValidatorFactoryImpl(ValidatorFactoryConfiguration configuration) {
+ this.messageResolver = configuration.getMessageResolver();
+ this.constraintFactory = configuration.getConstraintFactory();
//do init metadata from XML form
}
Modified: validator/trunk/validation-api/src/main/java/javax/validation/spi/ValidationProvider.java
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/spi/ValidationProvider.java 2008-11-04 02:26:44 UTC (rev 15492)
+++ validator/trunk/validation-api/src/main/java/javax/validation/spi/ValidationProvider.java 2008-11-04 02:37:22 UTC (rev 15493)
@@ -68,7 +68,7 @@
/**
* Build a ValidatorFactory using the current provider implementation. The ValidationFactory
- * is assembled and follow the configuration passed using ValidatorBuilderImplementor.
+ * is assembled and follow the configuration passed using ValidatorFactoryConfiguration.
* <p>
* The returned ValidatorFactory is properly initialized and ready for use.
* </p>
@@ -77,5 +77,5 @@
*
* @return the instanciated ValidatorFactory
*/
- ValidatorFactory buildValidatorFactory(ValidatorBuilderImplementor configuration);
+ ValidatorFactory buildValidatorFactory(ValidatorFactoryConfiguration configuration);
}
\ No newline at end of file
Copied: validator/trunk/validation-api/src/main/java/javax/validation/spi/ValidatorFactoryConfiguration.java (from rev 15487, validator/trunk/validation-api/src/main/java/javax/validation/spi/ValidatorBuilderImplementor.java)
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/spi/ValidatorFactoryConfiguration.java (rev 0)
+++ validator/trunk/validation-api/src/main/java/javax/validation/spi/ValidatorFactoryConfiguration.java 2008-11-04 02:37:22 UTC (rev 15493)
@@ -0,0 +1,56 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2008, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package javax.validation.spi;
+
+import java.io.InputStream;
+import javax.validation.ConstraintFactory;
+import javax.validation.MessageResolver;
+
+/**
+ * Contract between a <code>ValidatorFactoryBuilder</code> and a </code>ValidatorProvider</code> to create
+ * a <code>ValidatorFactory</code>.
+ * The configuration artifacts provided to the <code>ValidationBuilder</code> are passed along.
+ *
+ * @author Emmanuel Bernard
+ * @author Hardy Ferentschik
+ */
+public interface ValidatorFactoryConfiguration {
+ /**
+ * Message resolver as defined by the client programmatically
+ * or null if undefined.
+ *
+ * @return message provider instance or null if not defined
+ */
+ MessageResolver getMessageResolver();
+
+ /**
+ * Returns the configuration stream defined by the client programmatically
+ * or null if undefined.
+ *
+ * @return the configuration input stream or null
+ */
+ InputStream getConfigurationStream();
+
+ /**
+ * Defines the constraint implementation factory as defined by the client programmatically
+ * or null if undefined
+ *
+ * @return factory instance or null if not defined
+ */
+ ConstraintFactory getConstraintFactory();
+}
Property changes on: validator/trunk/validation-api/src/main/java/javax/validation/spi/ValidatorFactoryConfiguration.java
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:keywords
+ Id
16 years, 2 months
Hibernate SVN: r15492 - in validator/trunk: hibernate-validator/src/main/java/org/hibernate/validation/engine and 5 other directories.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2008-11-03 21:26:44 -0500 (Mon, 03 Nov 2008)
New Revision: 15492
Added:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/HibernateValidatorFactoryBuilder.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryBuilderImpl.java
validator/trunk/validation-api/src/main/java/javax/validation/ValidatorFactoryBuilder.java
Removed:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ContextImpl.java
validator/trunk/validation-api/src/main/java/javax/validation/ReportAsViolationFromComposingConstraint.java
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/HibernateValidationProvider.java
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/bootstrap/ValidationTest.java
validator/trunk/validation-api/src/main/java/javax/validation/Validation.java
validator/trunk/validation-api/src/main/java/javax/validation/bootstrap/GenericBuilderFactory.java
validator/trunk/validation-api/src/main/java/javax/validation/bootstrap/SpecializedBuilderFactory.java
validator/trunk/validation-api/src/main/java/javax/validation/spi/ValidationProvider.java
Log:
BVAL-62 rename ValidatorBuilder into ValidatorFactoryBuilder
Copied: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/HibernateValidatorFactoryBuilder.java (from rev 15487, validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/HibernateValidatorBuilder.java)
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/HibernateValidatorFactoryBuilder.java (rev 0)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/HibernateValidatorFactoryBuilder.java 2008-11-04 02:26:44 UTC (rev 15492)
@@ -0,0 +1,12 @@
+package org.hibernate.validation;
+
+import javax.validation.ValidatorFactoryBuilder;
+
+/**
+ * Uniquely identify Hibernate Validator in the Bean Validation bootstrap strategy
+ * Also contains Hibernate Validator specific configurations
+ *
+ * @author Emmanuel Bernard
+ */
+public interface HibernateValidatorFactoryBuilder extends ValidatorFactoryBuilder<HibernateValidatorFactoryBuilder> {
+}
Property changes on: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/HibernateValidatorFactoryBuilder.java
___________________________________________________________________
Name: svn:keywords
+ Id
Deleted: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ContextImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ContextImpl.java 2008-11-04 00:14:54 UTC (rev 15491)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ContextImpl.java 2008-11-04 02:26:44 UTC (rev 15492)
@@ -1,69 +0,0 @@
-package org.hibernate.validation.engine;
-
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Collections;
-import javax.validation.Context;
-import javax.validation.ConstraintDescriptor;
-
-import org.hibernate.validation.impl.ConstraintDescriptorImpl;
-
-/**
- * @author Emmanuel Bernard
- */
-public class ContextImpl implements Context {
- private final ConstraintDescriptor constraintDescriptor;
- private final List<ErrorMessage> errorMessages;
- private boolean defaultDisabled;
-
- public ContextImpl(ConstraintDescriptorImpl constraintDescriptor) {
- this.constraintDescriptor = constraintDescriptor;
- this.errorMessages = new ArrayList<ErrorMessage>(3);
- }
-
- public void disableDefaultError() {
- defaultDisabled = true;
- }
-
- public String getDefaultErrorMessage() {
- return ( String ) constraintDescriptor.getParameters().get("message");
- }
-
- public void addError(String message) {
- //FIXME get the default property if property-level
- errorMessages.add( new ErrorMessage( message, null ) );
- }
-
- public void addError(String message, String property) {
- //FIXME: make sure the property is valid
- errorMessages.add( new ErrorMessage( message, property ) );
- }
-
- public List<ErrorMessage> getErrorMessages() {
- List<ErrorMessage> returnedErrorMessages = new ArrayList<ErrorMessage>( errorMessages.size() + 1 );
- Collections.copy( returnedErrorMessages, errorMessages );
- if ( ! defaultDisabled ) {
- //FIXME get the default property if property-level
- returnedErrorMessages.add( new ErrorMessage( getDefaultErrorMessage(), null) );
- }
- return returnedErrorMessages;
- }
-
- public static class ErrorMessage {
- private final String message;
- private final String property;
-
- private ErrorMessage(String message, String property) {
- this.message = message;
- this.property = property;
- }
-
- public String getMessage() {
- return message;
- }
-
- public String getProperty() {
- return property;
- }
- }
-}
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/HibernateValidationProvider.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/HibernateValidationProvider.java 2008-11-04 00:14:54 UTC (rev 15491)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/HibernateValidationProvider.java 2008-11-04 02:26:44 UTC (rev 15492)
@@ -18,13 +18,13 @@
package org.hibernate.validation.impl;
import javax.validation.ValidationException;
-import javax.validation.ValidatorBuilder;
+import javax.validation.ValidatorFactoryBuilder;
import javax.validation.ValidatorFactory;
import javax.validation.spi.ValidationProvider;
import javax.validation.spi.ValidatorBuilderImplementor;
import javax.validation.spi.BootstrapState;
-import org.hibernate.validation.HibernateValidatorBuilder;
+import org.hibernate.validation.HibernateValidatorFactoryBuilder;
/**
* Default implementation of <code>ValidationProvider</code> within Hibernate validator.
@@ -37,23 +37,23 @@
/**
* {@inheritDoc}
*/
- public boolean isSuitable(Class<? extends ValidatorBuilder<?>> builderClass) {
- return builderClass == HibernateValidatorBuilder.class;
+ public boolean isSuitable(Class<? extends ValidatorFactoryBuilder<?>> builderClass) {
+ return builderClass == HibernateValidatorFactoryBuilder.class;
}
- public <T extends ValidatorBuilder<T>> T createSpecializedValidatorBuilder(BootstrapState state, Class<T> builderClass) {
+ public <T extends ValidatorFactoryBuilder<T>> T createSpecializedValidatorFactoryBuilder(BootstrapState state, Class<T> builderClass) {
if ( ! isSuitable( builderClass ) ) {
- throw new ValidationException("Illegal call to createSpecializedValidatorBuilder() for a non suitable provider");
+ throw new ValidationException("Illegal call to createSpecializedValidatorFactoryBuilder() for a non suitable provider");
}
//cast protected by isSuitable call
- return builderClass.cast( new ValidatorBuilderImpl( this ) );
+ return builderClass.cast( new ValidatorFactoryBuilderImpl( this ) );
}
/**
* {@inheritDoc}
*/
- public ValidatorBuilder<?> createGenericValidatorBuilder(BootstrapState state) {
- return new ValidatorBuilderImpl( state );
+ public ValidatorFactoryBuilder<?> createGenericValidatorFactoryBuilder(BootstrapState state) {
+ return new ValidatorFactoryBuilderImpl( state );
}
/**
Copied: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryBuilderImpl.java (from rev 15487, validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorBuilderImpl.java)
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryBuilderImpl.java (rev 0)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryBuilderImpl.java 2008-11-04 02:26:44 UTC (rev 15492)
@@ -0,0 +1,116 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2008, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.hibernate.validation.impl;
+
+import java.io.InputStream;
+import java.util.List;
+import javax.validation.ConstraintFactory;
+import javax.validation.MessageResolver;
+import javax.validation.ValidationException;
+import javax.validation.ValidationProviderResolver;
+import javax.validation.ValidatorFactoryBuilder;
+import javax.validation.ValidatorFactory;
+import javax.validation.bootstrap.DefaultValidationProviderResolver;
+import javax.validation.spi.ValidationProvider;
+import javax.validation.spi.ValidatorBuilderImplementor;
+import javax.validation.spi.BootstrapState;
+
+import org.hibernate.validation.HibernateValidatorFactoryBuilder;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class ValidatorFactoryBuilderImpl implements HibernateValidatorFactoryBuilder, ValidatorBuilderImplementor {
+ private MessageResolver messageResolver = new ResourceBundleMessageResolver();
+ private ConstraintFactory constraintFactory = new ConstraintFactoryImpl();
+ private String configurationFile = "META-INF/validation.xml";
+ private final ValidationProvider provider;
+ private final ValidationProviderResolver providerResolver;
+
+ public ValidatorFactoryBuilderImpl(BootstrapState state) {
+ if (state.getValidationProviderResolver() == null) {
+ this.providerResolver = new DefaultValidationProviderResolver();
+ }
+ else {
+ this.providerResolver = state.getValidationProviderResolver();
+ }
+ this.provider = null;
+ }
+
+ public ValidatorFactoryBuilderImpl(ValidationProvider provider) {
+ if ( provider == null ) {
+ throw new ValidationException( "Assertion error: inconsistent ValidatorFactoryBuilderImpl construction");
+ }
+ this.provider = provider;
+ this.providerResolver = null;
+ }
+
+ public ValidatorFactoryBuilderImpl messageResolver(MessageResolver resolver) {
+ this.messageResolver = resolver;
+ return this;
+ }
+
+ public ValidatorFactoryBuilderImpl constraintFactory(ConstraintFactory constraintFactory) {
+ this.constraintFactory = constraintFactory;
+ return this;
+ }
+
+ public ValidatorFactory build() {
+ if ( isSpecificProvider() ) {
+ return provider.buildValidatorFactory( this );
+ }
+ else {
+ //read provider name from configuration
+ Class<? extends ValidatorFactoryBuilder<?>> providerClass = null;
+
+ if ( providerClass != null ) {
+ for ( ValidationProvider provider : providerResolver.getValidationProviders() ) {
+ if ( provider.isSuitable( providerClass ) ) {
+ return provider.buildValidatorFactory( this );
+ }
+ }
+ throw new ValidationException( "Unable to find provider: " + providerClass );
+ }
+ else {
+ List<ValidationProvider> providers = providerResolver.getValidationProviders();
+ assert providers.size() != 0; //I run therefore I am
+ return providers.get( 0 ).buildValidatorFactory( this );
+ }
+ }
+ }
+
+ private boolean isSpecificProvider() {
+ return provider != null;
+ }
+
+ public MessageResolver getMessageResolver() {
+ return messageResolver;
+ }
+
+ public ConstraintFactory getConstraintFactory() {
+ return constraintFactory;
+ }
+
+ public ValidatorFactoryBuilderImpl configure(InputStream stream) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public InputStream getConfigurationStream() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
Property changes on: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ValidatorFactoryBuilderImpl.java
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:keywords
+ Id
Modified: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/bootstrap/ValidationTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/bootstrap/ValidationTest.java 2008-11-04 00:14:54 UTC (rev 15491)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/bootstrap/ValidationTest.java 2008-11-04 02:26:44 UTC (rev 15492)
@@ -29,7 +29,7 @@
import javax.validation.ValidationException;
import javax.validation.ValidationProviderResolver;
import javax.validation.Validator;
-import javax.validation.ValidatorBuilder;
+import javax.validation.ValidatorFactoryBuilder;
import javax.validation.ValidatorFactory;
import javax.validation.ConstraintContext;
import javax.validation.bootstrap.SpecializedBuilderFactory;
@@ -41,11 +41,11 @@
import static org.junit.Assert.fail;
import org.junit.Test;
-import org.hibernate.validation.HibernateValidatorBuilder;
+import org.hibernate.validation.HibernateValidatorFactoryBuilder;
import org.hibernate.validation.constraints.NotNullConstraint;
import org.hibernate.validation.eg.Customer;
import org.hibernate.validation.impl.ConstraintFactoryImpl;
-import org.hibernate.validation.impl.ValidatorBuilderImpl;
+import org.hibernate.validation.impl.ValidatorFactoryBuilderImpl;
import org.hibernate.validation.impl.ValidatorFactoryImpl;
import org.hibernate.validation.impl.HibernateValidationProvider;
@@ -58,21 +58,21 @@
@Test
public void testBootstrapAsServiceWithBuilder() {
- HibernateValidatorBuilder builder = Validation
- .builderType( HibernateValidatorBuilder.class )
- .getValidatorBuilder();
+ HibernateValidatorFactoryBuilder builder = Validation
+ .builderType( HibernateValidatorFactoryBuilder.class )
+ .getBuilder();
assertDefaultBuilderAndFactory( builder );
}
@Test
public void testBootstrapAsServiceDefault() {
- ValidatorBuilder<?> builder = Validation.getValidatorBuilder();
+ ValidatorFactoryBuilder<?> builder = Validation.getBuilder();
assertDefaultBuilderAndFactory( builder );
}
@Test
public void testGetCustomerValiator() {
- ValidatorBuilder<?> builder = Validation.getValidatorBuilder();
+ ValidatorFactoryBuilder<?> builder = Validation.getBuilder();
assertDefaultBuilderAndFactory( builder );
ValidatorFactory factory = builder.build();
@@ -95,7 +95,7 @@
public void testCustomMessageResolver() {
// first try with the default message resolver
- ValidatorBuilder<?> builder = Validation.getValidatorBuilder();
+ ValidatorFactoryBuilder<?> builder = Validation.getBuilder();
assertDefaultBuilderAndFactory( builder );
ValidatorFactory factory = builder.build();
@@ -129,7 +129,7 @@
@Test
public void testCustomConstraintFactory() {
- ValidatorBuilder<?> builder = Validation.getValidatorBuilder();
+ ValidatorFactoryBuilder<?> builder = Validation.getBuilder();
assertDefaultBuilderAndFactory( builder );
ValidatorFactory factory = builder.build();
@@ -173,10 +173,10 @@
};
- HibernateValidatorBuilder builder = Validation
- .builderType( HibernateValidatorBuilder.class )
+ HibernateValidatorFactoryBuilder builder = Validation
+ .builderType( HibernateValidatorFactoryBuilder.class )
.providerResolver( resolver )
- .getValidatorBuilder();
+ .getBuilder();
assertDefaultBuilderAndFactory( builder );
}
@@ -192,10 +192,10 @@
};
- ValidatorBuilder<?> builder = Validation
+ ValidatorFactoryBuilder<?> builder = Validation
.defineBootstrapState()
.providerResolver( resolver )
- .getValidatorBuilder();
+ .getBuilder();
assertDefaultBuilderAndFactory( builder );
}
@@ -208,27 +208,27 @@
}
};
- final SpecializedBuilderFactory<HibernateValidatorBuilder> specializedBuilderFactory =
+ final SpecializedBuilderFactory<HibernateValidatorFactoryBuilder> specializedBuilderFactory =
Validation
- .builderType(HibernateValidatorBuilder.class)
+ .builderType( HibernateValidatorFactoryBuilder.class)
.providerResolver( resolver );
try {
- specializedBuilderFactory.getValidatorBuilder();
+ specializedBuilderFactory.getBuilder();
fail();
}
catch ( ValidationException e ) {
assertEquals(
"Wrong error message",
- "Unable to find provider: interface org.hibernate.validation.HibernateValidatorBuilder",
+ "Unable to find provider: interface org.hibernate.validation.HibernateValidatorFactoryBuilder",
e.getMessage()
);
}
}
- private void assertDefaultBuilderAndFactory(ValidatorBuilder builder) {
+ private void assertDefaultBuilderAndFactory(ValidatorFactoryBuilder builder) {
assertNotNull( builder );
- assertTrue( builder instanceof ValidatorBuilderImpl );
+ assertTrue( builder instanceof ValidatorFactoryBuilderImpl );
ValidatorFactory factory = builder.build();
assertNotNull( factory );
Deleted: validator/trunk/validation-api/src/main/java/javax/validation/ReportAsViolationFromComposingConstraint.java
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/ReportAsViolationFromComposingConstraint.java 2008-11-04 00:14:54 UTC (rev 15491)
+++ validator/trunk/validation-api/src/main/java/javax/validation/ReportAsViolationFromComposingConstraint.java 2008-11-04 02:26:44 UTC (rev 15492)
@@ -1,35 +0,0 @@
-// $Id$
-/*
-* JBoss, Home of Professional Open Source
-* Copyright 2008, Red Hat Middleware LLC, and individual contributors
-* by the @authors tag. See the copyright.txt in the distribution for a
-* full listing of individual contributors.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-* http://www.apache.org/licenses/LICENSE-2.0
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-package javax.validation;
-
-import java.lang.annotation.Target;
-import java.lang.annotation.Retention;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
-
-/**
- * A constraint annotation annotated with this annotation
- * will return the composed annotation error report if any of the composing annotations
- * fail. The error reports of each individual composing constraint is ignored.
- *
- * @author Emmanuel Bernard
- */
-@Target({ ANNOTATION_TYPE })
-@Retention(RUNTIME)
-public @interface ReportAsViolationFromComposingConstraint {
-}
Modified: validator/trunk/validation-api/src/main/java/javax/validation/Validation.java
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/Validation.java 2008-11-04 00:14:54 UTC (rev 15491)
+++ validator/trunk/validation-api/src/main/java/javax/validation/Validation.java 2008-11-04 02:26:44 UTC (rev 15492)
@@ -29,7 +29,7 @@
* <li>
* The easiest approach is to use the default Bean Validation provider.
* <pre>
- * ValidatorFactory factory = Validation.getValidatorBuilder().build();
+ * ValidatorFactory factory = Validation.getBuilder().build();
* </pre>
* In this case {@link javax.validation.bootstrap.DefaultValidationProviderResolver DefaultValidationProviderResolver}
* will be used to locate available providers.
@@ -45,10 +45,10 @@
* The second bootstrap approach allows to choose a custom <code>ValidationProviderResolver</code>. The chosen
* <code>ValidationProvider</code> is then determined in the same way as in the default bootstrapping case (see above).
* <pre>
- * ValidatorBuilder<?> builder = Validation
+ * ValidatorFactoryBuilder<?> builder = Validation
* .defineBootstrapState()
* .providerResolver( new MyResolverStrategy() )
- * .getValidatorBuilder();
+ * .getBuilder();
* ValidatorFactory factory = builder.build();
* </pre>
* </li>
@@ -56,14 +56,14 @@
* <p/>
* <li>
* The third approach allows you to specify explicitly and in a type safe fashion the expected provider by
- * using its specific <code>ValidatorBuilder</code> sub-interface.
+ * using its specific <code>ValidatorFactoryBuilder</code> sub-interface.
*
* Optionally you can choose a custom <code>ValidationProviderResolver</code>.
* <pre>
- * ACMEValidatorBuilder builder = Validation
- * .builderType(ACMEValidatorBuilder.class)
+ * ACMEValidatorFactoryBuilder builder = Validation
+ * .builderType(ACMEValidatorFactoryBuilder.class)
* .providerResolver( new MyResolverStrategy() ) // optionally set the provider resolver
- * .getValidatorBuilder();
+ * .getBuilder();
* ValidatorFactory factory = builder.build();
* </pre>
* </li>
@@ -86,61 +86,61 @@
public class Validation {
/**
- * Build a <code>ValidatorBuilder</code>. The actual provider choice is given by the XML configuration. If the
+ * Build a <code>ValidatorFactoryBuilder</code>. The actual provider choice is given by the XML configuration. If the
* XML configuration does not exsist the default is taken.
* <p/>
* The provider list is resolved using the {@link javax.validation.bootstrap.DefaultValidationProviderResolver DefaultValidationProviderResolver}.
*
- * @return <code>ValidatorBuilder</code> instance.
+ * @return <code>ValidatorFactoryBuilder</code> instance.
*/
- public static ValidatorBuilder<?> getValidatorBuilder() {
- return defineBootstrapState().getValidatorBuilder();
+ public static ValidatorFactoryBuilder<?> getBuilder() {
+ return defineBootstrapState().getBuilder();
}
/**
- * Build a <code>ValidatorBuilder</code>. The provider list is resolved using the strategy provided to the bootstrap state.
+ * Build a <code>ValidatorFactoryBuilder</code>. The provider list is resolved using the strategy provided to the bootstrap state.
* <pre>
- * ValidatorBuilder<?> builder = Validation
+ * ValidatorFactoryBuilder<?> builder = Validation
* .defineBootstrapState()
* .providerResolver( new MyResolverStrategy() )
- * .getValidatorBuilder();
+ * .getBuilder();
* ValidatorFactory factory = builder.build();
* </pre>
* The actual provider choice is given by the XML configuration. If the XML configuration does not exsist the first
* available provider will be returned.
*
- * @return instance building a generic <code>ValidatorBuilder</code> compliant with the bootstrap state provided.
+ * @return instance building a generic <code>ValidatorFactoryBuilder</code> compliant with the bootstrap state provided.
*/
public static GenericBuilderFactory defineBootstrapState() {
return new GenericBuilderFactoryImpl();
}
/**
- * Build a <code>ValidatorBuilder</code> for a particular provider implementation.
+ * Build a <code>ValidatorFactoryBuilder</code> for a particular provider implementation.
* Optionally override the provider resolution strategy used to determine the provider.
* <p/>
* Used by applications targeting a specific provider programmatically.
* <p/>
* <pre>
- * ACMEValidatorBuilder builder = Validation.builderType(ACMEValidatorBuilder.class)
+ * ACMEValidatorFactoryBuilder builder = Validation.builderType(ACMEValidatorFactoryBuilder.class)
* .providerResolver( new MyResolverStrategy() )
* .build();
* </pre>,
- * where <code>ACMEValidatorBuilder</code> is the <code>ValidatorBuiler</code> sub interface uniquely identifying
+ * where <code>ACMEValidatorFactoryBuilder</code> is the <code>ValidatorFactoryBuilder</code> sub interface uniquely identifying
* the ACME Bean Validation provider.
*
- * @param builderType the <code>ValidatorBuilder</code> sub interface uniquely defining the targeted provider.
+ * @param builderType the <code>ValidatorFactoryBuilder</code> sub interface uniquely defining the targeted provider.
*
- * @return instance building a provider specific <code>ValidatorBuilder</code> sub interface implementation.
+ * @return instance building a provider specific <code>ValidatorFactoryBuilder</code> sub interface implementation.
*
- * @see #getValidatorBuilder()
+ * @see #getBuilder()
*/
- public static <T extends ValidatorBuilder<T>> SpecializedBuilderFactory<T> builderType(Class<T> builderType) {
+ public static <T extends ValidatorFactoryBuilder<T>> SpecializedBuilderFactory<T> builderType(Class<T> builderType) {
return new SpecializedBuilderFactoryImpl<T>( builderType );
}
//private class, not exposed
- private static class SpecializedBuilderFactoryImpl<T extends ValidatorBuilder<T>>
+ private static class SpecializedBuilderFactoryImpl<T extends ValidatorFactoryBuilder<T>>
implements SpecializedBuilderFactory<T> {
private Class<T> builderType;
@@ -165,14 +165,14 @@
/**
* Determine the provider implementation suitable for builderType and delegate the creation
- * of this specific ValidatorBuilder subclass to the provider.
+ * of this specific ValidatorFactoryBuilder subclass to the provider.
*
- * @return a ValidatorBuilder sub interface implementation
+ * @return a ValidatorFactoryBuilder sub interface implementation
*/
- public T getValidatorBuilder() {
+ public T getBuilder() {
if ( builderType == null ) {
throw new ValidationException(
- "builder is mandatory. Use getValidatorBuilder() to use the generic provider discovery mechanism"
+ "builder is mandatory. Use getBuilder() to use the generic provider discovery mechanism"
);
}
if ( resolver == null ) {
@@ -182,7 +182,7 @@
if ( provider.isSuitable( builderType ) ) {
GenericBuilderFactoryImpl state = new GenericBuilderFactoryImpl();
state.providerResolver( resolver );
- return provider.createSpecializedValidatorBuilder( state, builderType );
+ return provider.createSpecializedValidatorFactoryBuilder( state, builderType );
}
}
throw new ValidationException( "Unable to find provider: " + builderType );
@@ -203,7 +203,7 @@
return resolver;
}
- public ValidatorBuilder<?> getValidatorBuilder() {
+ public ValidatorFactoryBuilder<?> getBuilder() {
ValidationProviderResolver resolver = this.resolver == null ?
new DefaultValidationProviderResolver() :
this.resolver;
@@ -212,7 +212,7 @@
//FIXME looks like an assertion error almost
throw new ValidationException( "Unable to find a default provider" );
}
- return resolver.getValidationProviders().get( 0 ).createGenericValidatorBuilder( this );
+ return resolver.getValidationProviders().get( 0 ).createGenericValidatorFactoryBuilder( this );
}
}
}
Copied: validator/trunk/validation-api/src/main/java/javax/validation/ValidatorFactoryBuilder.java (from rev 15487, validator/trunk/validation-api/src/main/java/javax/validation/ValidatorBuilder.java)
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/ValidatorFactoryBuilder.java (rev 0)
+++ validator/trunk/validation-api/src/main/java/javax/validation/ValidatorFactoryBuilder.java 2008-11-04 02:26:44 UTC (rev 15492)
@@ -0,0 +1,86 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2008, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package javax.validation;
+
+import java.io.InputStream;
+
+/**
+ * Receives configuration information, selects the appropriate
+ * Bean Validation provider and build the appropriate
+ * ValidatorFactory.
+ * <p/>
+ * Usage:
+ * <pre>
+ * ValidatorFactoryBuilder<?> builder = //provided by one of the Validation bootstrap methods
+ * ValidatorFactory = builder
+ * .messageResolver( new CustomMessageResolver() )
+ * .build();
+ * </pre>
+ * <p/>
+ * The ValidationProviderResolver is specified at ValidatorFactoryBuilder time (see {@link javax.validation.spi.ValidationProvider}).
+ * If none is explicitely requested, the default ValidationProviderResolver is used.
+ * <p/>
+ * The provider is selected in the following way:
+ * - if a specific ValidatorFactoryBuilder subclass is requested programmatically using Validation.builderType(),
+ * find the first provider matching it
+ * - if a specific ValidatorFactoryBuilder subclass is defined in META-INF/validation.xml,
+ * find the first provider matching it
+ * - otherwise, use the first provider returned by the ValidationProviderResolver
+ * <p/>
+ * Implementations are not meant to be thread safe
+ *
+ * @author Emmanuel Bernard
+ */
+public interface ValidatorFactoryBuilder<T extends ValidatorFactoryBuilder> {
+ /**
+ * Defines the message resolver used. Has priority over the configuration based message resolver.
+ *
+ * @param resolver message resolver implementation.
+ *
+ * @return <code>this</code> following the chaining method pattern.
+ */
+ T messageResolver(MessageResolver resolver);
+
+ /**
+ * Defines the constraint factory. Has priority over the configuration based constraint factory.
+ *
+ * @param constraintFactory constraint factory inmplementation.
+ *
+ * @return <code>this</code> following the chaining method pattern.
+ */
+ T constraintFactory(ConstraintFactory constraintFactory);
+
+ /**
+ * Configure the ValidatorFactory based on <code>stream</code>
+ * If not specified, META-INF/validation.xml is used
+ * <p/>
+ * The stream should be closed by the client API after the ValidatorFactory has been returned
+ *
+ * @param stream configuration stream.
+ *
+ * @return <code>this</code> following the chaining method pattern.
+ */
+ T configure(InputStream stream);
+
+ /**
+ * Build a ValidatorFactory implementation.
+ *
+ * @return ValidatorFactory
+ */
+ ValidatorFactory build();
+}
Property changes on: validator/trunk/validation-api/src/main/java/javax/validation/ValidatorFactoryBuilder.java
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:keywords
+ Id
Modified: validator/trunk/validation-api/src/main/java/javax/validation/bootstrap/GenericBuilderFactory.java
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/bootstrap/GenericBuilderFactory.java 2008-11-04 00:14:54 UTC (rev 15491)
+++ validator/trunk/validation-api/src/main/java/javax/validation/bootstrap/GenericBuilderFactory.java 2008-11-04 02:26:44 UTC (rev 15492)
@@ -1,11 +1,11 @@
package javax.validation.bootstrap;
import javax.validation.ValidationProviderResolver;
-import javax.validation.ValidatorBuilder;
+import javax.validation.ValidatorFactoryBuilder;
/**
* Defines the state used to bootstrap Bean Validation and create an appropriate
- * ValidatorBuilder
+ * ValidatorFactoryBuilder
*
* @author Emmanuel Bernard
*/
@@ -23,13 +23,13 @@
GenericBuilderFactory providerResolver(ValidationProviderResolver resolver);
/**
- * Returns a generic ValidatorBuilder implementation.
+ * Returns a generic ValidatorFactoryBuilder implementation.
* At this stage the provider used to build the ValidationFactory is not defined.
* <p/>
- * The ValidatorBuilder implementation is provided by the first provider returned
+ * The ValidatorFactoryBuilder implementation is provided by the first provider returned
* by the ValidationProviderResolver strategy.
*
- * @return a ValidatorBuilder implementation compliant with the bootstrap state
+ * @return a ValidatorFactoryBuilder implementation compliant with the bootstrap state
*/
- ValidatorBuilder<?> getValidatorBuilder();
+ ValidatorFactoryBuilder<?> getBuilder();
}
Modified: validator/trunk/validation-api/src/main/java/javax/validation/bootstrap/SpecializedBuilderFactory.java
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/bootstrap/SpecializedBuilderFactory.java 2008-11-04 00:14:54 UTC (rev 15491)
+++ validator/trunk/validation-api/src/main/java/javax/validation/bootstrap/SpecializedBuilderFactory.java 2008-11-04 02:26:44 UTC (rev 15492)
@@ -1,10 +1,10 @@
package javax.validation.bootstrap;
import javax.validation.ValidationProviderResolver;
-import javax.validation.ValidatorBuilder;
+import javax.validation.ValidatorFactoryBuilder;
/**
- * Build implementations of builderType, the specific ValidationBuilder sub interface uniquely identifying
+ * Build implementations of builderType, the specific ValidatorFactoryBuilder sub interface uniquely identifying
* a provider.
* <p/>
* The requested provider is the first provider suitable for T (as defined in
@@ -14,7 +14,7 @@
*
* @author Emmanuel Bernard
*/
-public interface SpecializedBuilderFactory<T extends ValidatorBuilder<T>> {
+public interface SpecializedBuilderFactory<T extends ValidatorFactoryBuilder<T>> {
/**
* Optionally define the provider resolver implementation used.
@@ -28,9 +28,9 @@
/**
* Determine the provider implementation suitable for builderType and delegate the creation
- * of this specific ValidatorBuilder subclass to the provider.
+ * of this specific ValidatorFactoryBuilder subclass to the provider.
*
- * @return a ValidatorBuilder sub interface implementation
+ * @return a ValidatorFactoryBuilder sub interface implementation
*/
- public T getValidatorBuilder();
+ public T getBuilder();
}
Modified: validator/trunk/validation-api/src/main/java/javax/validation/spi/ValidationProvider.java
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/spi/ValidationProvider.java 2008-11-04 00:14:54 UTC (rev 15491)
+++ validator/trunk/validation-api/src/main/java/javax/validation/spi/ValidationProvider.java 2008-11-04 02:26:44 UTC (rev 15492)
@@ -17,7 +17,7 @@
*/
package javax.validation.spi;
-import javax.validation.ValidatorBuilder;
+import javax.validation.ValidatorFactoryBuilder;
import javax.validation.ValidatorFactory;
/**
@@ -33,14 +33,14 @@
/**
* @param builderClass targeted builder class.
*
- * @return <code>true</code> if <code>builderClass</code> is the Bean Validation Provider sub interface for ValidatorBuilder
+ * @return <code>true</code> if <code>builderClass</code> is the Bean Validation Provider sub interface for ValidatorFactoryBuilder
* This sub interface uniquely identify a provider.
*/
- boolean isSuitable(Class<? extends ValidatorBuilder<?>> builderClass);
+ boolean isSuitable(Class<? extends ValidatorFactoryBuilder<?>> builderClass);
/**
- * Returns a ValidatorBuilder instance implementing the <code>builderType</code> interface.
- * The ValidatorBuilder instance uses the current provider (<code>this</code>) to build
+ * Returns a ValidatorFactoryBuilder instance implementing the <code>builderType</code> interface.
+ * The ValidatorFactoryBuilder instance uses the current provider (<code>this</code>) to build
* the ValidatorFactory instance.
* <p/>
* This method can only be called on providers returning true on <code>#issuitable(builderType)</code>
@@ -50,12 +50,12 @@
*
* @return specific validator builder implementation
*/
- <T extends ValidatorBuilder<T>> T createSpecializedValidatorBuilder(BootstrapState state, Class<T> builderClass);
+ <T extends ValidatorFactoryBuilder<T>> T createSpecializedValidatorFactoryBuilder(BootstrapState state, Class<T> builderClass);
/**
- * Returns a ValidatorBuilder instance. This instance is not bound to
+ * Returns a ValidatorFactoryBuilder instance. This instance is not bound to
* use the current provider. The choice of provider follows the algorithm described
- * in {@link javax.validation.ValidatorBuilder}
+ * in {@link javax.validation.ValidatorFactoryBuilder}
* <p/>
* The ValidationProviderResolver used is provided by <code>state</code>.
* If null, the default ValidationProviderResolver is used.
@@ -64,7 +64,7 @@
*
* @return validator builder implementation
*/
- ValidatorBuilder<?> createGenericValidatorBuilder(BootstrapState state);
+ ValidatorFactoryBuilder<?> createGenericValidatorFactoryBuilder(BootstrapState state);
/**
* Build a ValidatorFactory using the current provider implementation. The ValidationFactory
16 years, 2 months
Hibernate SVN: r15491 - in validator/trunk: validation-api/src/main/java/javax/validation and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2008-11-03 19:14:54 -0500 (Mon, 03 Nov 2008)
New Revision: 15491
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java
validator/trunk/validation-api/src/main/java/javax/validation/Validator.java
Log:
BVAL-64 rename getValidatedProperties to getPropertiesWithConstraints
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java 2008-11-03 23:49:23 UTC (rev 15490)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ValidatorImpl.java 2008-11-04 00:14:54 UTC (rev 15491)
@@ -514,7 +514,7 @@
return metaDataProvider.getPropertyDescriptors().get( propertyName );
}
- public Set<String> getValidatedProperties() {
+ public Set<String> getPropertiesWithConstraints() {
return Collections.unmodifiableSet( metaDataProvider.getPropertyDescriptors()
.keySet() );
}
Modified: validator/trunk/validation-api/src/main/java/javax/validation/Validator.java
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/Validator.java 2008-11-03 23:49:23 UTC (rev 15490)
+++ validator/trunk/validation-api/src/main/java/javax/validation/Validator.java 2008-11-04 00:14:54 UTC (rev 15491)
@@ -87,6 +87,6 @@
/**
* return the property names having at least a constraint defined
*/
- Set<String> getValidatedProperties();
+ Set<String> getPropertiesWithConstraints();
}
16 years, 2 months
Hibernate SVN: r15490 - in validator/trunk: hibernate-validator/src/test/java/org/hibernate/validation/engine and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2008-11-03 18:49:23 -0500 (Mon, 03 Nov 2008)
New Revision: 15490
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ConstraintViolationImpl.java
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/ValidatorImplTest.java
validator/trunk/validation-api/src/main/java/javax/validation/ConstraintViolation.java
validator/trunk/validation-api/src/main/java/javax/validation/Validator.java
Log:
BVAL-61 rename getValue to getInvalidValue
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ConstraintViolationImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ConstraintViolationImpl.java 2008-11-03 22:32:21 UTC (rev 15489)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ConstraintViolationImpl.java 2008-11-03 23:49:23 UTC (rev 15490)
@@ -74,7 +74,7 @@
/**
* {@inheritDoc}
*/
- public Object getValue() {
+ public Object getInvalidValue() {
return value;
}
Modified: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/ValidatorImplTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/ValidatorImplTest.java 2008-11-03 22:32:21 UTC (rev 15489)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/ValidatorImplTest.java 2008-11-03 23:49:23 UTC (rev 15490)
@@ -120,7 +120,7 @@
assertEquals( "Wrong message", "may not be empty", constraintViolation.getMessage() );
assertEquals( "Wrong bean class", Book.class, constraintViolation.getBeanClass() );
assertEquals( "Wrong root entity", book, constraintViolation.getRootBean() );
- assertEquals( "Wrong value", book.getTitle(), constraintViolation.getValue() );
+ assertEquals( "Wrong value", book.getTitle(), constraintViolation.getInvalidValue() );
assertEquals( "Wrong propertyName", "title", constraintViolation.getPropertyPath() );
book.setTitle( "Hibernate Persistence with JPA" );
@@ -132,7 +132,7 @@
assertEquals( "Wrong message", "length must be between 0 and 30", constraintViolation.getMessage() );
assertEquals( "Wrong bean class", Book.class, constraintViolation.getBeanClass() );
assertEquals( "Wrong root entity", book, constraintViolation.getRootBean() );
- assertEquals( "Wrong value", book.getSubtitle(), constraintViolation.getValue() );
+ assertEquals( "Wrong value", book.getSubtitle(), constraintViolation.getInvalidValue() );
assertEquals( "Wrong propertyName", "subtitle", constraintViolation.getPropertyPath() );
book.setSubtitle( "Revised Edition" );
@@ -144,7 +144,7 @@
assertEquals( "Wrong message", "length must be between 0 and 20", constraintViolation.getMessage() );
assertEquals( "Wrong bean class", Author.class, constraintViolation.getBeanClass() );
assertEquals( "Wrong root entity", book, constraintViolation.getRootBean() );
- assertEquals( "Wrong value", author.getCompany(), constraintViolation.getValue() );
+ assertEquals( "Wrong value", author.getCompany(), constraintViolation.getInvalidValue() );
assertEquals( "Wrong propertyName", "author.company", constraintViolation.getPropertyPath() );
author.setCompany( "JBoss" );
@@ -175,7 +175,7 @@
assertEquals( "Wrong message", "may not be null", constraintViolation.getMessage() );
assertEquals( "Wrong bean class", Book.class, constraintViolation.getBeanClass() );
assertEquals( "Wrong root entity", book, constraintViolation.getRootBean() );
- assertEquals( "Wrong value", book.getTitle(), constraintViolation.getValue() );
+ assertEquals( "Wrong value", book.getTitle(), constraintViolation.getInvalidValue() );
assertEquals( "Wrong propertyName", "title", constraintViolation.getPropertyPath() );
book.setTitle( "Hibernate Persistence with JPA" );
@@ -316,7 +316,7 @@
assertEquals( "Wrong message", "may not be null", constraintViolation.getMessage() );
assertEquals( "Wrong bean class", Order.class, constraintViolation.getBeanClass() );
assertEquals( "Wrong root entity", customer, constraintViolation.getRootBean() );
- assertEquals( "Wrong value", order1.getOrderNumber(), constraintViolation.getValue() );
+ assertEquals( "Wrong value", order1.getOrderNumber(), constraintViolation.getInvalidValue() );
assertEquals( "Wrong propertyName", "orderList[0].orderNumber", constraintViolation.getPropertyPath() );
}
@@ -366,7 +366,7 @@
assertEquals( "Wrong message", "may not be empty", constraintViolation.getMessage() );
assertEquals( "Wrong bean class", Actor.class, constraintViolation.getBeanClass() );
assertEquals( "Wrong root entity", clint, constraintViolation.getRootBean() );
- assertEquals( "Wrong value", morgan.getLastName(), constraintViolation.getValue() );
+ assertEquals( "Wrong value", morgan.getLastName(), constraintViolation.getInvalidValue() );
assertEquals( "Wrong propertyName", "playedWith[0].playedWith[1].lastName", constraintViolation.getPropertyPath() );
}
@@ -386,7 +386,7 @@
assertEquals( "Wrong message", "may not be null", constraintViolation.getMessage() );
assertEquals( "Wrong bean class", null, constraintViolation.getBeanClass() );
assertEquals( "Wrong root entity", null, constraintViolation.getRootBean() );
- assertEquals( "Wrong value", order.getOrderNumber(), constraintViolation.getValue() );
+ assertEquals( "Wrong value", order.getOrderNumber(), constraintViolation.getInvalidValue() );
assertEquals( "Wrong propertyName", "orderList[0].orderNumber", constraintViolation.getPropertyPath() );
constraintViolations = validator.validateValue( "orderList[0].orderNumber", "1234" );
Modified: validator/trunk/validation-api/src/main/java/javax/validation/ConstraintViolation.java
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/ConstraintViolation.java 2008-11-03 22:32:21 UTC (rev 15489)
+++ validator/trunk/validation-api/src/main/java/javax/validation/ConstraintViolation.java 2008-11-03 23:49:23 UTC (rev 15490)
@@ -62,7 +62,7 @@
/**
* @return the value failing to pass the constraint.
*/
- Object getValue();
+ Object getInvalidValue();
/**
* @return the list of groups that the triggered constraint applies on and which also are
Modified: validator/trunk/validation-api/src/main/java/javax/validation/Validator.java
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/Validator.java 2008-11-03 22:32:21 UTC (rev 15489)
+++ validator/trunk/validation-api/src/main/java/javax/validation/Validator.java 2008-11-03 23:49:23 UTC (rev 15490)
@@ -32,7 +32,7 @@
* validate all constraints on object
*
* @param object object to validate
- * @param groups group name(s) targeted for validation (default to <code>default</code>)
+ * @param groups group name(s) (including group sequence names) targeted for validation (default to <code>default</code>)
*
* @return constraint violations or an empty Set if none
*
@@ -44,8 +44,8 @@
* validate all constraints on <code>propertyName</code> property of object
*
* @param object object to validate
- * @param propertyName property to validate
- * @param groups group name(s) targeted for validation (default to <code>default</code>)
+ * @param propertyName property to validate (ie field and getter constraints)
+ * @param groups group name(s) (including group sequence names) targeted for validation (default to <code>default</code>)
*
* @return constraint violations or an empty Set if none
*
@@ -61,7 +61,7 @@
*
* @param propertyName property to validate
* @param value property value to validate
- * @param groups group name(s) targeted for validation (default to <code>default</code>)
+ * @param groups group name(s) (including group sequence names) targeted for validation (default to <code>default</code>)
*
* @return constraint violations or an empty Set if none
*/
16 years, 2 months
Hibernate SVN: r15489 - in validator/trunk: validation-api/src/main/java/javax/validation and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2008-11-03 17:32:21 -0500 (Mon, 03 Nov 2008)
New Revision: 15489
Added:
validator/trunk/validation-api/src/main/java/javax/validation/ReportAsViolationFromCompositeConstraint.java
Removed:
validator/trunk/validation-api/src/main/java/javax/validation/Context.java
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ConstraintDescriptorImpl.java
validator/trunk/validation-api/src/main/java/javax/validation/ConstraintDescriptor.java
Log:
Rename @ReportAsViolationFromComposingConstraint to @ReportAsViolationFromCompositeConstraint
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ConstraintDescriptorImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ConstraintDescriptorImpl.java 2008-11-03 21:35:45 UTC (rev 15488)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/impl/ConstraintDescriptorImpl.java 2008-11-03 22:32:21 UTC (rev 15489)
@@ -28,7 +28,7 @@
import java.util.Set;
import javax.validation.Constraint;
import javax.validation.ConstraintDescriptor;
-import javax.validation.ReportAsViolationFromComposingConstraint;
+import javax.validation.ReportAsViolationFromCompositeConstraint;
import javax.validation.ValidationException;
/**
@@ -55,7 +55,7 @@
this.constraintImplementation = validator;
this.parameters = getAnnotationParameters( annotation );
this.isReportAsSingleInvalidConstraint = annotation.annotationType().isAnnotationPresent(
- ReportAsViolationFromComposingConstraint.class
+ ReportAsViolationFromCompositeConstraint.class
);
this.constraintClass = constraintClass;
}
@@ -114,7 +114,7 @@
/**
* {@inheritDoc}
*/
- public boolean ReportAsViolationFromComposingConstraint() {
+ public boolean isReportAsViolationFromCompositeConstraint() {
return isReportAsSingleInvalidConstraint;
}
Modified: validator/trunk/validation-api/src/main/java/javax/validation/ConstraintDescriptor.java
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/ConstraintDescriptor.java 2008-11-03 21:35:45 UTC (rev 15488)
+++ validator/trunk/validation-api/src/main/java/javax/validation/ConstraintDescriptor.java 2008-11-03 22:32:21 UTC (rev 15489)
@@ -68,7 +68,7 @@
Set<ConstraintDescriptor> getComposingConstraints();
/**
- * @return true if the constraint is annotated with @ReportAsSingleInvalidConstraint
+ * @return true if the constraint is annotated with @ReportAsViolationFromCompositeConstraint
*/
- boolean ReportAsViolationFromComposingConstraint();
+ boolean isReportAsViolationFromCompositeConstraint();
}
Deleted: validator/trunk/validation-api/src/main/java/javax/validation/Context.java
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/Context.java 2008-11-03 21:35:45 UTC (rev 15488)
+++ validator/trunk/validation-api/src/main/java/javax/validation/Context.java 2008-11-03 22:32:21 UTC (rev 15489)
@@ -1,55 +0,0 @@
-package javax.validation;
-
-/**
- * Provide contextual data and operation when applying a given constraint implementation
- *
- * @author Emmanuel Bernard
- */
-public interface Context {
- /**
- * Disable default error message and default ConstraintViolation object generation.
- * Useful to set a different error message or generate an ConstraintViolation based on
- * a different property
- *
- * @see #addError(String)
- * @see #addError(String, String)
- */
- void disableDefaultError();
-
- /**
- * return the current unexpanded default message
- * TODO: is it needed
- */
- String getDefaultErrorMessage();
-
- /**
- * Add a new unexpanded error message.
- * <p/>
- * If isValid returns false, a ConstraintViolation object will be built per error message
- * including the default one unless #disableDefaultErrorMEssage() has been called.
- * <p/>
- * Aside from the error message, ConstraintViolation objects generated from such a call
- * contains the same contextual information (root bean, path and so on)
- * <p/>
- * This method can be called multiple time. One ConstraintViolation instance per call is created.
- *
- * @param message new unexpanded error message
- */
- void addError(String message);
-
- /**
- * Add a new unexpanded error message to a given sub property.
- * <p/>
- * If isValid returns false, a ConstraintViolation object will be built per error message including the default one
- * if null apply to the current property or the bean the constraint is applied on, otherwise apply to the <code>property</code> named
- * <p/>
- * TODO exception or swallowed when bean-level instance is not present?
- *
- * @param message new unexpanded error message
- * @param property property name the ConstraintViolation is targeting
- *
- * @throws ValidationException when the property is not present on the bean level object
- */
- void addError(String message, String property);
-
-}
Copied: validator/trunk/validation-api/src/main/java/javax/validation/ReportAsViolationFromCompositeConstraint.java (from rev 15487, validator/trunk/validation-api/src/main/java/javax/validation/ReportAsViolationFromComposingConstraint.java)
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/ReportAsViolationFromCompositeConstraint.java (rev 0)
+++ validator/trunk/validation-api/src/main/java/javax/validation/ReportAsViolationFromCompositeConstraint.java 2008-11-03 22:32:21 UTC (rev 15489)
@@ -0,0 +1,35 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2008, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package javax.validation;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+
+/**
+ * A constraint annotation annotated with this annotation
+ * will return the composed annotation error report if any of the composing annotations
+ * fail. The error reports of each individual composing constraint is ignored.
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({ ANNOTATION_TYPE })
+@Retention(RUNTIME)
+public @interface ReportAsViolationFromCompositeConstraint {
+}
Property changes on: validator/trunk/validation-api/src/main/java/javax/validation/ReportAsViolationFromCompositeConstraint.java
___________________________________________________________________
Name: svn:keywords
+ Id
16 years, 2 months
Hibernate SVN: r15488 - validator/trunk/validation-api/src/main/java/javax/validation.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2008-11-03 16:35:45 -0500 (Mon, 03 Nov 2008)
New Revision: 15488
Modified:
validator/trunk/validation-api/src/main/java/javax/validation/Constraint.java
Log:
BVAL-53 rename Context into ConstraintContext
Modified: validator/trunk/validation-api/src/main/java/javax/validation/Constraint.java
===================================================================
--- validator/trunk/validation-api/src/main/java/javax/validation/Constraint.java 2008-11-03 21:28:09 UTC (rev 15487)
+++ validator/trunk/validation-api/src/main/java/javax/validation/Constraint.java 2008-11-03 21:35:45 UTC (rev 15488)
@@ -40,10 +40,10 @@
* Implement the validation constraint
*
* @param object object to validate
- * @param validationContext context in which the constraint implementation is evaluated
+ * @param constraintContext context in which the constraint implementation is evaluated
*
* @return true if object pass the constraint
*/
- boolean isValid(Object object, ConstraintContext validationContext);
+ boolean isValid(Object object, ConstraintContext constraintContext);
}
\ No newline at end of file
16 years, 2 months