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&