[hibernate-commits] Hibernate SVN: r19713 - core/trunk/documentation/manual/src/main/docbook/en-US/content.
hibernate-commits at lists.jboss.org
hibernate-commits at lists.jboss.org
Thu Jun 10 12:22:35 EDT 2010
Author: epbernard
Date: 2010-06-10 12:22:34 -0400 (Thu, 10 Jun 2010)
New Revision: 19713
Modified:
core/trunk/documentation/manual/src/main/docbook/en-US/content/basic_mapping.xml
Log:
HHH-5149 Reorganise sections of basic O/R mappings
Modified: core/trunk/documentation/manual/src/main/docbook/en-US/content/basic_mapping.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/basic_mapping.xml 2010-06-10 16:21:56 UTC (rev 19712)
+++ core/trunk/documentation/manual/src/main/docbook/en-US/content/basic_mapping.xml 2010-06-10 16:22:34 UTC (rev 19713)
@@ -210,345 +210,6 @@
affect the database schemas exported by the schema export tool (for
example, the <literal> not-null</literal> attribute).</para>
- <section>
- <title>Some hbm.xml specificities</title>
-
- <para>The hbm.xml structure has some specificities naturally not present
- when using annotations, let's describe them briefly.</para>
-
- <section id="mapping-declaration-doctype" revision="3">
- <title>Doctype</title>
-
- <para>All XML mappings should declare the doctype shown. The actual
- DTD can 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 the DTD declaration against the contents
- of your classpath.</para>
-
- <section id="mapping-declaration-entity-resolution">
- <title>EntityResolver</title>
-
- <para>Hibernate will first attempt to resolve DTDs in its classpath.
- 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 encounters a systemId starting with
- <literal>http://hibernate.sourceforge.net/</literal>. The
- resolver attempts to resolve these entities via the classloader
- which loaded the Hibernate classes.</para>
- </listitem>
-
- <listitem>
- <para>a <literal>user namespace</literal> is recognized whenever
- the resolver encounters 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>The following is an example of utilizing user
- namespacing:</para>
-
- <programlisting language="XML" role="XML">
-<xi:include href="../extras/namespacing.xml_sample" parse="text"
- xmlns:xi="http://www.w3.org/2001/XInclude" />
-</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>
- </section>
- </section>
-
- <section 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 they are specified, tablenames will be
- qualified by the given schema and catalog names. If they are missing,
- tablenames will be unqualified. The <literal>default-cascade</literal>
- attribute specifies what cascade style should be assumed for
- properties and collections that do not specify a
- <literal>cascade</literal> attribute. By default, the
- <literal>auto-import</literal> attribute allows you to use unqualified
- class names in the query language.</para>
-
- <programlistingco role="XML">
- <areaspec>
- <area coords="2" id="hm1" />
-
- <area coords="3" id="hm2" />
-
- <area coords="4" id="hm3" />
-
- <area coords="5" id="hm4" />
-
- <area coords="6" id="hm5" />
-
- <area coords="7" id="hm6" />
-
- <area coords="8" id="hm7" />
- </areaspec>
-
- <programlisting><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. It 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 unspecified
- <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 use 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>. An
- exception will result if you attempt to assign two classes to the same
- "imported" name.</para>
-
- <para>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. For example, <literal>Cat.hbm.xml</literal>,
- <literal>Dog.hbm.xml</literal>, or if using inheritance,
- <literal>Animal.hbm.xml</literal>.</para>
- </section>
-
- <section id="mapping-declaration-key">
- <title>Key</title>
-
- <para>The <literal><key></literal> element is featured a few
- times within this guide. It appears anywhere the parent mapping
- element defines a join to a new table that references the primary key
- of the original table. It also defines the foreign key in the joined
- table:</para>
-
- <programlistingco role="XML">
- <areaspec>
- <area coords="2" id="key1" />
-
- <area coords="3" id="key2" />
-
- <area coords="4" id="key3" />
-
- <area coords="5" id="key4" />
-
- <area coords="6" id="key5" />
-
- <area coords="7" id="key6" />
- </areaspec>
-
- <programlisting><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 can 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 original table. It is 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>For systems where delete performance is important, we recommend
- that all keys should be defined
- <literal>on-delete="cascade"</literal>. Hibernate uses 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 association to a
- non-nullable foreign key, you <emphasis>must</emphasis> declare the
- key column using <literal><key
- not-null="true"></literal>.</para>
- </section>
-
- <section id="mapping-declaration-import">
- <title>Import</title>
-
- <para>If your application has two persistent classes with the same
- name, and you do not want to specify the fully qualified package name
- in Hibernate queries, classes can be "imported" explicitly, rather
- than relying upon <literal>auto-import="true"</literal>. You can also
- import classes and interfaces that are not explicitly mapped:</para>
-
- <programlisting role="XML"><import class="java.lang.Object" rename="Universe"/></programlisting>
-
- <programlistingco role="XML">
- <areaspec>
- <area coords="2" id="import1" />
-
- <area coords="3" id="import2" />
- </areaspec>
-
- <programlisting><import
- class="ClassName"
- rename="ShortName"
-/></programlisting>
-
- <calloutlist>
- <callout arearefs="import1">
- <para><literal>class</literal>: the fully qualified class name
- of any Java class.</para>
- </callout>
-
- <callout arearefs="import2">
- <para><literal>rename</literal> (optional - defaults to the
- unqualified class name): a name that can be used in the query
- language.</para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <note>
- <para>This feature is unique to hbm.xml and is not supported in
- annotations.</para>
- </note>
- </section>
-
- <section id="mapping-column" revision="5">
- <title>Column and formula elements</title>
-
- <para>Mapping elements which accept 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. For example:</para>
-
- <programlisting role="XML"><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"
- read="SQL expression"
- write="SQL expression"/></programlisting>
-
- <programlisting role="XML"><formula>SQL expression</formula></programlisting>
-
- <para>Most of the attributes on <literal>column</literal> provide a
- means of tailoring the DDL during automatic schema generation. The
- <literal>read</literal> and <literal>write</literal> attributes allow
- you to specify custom SQL that Hibernate will use to access the
- column's value. For more on this, see the discussion of <link
- linkend="mapping-column-read-and-write">column read and write
- expressions</link>.</para>
-
- <para>The <literal>column</literal> and <literal>formula</literal>
- elements can even be combined within the same property or association
- mapping to express, for example, exotic join conditions.</para>
-
- <programlisting role="XML"><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>
- </section>
- </section>
-
<section id="mapping-declaration-class" revision="3">
<title>Entity</title>
@@ -2400,803 +2061,6 @@
</section>
<section>
- <title>Inheritance strategy</title>
-
- <para>Java is a language supporting polymorphism: a class can inherit
- from another. Several strategies are possible to persist a class
- hierarchy:</para>
-
- <itemizedlist>
- <listitem>
- <para>Single table per class hierarchy strategy: a single table
- hosts all the instances of a class hierarchy</para>
- </listitem>
-
- <listitem>
- <para>Joined subclass strategy: one table per class and subclass is
- present and each table persist the properties specific to a given
- subclass. The state of the entity is then stored in its
- corresponding class table and all its superclasses</para>
- </listitem>
-
- <listitem>
- <para>Table per class strategy: one table per concrete class and
- subclass is present and each table persist the properties of the
- class and its superclasses. The state of the entity is then stored
- entirely in the dedicated table for its class.</para>
- </listitem>
- </itemizedlist>
-
- <section id="mapping-declaration-subclass" revision="4">
- <title>Single table per class hierarchy strategy</title>
-
- <para>With this approach the properties of all the subclasses in a
- given mapped class hierarchy are stored in a single table.</para>
-
- <para>Each subclass declares its own persistent properties and
- subclasses. Version and id properties are assumed to be inherited from
- the root class. Each subclass in a hierarchy must define a unique
- discriminator value. If this is not specified, the fully qualified
- Java class name is used.</para>
-
- <programlisting language="JAVA" role="JAVA">@Entity
- at Inheritance(strategy=InheritanceType.SINGLE_TABLE)
- at DiscriminatorColumn(
- name="planetype",
- discriminatorType=DiscriminatorType.STRING
-)
- at DiscriminatorValue("Plane")
-public class Plane { ... }
-
- at Entity
- at DiscriminatorValue("A320")
-public class A320 extends Plane { ... } </programlisting>
-
- <para>In hbm.xml, for the table-per-class-hierarchy mapping strategy,
- the <literal><subclass></literal> declaration is used. For
- example:</para>
-
- <programlistingco role="XML">
- <areaspec>
- <area coords="2" id="subclass1" />
-
- <area coords="3" id="subclass2" />
-
- <area coords="4" id="subclass3" />
-
- <area coords="5" id="subclass4" />
- </areaspec>
-
- <programlisting><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 distinguishes
- individual subclasses.</para>
- </callout>
-
- <callout arearefs="subclass3">
- <para><literal>proxy</literal> (optional): specifies a class or
- interface used 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>For information about inheritance mappings see <xref
- linkend="inheritance" />.</para>
-
- <section id="mapping-declaration-discriminator" revision="3">
- <title>Discriminator</title>
-
- <para>Discriminators are required for polymorphic persistence using
- the table-per-class-hierarchy mapping strategy. It 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 can 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>
-
- <para>Use the <classname>@DiscriminatorColumn</classname> to define
- the discriminator column as well as the discriminator type.
- Alternatively, you can also use
- <classname>@DiscriminatorFormula</classname> to express in SQL what
- would be in a virtual discriminator column. This is particularly
- handy when the discriminator value can be extracted from one or more
- columns of the table. Both
- <classname>@DiscriminatorColumn</classname> and
- <classname>@DiscriminatorFormula</classname> are to be set on the
- root entity (once per persisted hierarchy).</para>
-
- <para>Finally, use <classname>@DiscriminatorValue</classname> on
- each class of the hierarchy to specify the value stored in the
- discriminator column for a given entity. If you do not set
- <classname>@DiscriminatorValue</classname> on a class, the fully
- qualified class name is used.</para>
-
- <programlisting language="JAVA" role="JAVA">@Entity
- at Inheritance(strategy=InheritanceType.SINGLE_TABLE)
- at DiscriminatorColumn(
- name="planetype",
- discriminatorType=DiscriminatorType.STRING
-)
- at DiscriminatorValue("Plane")
-public class Plane { ... }
-
- at Entity
- at DiscriminatorValue("A320")
-public class A320 extends Plane { ... } </programlisting>
-
- <para>In hbm.xml, the <literal><discriminator></literal>
- element is used to define the discriminator column or
- formula:</para>
-
- <programlistingco role="XML">
- <areaspec>
- <area coords="2" id="discriminator1" />
-
- <area coords="3" id="discriminator2" />
-
- <area coords="4" id="discriminator3" />
-
- <area coords="5" id="discriminator4" />
-
- <area coords="6" id="discriminator5" />
- </areaspec>
-
- <programlisting><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>): "forces" Hibernate to specify the
- 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. It tells Hibernate not to include the
- column in SQL <literal>INSERTs</literal>.</para>
- </callout>
-
- <callout arearefs="discriminator5">
- <para><literal>formula</literal> (optional): an arbitrary SQL
- expression that is executed when a type has to be evaluated.
- It 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>The <literal>formula</literal> attribute allows you to declare
- an arbitrary SQL expression that will be used to evaluate the type
- of a row. For example:</para>
-
- <programlisting role="XML"><discriminator
- formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
- type="integer"/></programlisting>
- </section>
- </section>
-
- <section id="mapping-declaration-joinedsubclass" revision="3">
- <title>Joined subclass strategy</title>
-
- <para>Each subclass can also be mapped to its own table. This is
- called the table-per-subclass mapping strategy. An inherited state is
- retrieved by joining with the table of the superclass. A discriminator
- column is not required for this mapping strategy. Each subclass must,
- however, declare a table column holding the object identifier. The
- primary key of this table is also a foreign key to the superclass
- table and described by the
- <classname>@PrimaryKeyJoinColumn</classname>s or the
- <literal><key></literal> element.</para>
-
- <programlisting language="JAVA" role="JAVA">@Entity @Table(name="CATS")
- at Inheritance(strategy=InheritanceType.JOINED)
-public class Cat implements Serializable {
- @Id @GeneratedValue(generator="cat-uuid")
- @GenericGenerator(name="cat-uuid", strategy="uuid")
- String getId() { return id; }
-
- ...
-}
-
- at Entity @Table(name="DOMESTIC_CATS")
- at PrimaryKeyJoinColumn(name="CAT")
-public class DomesticCat extends Cat {
- public String getName() { return name; }
-} </programlisting>
-
- <note>
- <para>The table name still defaults to the non qualified class name.
- Also if <classname>@PrimaryKeyJoinColumn</classname> is not set, the
- primary key / foreign key columns are assumed to have the same names
- as the primary key columns of the primary table of the
- superclass.</para>
- </note>
-
- <para>In hbm.xml, use the <literal><joined-subclass></literal>
- element. For example:</para>
-
- <programlistingco role="XML">
- <areaspec>
- <area coords="2" id="joinedsubclass1" />
-
- <area coords="3" id="joinedsubclass2" />
-
- <area coords="4" id="joinedsubclass3" />
-
- <area coords="5" id="joinedsubclass4" />
- </areaspec>
-
- <programlisting><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>Use the <literal><key></literal> element to declare the
- primary key / foreign key column. The mapping at the start of the
- chapter would then be re-written as:</para>
-
- <programlisting role="XML"><?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>
- </section>
-
- <section id="mapping-declaration-unionsubclass" revision="2">
- <title>Table per class strategy</title>
-
- <para>A third option is to map only the concrete classes of an
- inheritance hierarchy to tables. This is called the
- table-per-concrete-class strategy. Each table defines all persistent
- states of the class, including the inherited state. In Hibernate, it
- is not necessary to explicitly map such inheritance hierarchies. You
- can map each class as a separate entity root. However, if you wish use
- polymorphic associations (e.g. an association to the superclass of
- your hierarchy), you need to use the union subclass mapping.</para>
-
- <programlisting language="JAVA" role="JAVA">@Entity
- at Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
-public class Flight implements Serializable { ... } </programlisting>
-
- <para>Or in hbm.xml:</para>
-
- <programlistingco role="XML">
- <areaspec>
- <area coords="2" id="unionsubclass1" />
-
- <area coords="3" id="unionsubclass2" />
-
- <area coords="4" id="unionsubclass3" />
-
- <area coords="5" id="unionsubclass4" />
- </areaspec>
-
- <programlisting><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>
- </section>
-
- <section>
- <title>Inherit properties from superclasses</title>
-
- <para>This is sometimes useful to share common properties through a
- technical or a business superclass without including it as a regular
- mapped entity (ie no specific table for this entity). For that purpose
- you can map them as <literal>@MappedSuperclass</literal>.</para>
-
- <programlisting language="JAVA" role="JAVA">@MappedSuperclass
-public class BaseEntity {
- @Basic
- @Temporal(TemporalType.TIMESTAMP)
- public Date getLastUpdate() { ... }
- public String getLastUpdater() { ... }
- ...
-}
-
- at Entity class Order extends BaseEntity {
- @Id public Integer getId() { ... }
- ...
-}</programlisting>
-
- <para>In database, this hierarchy will be represented as an
- <literal>Order</literal> table having the <literal>id</literal>,
- <literal>lastUpdate</literal> and <literal>lastUpdater</literal>
- columns. The embedded superclass property mappings are copied into
- their entity subclasses. Remember that the embeddable superclass is
- not the root of the hierarchy though.</para>
-
- <note>
- <para>Properties from superclasses not mapped as
- <literal>@MappedSuperclass</literal> are ignored.</para>
- </note>
-
- <note>
- <para>The default access type (field or methods) is used, unless you
- use the <literal>@Access</literal> annotation.</para>
- </note>
-
- <note>
- <para>The same notion can be applied to
- <literal>@Embeddable</literal> objects to persist properties from
- their superclasses. You also need to use
- <literal>@MappedSuperclass</literal> to do that (this should not be
- considered as a standard EJB3 feature though)</para>
- </note>
-
- <note>
- <para>It is allowed to mark a class as
- <literal>@MappedSuperclass</literal> in the middle of the mapped
- inheritance hierarchy.</para>
- </note>
-
- <note>
- <para>Any class in the hierarchy non annotated with
- <literal>@MappedSuperclass</literal> nor <literal>@Entity</literal>
- will be ignored.</para>
- </note>
-
- <para>You can override columns defined in entity superclasses at the
- root entity level using the <literal>@AttributeOverride</literal>
- annotation.</para>
-
- <programlisting language="JAVA" role="JAVA">@MappedSuperclass
-public class FlyingObject implements Serializable {
-
- public int getAltitude() {
- return altitude;
- }
-
- @Transient
- public int getMetricAltitude() {
- return metricAltitude;
- }
-
- @ManyToOne
- public PropulsionType getPropulsion() {
- return metricAltitude;
- }
- ...
-}
-
- at Entity
- at AttributeOverride( name="altitude", column = @Column(name="fld_altitude") )
- at AssociationOverride(
- name="propulsion",
- joinColumns = @JoinColumn(name="fld_propulsion_fk")
-)
-public class Plane extends FlyingObject {
- ...
-}</programlisting>
-
- <para>The <literal>altitude</literal> property will be persisted in an
- <literal>fld_altitude</literal> column of table
- <literal>Plane</literal> and the propulsion association will be
- materialized in a <literal>fld_propulsion_fk</literal> foreign key
- column.</para>
-
- <para>You can define <literal>@AttributeOverride</literal>(s) and
- <literal>@AssociationOverride</literal>(s) on
- <literal>@Entity</literal> classes,
- <literal>@MappedSuperclass</literal> classes and properties pointing
- to an <literal>@Embeddable</literal> object.</para>
-
- <para>In hbm.xml, simply map the properties of the superclass in the
- <literal><class></literal> element of the entity that needs to
- inherit them.</para>
- </section>
-
- <section id="mapping-declaration-join" revision="3">
- <title>Mapping one entity to several tables</title>
-
- <para>While not recommended for a fresh schema, some legacy databases
- force your to map a single entity on several tables.</para>
-
- <para>Using the <literal>@SecondaryTable</literal> or
- <literal>@SecondaryTables</literal> class level annotations. To
- express that a column is in a particular table, use the
- <literal>table</literal> parameter of <literal>@Column</literal> or
- <literal>@JoinColumn</literal>.</para>
-
- <programlisting language="JAVA" role="JAVA">@Entity
- at Table(name="MainCat")
- at SecondaryTables({
- @SecondaryTable(name="Cat1", pkJoinColumns={
- @PrimaryKeyJoinColumn(name="cat_id", referencedColumnName="id")
- ),
- @SecondaryTable(name="Cat2", uniqueConstraints={@UniqueConstraint(columnNames={"storyPart2"})})
-})
-public class Cat implements Serializable {
-
- private Integer id;
- private String name;
- private String storyPart1;
- private String storyPart2;
-
- @Id @GeneratedValue
- public Integer getId() {
- return id;
- }
-
- public String getName() {
- return name;
- }
-
- @Column(table="Cat1")
- public String getStoryPart1() {
- return storyPart1;
- }
-
- @Column(table="Cat2")
- public String getStoryPart2() {
- return storyPart2;
- }
-}</programlisting>
-
- <para>In this example, <literal>name</literal> will be in
- <literal>MainCat</literal>. <literal>storyPart1</literal> will be in
- <literal>Cat1</literal> and <literal>storyPart2</literal> will be in
- <literal>Cat2</literal>. <literal>Cat1</literal> will be joined to
- <literal>MainCat</literal> using the <literal>cat_id</literal> as a
- foreign key, and <literal>Cat2</literal> using <literal>id</literal>
- (ie the same column name, the <literal>MainCat</literal> id column
- has). Plus a unique constraint on <literal>storyPart2</literal> has
- been set.</para>
-
- <para>There is also additional tuning accessible via the
- <classname>@org.hibernate.annotations.Table</classname>
- annotation:</para>
-
- <itemizedlist>
- <listitem>
- <para><literal>fetch</literal>: If set to JOIN, the default,
- Hibernate will use an inner join to retrieve a secondary table
- defined by a class or its superclasses and an outer join for a
- secondary table defined by a subclass. If set to
- <classname>SELECT</classname> then Hibernate will use a sequential
- select for a secondary table 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 secondary
- defined by the class and its superclasses.</para>
- </listitem>
-
- <listitem>
- <para><literal>inverse</literal>: If true, Hibernate will not try
- to insert or update the properties defined by this join. Default
- to false.</para>
- </listitem>
-
- <listitem>
- <para><literal>optional</literal>: If enabled (the default),
- 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>
- </listitem>
-
- <listitem>
- <para><literal>foreignKey</literal>: defines the Foreign Key name
- of a secondary table pointing back to the primary table.</para>
- </listitem>
- </itemizedlist>
-
- <para>Make sure to use the secondary table name in the
- <methodname>appliesto</methodname> property</para>
-
- <programlisting language="JAVA" role="JAVA">@Entity
- at Table(name="MainCat")
- at SecondaryTable(name="Cat1")
- at org.hibernate.annotations.Table(
- appliesTo="Cat1",
- fetch=FetchMode.SELECT,
- optional=true)
-public class Cat implements Serializable {
-
- private Integer id;
- private String name;
- private String storyPart1;
- private String storyPart2;
-
- @Id @GeneratedValue
- public Integer getId() {
- return id;
- }
-
- public String getName() {
- return name;
- }
-
- @Column(table="Cat1")
- public String getStoryPart1() {
- return storyPart1;
- }
-
- @Column(table="Cat2")
- public String getStoryPart2() {
- return storyPart2;
- }
-}</programlisting>
-
- <para>In hbm.xml, use the <literal><join></literal>
- element.</para>
-
- <programlistingco role="XML">
- <areaspec>
- <area coords="2" id="join1" />
-
- <area coords="3" id="join2" />
-
- <area coords="4" id="join3" />
-
- <area coords="5" id="join4" />
-
- <area coords="6" id="join5" />
-
- <area coords="7" id="join6" />
- </areaspec>
-
- <programlisting><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): overrides the schema
- name specified by the root
- <literal><hibernate-mapping></literal> element.</para>
- </callout>
-
- <callout arearefs="join3">
- <para><literal>catalog</literal> (optional): overrides 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. It will use 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. This will be issued only if a row represents 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 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. It
- will always use an outer join to retrieve the properties.</para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>For example, address information for a person can be mapped to a
- separate table while preserving value type semantics for all
- properties:</para>
-
- <programlisting role="XML"><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>
- </section>
- </section>
-
- <section>
<title>Optimistic locking properties (optional)</title>
<para>When using long transactions or conversations that span several
@@ -4182,7 +3046,1013 @@
</section>
</section>
+ <section id="mapping-declaration-component">
+ <title>Embedded objects (aka components)</title>
+
+ <para>Embeddable objects (or components) are objects whose properties
+ are mapped to the same table as the owning entity's table. Components
+ can, in turn, declare their own properties, components or
+ collections</para>
+
+ <para>It is possible to declare an embedded component inside an entity
+ and even override its column mapping. Component classes have to be
+ annotated at the class level with the <literal>@Embeddable</literal>
+ annotation. It is possible to override the column mapping of an embedded
+ object for a particular entity using the <literal>@Embedded</literal>
+ and <literal>@AttributeOverride</literal> annotation in the associated
+ property:</para>
+
+ <programlisting language="JAVA" role="JAVA">@Entity
+public class Person implements Serializable {
+
+ // Persistent component using defaults
+ Address homeAddress;
+
+ @Embedded
+ @AttributeOverrides( {
+ @AttributeOverride(name="iso2", column = @Column(name="bornIso2") ),
+ @AttributeOverride(name="name", column = @Column(name="bornCountryName") )
+ } )
+ Country bornIn;
+ ...
+} </programlisting>
+
+ <programlisting language="JAVA" role="JAVA">@Embeddable
+public class Address implements Serializable {
+ String city;
+ Country nationality; //no overriding here
+} </programlisting>
+
+ <programlisting language="JAVA" role="JAVA">@Embeddable
+public class Country implements Serializable {
+ private String iso2;
+ @Column(name="countryName") private String name;
+
+ public String getIso2() { return iso2; }
+ public void setIso2(String iso2) { this.iso2 = iso2; }
+
+
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+ ...
+} </programlisting>
+
+ <para>An embeddable object inherits the access type of its owning entity
+ (note that you can override that using the <literal>@Access</literal>
+ annotation).</para>
+
+ <para>The <literal>Person</literal> entity has two component properties,
+ <literal>homeAddress</literal> and <literal>bornIn</literal>.
+ <literal>homeAddress</literal> property has not been annotated, but
+ Hibernate will guess that it is a persistent component by looking for
+ the <literal>@Embeddable</literal> annotation in the Address class. We
+ also override the mapping of a column name (to
+ <literal>bornCountryName</literal>) with the
+ <literal>@Embedded</literal> and <literal>@AttributeOverride
+ </literal>annotations for each mapped attribute of
+ <literal>Country</literal>. As you can see, <literal>Country
+ </literal>is also a nested component of <literal>Address</literal>,
+ again using auto-detection by Hibernate and JPA defaults. Overriding
+ columns of embedded objects of embedded objects is through dotted
+ expressions.</para>
+
+ <programlisting language="JAVA" role="JAVA"> @Embedded
+ @AttributeOverrides( {
+ @AttributeOverride(name="city", column = @Column(name="fld_city") ),
+ @AttributeOverride(name="nationality.iso2", column = @Column(name="nat_Iso2") ),
+ @AttributeOverride(name="nationality.name", column = @Column(name="nat_CountryName") )
+ //nationality columns in homeAddress are overridden
+ } )
+ Address homeAddress;</programlisting>
+
+ <para>Hibernate Annotations supports something that is not explicitly
+ supported by the JPA specification. You can annotate a embedded object
+ with the <literal>@MappedSuperclass</literal> annotation to make the
+ superclass properties persistent (see
+ <literal>@MappedSuperclass</literal> for more informations).</para>
+
+ <para>You can also use association annotations in an embeddable object
+ (ie <literal>@OneToOne</literal>, <classname>@ManyToOne</classname>,
+ <classname>@OneToMany</classname> or <literal>@ManyToMany</literal>). To
+ override the association columns you can use
+ <literal>@AssociationOverride</literal>.</para>
+
+ <para>If you want to have the same embeddable object type twice in the
+ same entity, the column name defaulting will not work as several
+ embedded objects would share the same set of columns. In plain JPA, you
+ need to override at least one set of columns. Hibernate, however, allows
+ you to enhance the default naming mechanism through the
+ <classname>NamingStrategy</classname> interface. You can write a
+ strategy that prevent name clashing in such a situation.
+ <classname>DefaultComponentSafeNamingStrategy</classname> is an example
+ of this.</para>
+
+ <para>If a property of the embedded object points back to the owning
+ entity, annotate it with the <classname>@Parent</classname> annotation.
+ Hibernate will make sure this property is properly loaded with the
+ entity reference.</para>
+
+ <para>In XML, use the <literal><component></literal>
+ element.</para>
+
+ <programlistingco role="XML">
+ <areaspec>
+ <area coords="2" id="component1" />
+
+ <area coords="3" id="component2" />
+
+ <area coords="4" id="component3" />
+
+ <area coords="5" id="component4" />
+
+ <area coords="6" id="component5" />
+
+ <area coords="7" id="component6" />
+
+ <area coords="8" id="component7" />
+
+ <area coords="9" id="component8" />
+ </areaspec>
+
+ <programlisting><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>INSERTs</literal>?</para>
+ </callout>
+
+ <callout arearefs="component4">
+ <para><literal>update</literal>: do the mapped columns appear in
+ SQL <literal>UPDATEs</literal>?</para>
+ </callout>
+
+ <callout arearefs="component5">
+ <para><literal>access</literal> (optional - defaults to
+ <literal>property</literal>): the strategy Hibernate uses 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. It
+ 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
+ either do or do not require acquisition of the optimistic lock. It
+ 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" /> for more information. This feature is
+ not supported in annotations.</para>
+ </section>
+
<section>
+ <title>Inheritance strategy</title>
+
+ <para>Java is a language supporting polymorphism: a class can inherit
+ from another. Several strategies are possible to persist a class
+ hierarchy:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Single table per class hierarchy strategy: a single table
+ hosts all the instances of a class hierarchy</para>
+ </listitem>
+
+ <listitem>
+ <para>Joined subclass strategy: one table per class and subclass is
+ present and each table persist the properties specific to a given
+ subclass. The state of the entity is then stored in its
+ corresponding class table and all its superclasses</para>
+ </listitem>
+
+ <listitem>
+ <para>Table per class strategy: one table per concrete class and
+ subclass is present and each table persist the properties of the
+ class and its superclasses. The state of the entity is then stored
+ entirely in the dedicated table for its class.</para>
+ </listitem>
+ </itemizedlist>
+
+ <section id="mapping-declaration-subclass" revision="4">
+ <title>Single table per class hierarchy strategy</title>
+
+ <para>With this approach the properties of all the subclasses in a
+ given mapped class hierarchy are stored in a single table.</para>
+
+ <para>Each subclass declares its own persistent properties and
+ subclasses. Version and id properties are assumed to be inherited from
+ the root class. Each subclass in a hierarchy must define a unique
+ discriminator value. If this is not specified, the fully qualified
+ Java class name is used.</para>
+
+ <programlisting language="JAVA" role="JAVA">@Entity
+ at Inheritance(strategy=InheritanceType.SINGLE_TABLE)
+ at DiscriminatorColumn(
+ name="planetype",
+ discriminatorType=DiscriminatorType.STRING
+)
+ at DiscriminatorValue("Plane")
+public class Plane { ... }
+
+ at Entity
+ at DiscriminatorValue("A320")
+public class A320 extends Plane { ... } </programlisting>
+
+ <para>In hbm.xml, for the table-per-class-hierarchy mapping strategy,
+ the <literal><subclass></literal> declaration is used. For
+ example:</para>
+
+ <programlistingco role="XML">
+ <areaspec>
+ <area coords="2" id="subclass1" />
+
+ <area coords="3" id="subclass2" />
+
+ <area coords="4" id="subclass3" />
+
+ <area coords="5" id="subclass4" />
+ </areaspec>
+
+ <programlisting><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 distinguishes
+ individual subclasses.</para>
+ </callout>
+
+ <callout arearefs="subclass3">
+ <para><literal>proxy</literal> (optional): specifies a class or
+ interface used 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>For information about inheritance mappings see <xref
+ linkend="inheritance" />.</para>
+
+ <section id="mapping-declaration-discriminator" revision="3">
+ <title>Discriminator</title>
+
+ <para>Discriminators are required for polymorphic persistence using
+ the table-per-class-hierarchy mapping strategy. It 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 can 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>
+
+ <para>Use the <classname>@DiscriminatorColumn</classname> to define
+ the discriminator column as well as the discriminator type.
+ Alternatively, you can also use
+ <classname>@DiscriminatorFormula</classname> to express in SQL what
+ would be in a virtual discriminator column. This is particularly
+ handy when the discriminator value can be extracted from one or more
+ columns of the table. Both
+ <classname>@DiscriminatorColumn</classname> and
+ <classname>@DiscriminatorFormula</classname> are to be set on the
+ root entity (once per persisted hierarchy).</para>
+
+ <para>Finally, use <classname>@DiscriminatorValue</classname> on
+ each class of the hierarchy to specify the value stored in the
+ discriminator column for a given entity. If you do not set
+ <classname>@DiscriminatorValue</classname> on a class, the fully
+ qualified class name is used.</para>
+
+ <programlisting language="JAVA" role="JAVA">@Entity
+ at Inheritance(strategy=InheritanceType.SINGLE_TABLE)
+ at DiscriminatorColumn(
+ name="planetype",
+ discriminatorType=DiscriminatorType.STRING
+)
+ at DiscriminatorValue("Plane")
+public class Plane { ... }
+
+ at Entity
+ at DiscriminatorValue("A320")
+public class A320 extends Plane { ... } </programlisting>
+
+ <para>In hbm.xml, the <literal><discriminator></literal>
+ element is used to define the discriminator column or
+ formula:</para>
+
+ <programlistingco role="XML">
+ <areaspec>
+ <area coords="2" id="discriminator1" />
+
+ <area coords="3" id="discriminator2" />
+
+ <area coords="4" id="discriminator3" />
+
+ <area coords="5" id="discriminator4" />
+
+ <area coords="6" id="discriminator5" />
+ </areaspec>
+
+ <programlisting><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>): "forces" Hibernate to specify the
+ 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. It tells Hibernate not to include the
+ column in SQL <literal>INSERTs</literal>.</para>
+ </callout>
+
+ <callout arearefs="discriminator5">
+ <para><literal>formula</literal> (optional): an arbitrary SQL
+ expression that is executed when a type has to be evaluated.
+ It 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>The <literal>formula</literal> attribute allows you to declare
+ an arbitrary SQL expression that will be used to evaluate the type
+ of a row. For example:</para>
+
+ <programlisting role="XML"><discriminator
+ formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
+ type="integer"/></programlisting>
+ </section>
+ </section>
+
+ <section id="mapping-declaration-joinedsubclass" revision="3">
+ <title>Joined subclass strategy</title>
+
+ <para>Each subclass can also be mapped to its own table. This is
+ called the table-per-subclass mapping strategy. An inherited state is
+ retrieved by joining with the table of the superclass. A discriminator
+ column is not required for this mapping strategy. Each subclass must,
+ however, declare a table column holding the object identifier. The
+ primary key of this table is also a foreign key to the superclass
+ table and described by the
+ <classname>@PrimaryKeyJoinColumn</classname>s or the
+ <literal><key></literal> element.</para>
+
+ <programlisting language="JAVA" role="JAVA">@Entity @Table(name="CATS")
+ at Inheritance(strategy=InheritanceType.JOINED)
+public class Cat implements Serializable {
+ @Id @GeneratedValue(generator="cat-uuid")
+ @GenericGenerator(name="cat-uuid", strategy="uuid")
+ String getId() { return id; }
+
+ ...
+}
+
+ at Entity @Table(name="DOMESTIC_CATS")
+ at PrimaryKeyJoinColumn(name="CAT")
+public class DomesticCat extends Cat {
+ public String getName() { return name; }
+} </programlisting>
+
+ <note>
+ <para>The table name still defaults to the non qualified class name.
+ Also if <classname>@PrimaryKeyJoinColumn</classname> is not set, the
+ primary key / foreign key columns are assumed to have the same names
+ as the primary key columns of the primary table of the
+ superclass.</para>
+ </note>
+
+ <para>In hbm.xml, use the <literal><joined-subclass></literal>
+ element. For example:</para>
+
+ <programlistingco role="XML">
+ <areaspec>
+ <area coords="2" id="joinedsubclass1" />
+
+ <area coords="3" id="joinedsubclass2" />
+
+ <area coords="4" id="joinedsubclass3" />
+
+ <area coords="5" id="joinedsubclass4" />
+ </areaspec>
+
+ <programlisting><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>Use the <literal><key></literal> element to declare the
+ primary key / foreign key column. The mapping at the start of the
+ chapter would then be re-written as:</para>
+
+ <programlisting role="XML"><?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>
+ </section>
+
+ <section id="mapping-declaration-unionsubclass" revision="2">
+ <title>Table per class strategy</title>
+
+ <para>A third option is to map only the concrete classes of an
+ inheritance hierarchy to tables. This is called the
+ table-per-concrete-class strategy. Each table defines all persistent
+ states of the class, including the inherited state. In Hibernate, it
+ is not necessary to explicitly map such inheritance hierarchies. You
+ can map each class as a separate entity root. However, if you wish use
+ polymorphic associations (e.g. an association to the superclass of
+ your hierarchy), you need to use the union subclass mapping.</para>
+
+ <programlisting language="JAVA" role="JAVA">@Entity
+ at Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
+public class Flight implements Serializable { ... } </programlisting>
+
+ <para>Or in hbm.xml:</para>
+
+ <programlistingco role="XML">
+ <areaspec>
+ <area coords="2" id="unionsubclass1" />
+
+ <area coords="3" id="unionsubclass2" />
+
+ <area coords="4" id="unionsubclass3" />
+
+ <area coords="5" id="unionsubclass4" />
+ </areaspec>
+
+ <programlisting><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>
+ </section>
+
+ <section>
+ <title>Inherit properties from superclasses</title>
+
+ <para>This is sometimes useful to share common properties through a
+ technical or a business superclass without including it as a regular
+ mapped entity (ie no specific table for this entity). For that purpose
+ you can map them as <literal>@MappedSuperclass</literal>.</para>
+
+ <programlisting language="JAVA" role="JAVA">@MappedSuperclass
+public class BaseEntity {
+ @Basic
+ @Temporal(TemporalType.TIMESTAMP)
+ public Date getLastUpdate() { ... }
+ public String getLastUpdater() { ... }
+ ...
+}
+
+ at Entity class Order extends BaseEntity {
+ @Id public Integer getId() { ... }
+ ...
+}</programlisting>
+
+ <para>In database, this hierarchy will be represented as an
+ <literal>Order</literal> table having the <literal>id</literal>,
+ <literal>lastUpdate</literal> and <literal>lastUpdater</literal>
+ columns. The embedded superclass property mappings are copied into
+ their entity subclasses. Remember that the embeddable superclass is
+ not the root of the hierarchy though.</para>
+
+ <note>
+ <para>Properties from superclasses not mapped as
+ <literal>@MappedSuperclass</literal> are ignored.</para>
+ </note>
+
+ <note>
+ <para>The default access type (field or methods) is used, unless you
+ use the <literal>@Access</literal> annotation.</para>
+ </note>
+
+ <note>
+ <para>The same notion can be applied to
+ <literal>@Embeddable</literal> objects to persist properties from
+ their superclasses. You also need to use
+ <literal>@MappedSuperclass</literal> to do that (this should not be
+ considered as a standard EJB3 feature though)</para>
+ </note>
+
+ <note>
+ <para>It is allowed to mark a class as
+ <literal>@MappedSuperclass</literal> in the middle of the mapped
+ inheritance hierarchy.</para>
+ </note>
+
+ <note>
+ <para>Any class in the hierarchy non annotated with
+ <literal>@MappedSuperclass</literal> nor <literal>@Entity</literal>
+ will be ignored.</para>
+ </note>
+
+ <para>You can override columns defined in entity superclasses at the
+ root entity level using the <literal>@AttributeOverride</literal>
+ annotation.</para>
+
+ <programlisting language="JAVA" role="JAVA">@MappedSuperclass
+public class FlyingObject implements Serializable {
+
+ public int getAltitude() {
+ return altitude;
+ }
+
+ @Transient
+ public int getMetricAltitude() {
+ return metricAltitude;
+ }
+
+ @ManyToOne
+ public PropulsionType getPropulsion() {
+ return metricAltitude;
+ }
+ ...
+}
+
+ at Entity
+ at AttributeOverride( name="altitude", column = @Column(name="fld_altitude") )
+ at AssociationOverride(
+ name="propulsion",
+ joinColumns = @JoinColumn(name="fld_propulsion_fk")
+)
+public class Plane extends FlyingObject {
+ ...
+}</programlisting>
+
+ <para>The <literal>altitude</literal> property will be persisted in an
+ <literal>fld_altitude</literal> column of table
+ <literal>Plane</literal> and the propulsion association will be
+ materialized in a <literal>fld_propulsion_fk</literal> foreign key
+ column.</para>
+
+ <para>You can define <literal>@AttributeOverride</literal>(s) and
+ <literal>@AssociationOverride</literal>(s) on
+ <literal>@Entity</literal> classes,
+ <literal>@MappedSuperclass</literal> classes and properties pointing
+ to an <literal>@Embeddable</literal> object.</para>
+
+ <para>In hbm.xml, simply map the properties of the superclass in the
+ <literal><class></literal> element of the entity that needs to
+ inherit them.</para>
+ </section>
+
+ <section id="mapping-declaration-join" revision="3">
+ <title>Mapping one entity to several tables</title>
+
+ <para>While not recommended for a fresh schema, some legacy databases
+ force your to map a single entity on several tables.</para>
+
+ <para>Using the <literal>@SecondaryTable</literal> or
+ <literal>@SecondaryTables</literal> class level annotations. To
+ express that a column is in a particular table, use the
+ <literal>table</literal> parameter of <literal>@Column</literal> or
+ <literal>@JoinColumn</literal>.</para>
+
+ <programlisting language="JAVA" role="JAVA">@Entity
+ at Table(name="MainCat")
+ at SecondaryTables({
+ @SecondaryTable(name="Cat1", pkJoinColumns={
+ @PrimaryKeyJoinColumn(name="cat_id", referencedColumnName="id")
+ ),
+ @SecondaryTable(name="Cat2", uniqueConstraints={@UniqueConstraint(columnNames={"storyPart2"})})
+})
+public class Cat implements Serializable {
+
+ private Integer id;
+ private String name;
+ private String storyPart1;
+ private String storyPart2;
+
+ @Id @GeneratedValue
+ public Integer getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Column(table="Cat1")
+ public String getStoryPart1() {
+ return storyPart1;
+ }
+
+ @Column(table="Cat2")
+ public String getStoryPart2() {
+ return storyPart2;
+ }
+}</programlisting>
+
+ <para>In this example, <literal>name</literal> will be in
+ <literal>MainCat</literal>. <literal>storyPart1</literal> will be in
+ <literal>Cat1</literal> and <literal>storyPart2</literal> will be in
+ <literal>Cat2</literal>. <literal>Cat1</literal> will be joined to
+ <literal>MainCat</literal> using the <literal>cat_id</literal> as a
+ foreign key, and <literal>Cat2</literal> using <literal>id</literal>
+ (ie the same column name, the <literal>MainCat</literal> id column
+ has). Plus a unique constraint on <literal>storyPart2</literal> has
+ been set.</para>
+
+ <para>There is also additional tuning accessible via the
+ <classname>@org.hibernate.annotations.Table</classname>
+ annotation:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><literal>fetch</literal>: If set to JOIN, the default,
+ Hibernate will use an inner join to retrieve a secondary table
+ defined by a class or its superclasses and an outer join for a
+ secondary table defined by a subclass. If set to
+ <classname>SELECT</classname> then Hibernate will use a sequential
+ select for a secondary table 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 secondary
+ defined by the class and its superclasses.</para>
+ </listitem>
+
+ <listitem>
+ <para><literal>inverse</literal>: If true, Hibernate will not try
+ to insert or update the properties defined by this join. Default
+ to false.</para>
+ </listitem>
+
+ <listitem>
+ <para><literal>optional</literal>: If enabled (the default),
+ 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>
+ </listitem>
+
+ <listitem>
+ <para><literal>foreignKey</literal>: defines the Foreign Key name
+ of a secondary table pointing back to the primary table.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Make sure to use the secondary table name in the
+ <methodname>appliesto</methodname> property</para>
+
+ <programlisting language="JAVA" role="JAVA">@Entity
+ at Table(name="MainCat")
+ at SecondaryTable(name="Cat1")
+ at org.hibernate.annotations.Table(
+ appliesTo="Cat1",
+ fetch=FetchMode.SELECT,
+ optional=true)
+public class Cat implements Serializable {
+
+ private Integer id;
+ private String name;
+ private String storyPart1;
+ private String storyPart2;
+
+ @Id @GeneratedValue
+ public Integer getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Column(table="Cat1")
+ public String getStoryPart1() {
+ return storyPart1;
+ }
+
+ @Column(table="Cat2")
+ public String getStoryPart2() {
+ return storyPart2;
+ }
+}</programlisting>
+
+ <para>In hbm.xml, use the <literal><join></literal>
+ element.</para>
+
+ <programlistingco role="XML">
+ <areaspec>
+ <area coords="2" id="join1" />
+
+ <area coords="3" id="join2" />
+
+ <area coords="4" id="join3" />
+
+ <area coords="5" id="join4" />
+
+ <area coords="6" id="join5" />
+
+ <area coords="7" id="join6" />
+ </areaspec>
+
+ <programlisting><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): overrides the schema
+ name specified by the root
+ <literal><hibernate-mapping></literal> element.</para>
+ </callout>
+
+ <callout arearefs="join3">
+ <para><literal>catalog</literal> (optional): overrides 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. It will use 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. This will be issued only if a row represents 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 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. It
+ will always use an outer join to retrieve the properties.</para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>For example, address information for a person can be mapped to a
+ separate table while preserving value type semantics for all
+ properties:</para>
+
+ <programlisting role="XML"><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>
+ </section>
+ </section>
+
+ <section>
<title>Mapping one to one and one to many associations</title>
<para>To link one entity to an other, you need to map the association
@@ -4900,213 +4770,145 @@
</itemizedlist>
</section>
- <section id="mapping-declaration-component">
- <title>Embedded objects (aka components)</title>
+ <section id="mapping-types-anymapping" revision="2">
+ <title>Any</title>
- <para>Embeddable objects (or components) are objects whose properties
- are mapped to the same table as the owning entity's table. Components
- can, in turn, declare their own properties, components or
- collections</para>
+ <para>There is one more type of property mapping. The
+ <classname>@Any</classname> mapping defines a polymorphic association to
+ classes from multiple tables. This type of mapping requires more than
+ one column. The first column contains the type of the associated entity.
+ The remaining columns contain the identifier. It is impossible to
+ specify a foreign key constraint for this kind of association. This is
+ not the usual way of mapping polymorphic associations and you should use
+ this only in special cases. For example, for audit logs, user session
+ data, etc.</para>
- <para>It is possible to declare an embedded component inside an entity
- and even override its column mapping. Component classes have to be
- annotated at the class level with the <literal>@Embeddable</literal>
- annotation. It is possible to override the column mapping of an embedded
- object for a particular entity using the <literal>@Embedded</literal>
- and <literal>@AttributeOverride</literal> annotation in the associated
- property:</para>
+ <para>The <classname>@Any</classname> annotation describes the column
+ holding the metadata information. To link the value of the metadata
+ information and an actual entity type, The
+ <classname>@AnyDef</classname> and <classname>@AnyDefs</classname>
+ annotations are used. The <literal>metaType</literal> attribute allows
+ the application to specify a custom type that maps database column
+ values to persistent classes that have identifier properties of the type
+ specified by <literal>idType</literal>. You must specify the mapping
+ from values of the <literal>metaType</literal> to class names.</para>
- <programlisting language="JAVA" role="JAVA">@Entity
-public class Person implements Serializable {
-
- // Persistent component using defaults
- Address homeAddress;
-
- @Embedded
- @AttributeOverrides( {
- @AttributeOverride(name="iso2", column = @Column(name="bornIso2") ),
- @AttributeOverride(name="name", column = @Column(name="bornCountryName") )
+ <programlisting language="JAVA" role="JAVA">@Any( metaColumn = @Column( name = "property_type" ), fetch=FetchType.EAGER )
+ at AnyMetaDef(
+ idType = "integer",
+ metaType = "string",
+ metaValues = {
+ @MetaValue( value = "S", targetEntity = StringProperty.class ),
+ @MetaValue( value = "I", targetEntity = IntegerProperty.class )
} )
- Country bornIn;
- ...
-} </programlisting>
+ at JoinColumn( name = "property_id" )
+public Property getMainProperty() {
+ return mainProperty;
+}</programlisting>
- <programlisting language="JAVA" role="JAVA">@Embeddable
-public class Address implements Serializable {
- String city;
- Country nationality; //no overriding here
-} </programlisting>
+ <para>Note that <classname>@AnyDef</classname> can be mutualized and
+ reused. It is recommended to place it as a package metadata in this
+ case.</para>
- <programlisting language="JAVA" role="JAVA">@Embeddable
-public class Country implements Serializable {
- private String iso2;
- @Column(name="countryName") private String name;
-
- public String getIso2() { return iso2; }
- public void setIso2(String iso2) { this.iso2 = iso2; }
-
-
- public String getName() { return name; }
- public void setName(String name) { this.name = name; }
- ...
-} </programlisting>
-
- <para>An embeddable object inherits the access type of its owning entity
- (note that you can override that using the <literal>@Access</literal>
- annotation).</para>
-
- <para>The <literal>Person</literal> entity has two component properties,
- <literal>homeAddress</literal> and <literal>bornIn</literal>.
- <literal>homeAddress</literal> property has not been annotated, but
- Hibernate will guess that it is a persistent component by looking for
- the <literal>@Embeddable</literal> annotation in the Address class. We
- also override the mapping of a column name (to
- <literal>bornCountryName</literal>) with the
- <literal>@Embedded</literal> and <literal>@AttributeOverride
- </literal>annotations for each mapped attribute of
- <literal>Country</literal>. As you can see, <literal>Country
- </literal>is also a nested component of <literal>Address</literal>,
- again using auto-detection by Hibernate and JPA defaults. Overriding
- columns of embedded objects of embedded objects is through dotted
- expressions.</para>
-
- <programlisting language="JAVA" role="JAVA"> @Embedded
- @AttributeOverrides( {
- @AttributeOverride(name="city", column = @Column(name="fld_city") ),
- @AttributeOverride(name="nationality.iso2", column = @Column(name="nat_Iso2") ),
- @AttributeOverride(name="nationality.name", column = @Column(name="nat_CountryName") )
- //nationality columns in homeAddress are overridden
+ <programlisting language="JAVA" role="JAVA">//on a package
+ at AnyMetaDef( name="property"
+ idType = "integer",
+ metaType = "string",
+ metaValues = {
+ @MetaValue( value = "S", targetEntity = StringProperty.class ),
+ @MetaValue( value = "I", targetEntity = IntegerProperty.class )
} )
- Address homeAddress;</programlisting>
+package org.hibernate.test.annotations.any;
- <para>Hibernate Annotations supports something that is not explicitly
- supported by the JPA specification. You can annotate a embedded object
- with the <literal>@MappedSuperclass</literal> annotation to make the
- superclass properties persistent (see
- <literal>@MappedSuperclass</literal> for more informations).</para>
- <para>You can also use association annotations in an embeddable object
- (ie <literal>@OneToOne</literal>, <classname>@ManyToOne</classname>,
- <classname>@OneToMany</classname> or <literal>@ManyToMany</literal>). To
- override the association columns you can use
- <literal>@AssociationOverride</literal>.</para>
+//in a class
+ @Any( metaDef="property", metaColumn = @Column( name = "property_type" ), fetch=FetchType.EAGER )
+ @JoinColumn( name = "property_id" )
+ public Property getMainProperty() {
+ return mainProperty;
+ }</programlisting>
- <para>If you want to have the same embeddable object type twice in the
- same entity, the column name defaulting will not work as several
- embedded objects would share the same set of columns. In plain JPA, you
- need to override at least one set of columns. Hibernate, however, allows
- you to enhance the default naming mechanism through the
- <classname>NamingStrategy</classname> interface. You can write a
- strategy that prevent name clashing in such a situation.
- <classname>DefaultComponentSafeNamingStrategy</classname> is an example
- of this.</para>
+ <para>The hbm.xml equivalent is:</para>
- <para>If a property of the embedded object points back to the owning
- entity, annotate it with the <classname>@Parent</classname> annotation.
- Hibernate will make sure this property is properly loaded with the
- entity reference.</para>
+ <programlisting role="XML"><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>
- <para>In XML, use the <literal><component></literal>
- element.</para>
+ <note>
+ <para>You cannot mutualize the metadata in hbm.xml as you can in
+ annotations.</para>
+ </note>
<programlistingco role="XML">
<areaspec>
- <area coords="2" id="component1" />
+ <area coords="2" id="any1" />
- <area coords="3" id="component2" />
+ <area coords="3" id="any2" />
- <area coords="4" id="component3" />
+ <area coords="4" id="any3" />
- <area coords="5" id="component4" />
+ <area coords="5" id="any4" />
- <area coords="6" id="component5" />
+ <area coords="6" id="any5" />
- <area coords="7" id="component6" />
-
- <area coords="8" id="component7" />
-
- <area coords="9" id="component8" />
+ <area coords="7" id="any6" />
</areaspec>
- <programlisting><component
+ <programlisting><any
name="propertyName"
- class="className"
- insert="true|false"
- update="true|false"
+ id-type="idtypename"
+ meta-type="metatypename"
+ cascade="cascade_style"
access="field|property|ClassName"
- lazy="true|false"
optimistic-lock="true|false"
- unique="true|false"
- node="element-name|."
>
+ <meta-value ... />
+ <meta-value ... />
+ .....
+ <column .... />
+ <column .... />
+ .....
+</any></programlisting>
- <property ...../>
- <many-to-one .... />
- ........
-</component></programlisting>
-
<calloutlist>
- <callout arearefs="component1">
- <para><literal>name</literal>: the name of the property.</para>
+ <callout arearefs="any1">
+ <para><literal>name</literal>: the property name.</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 arearefs="any2">
+ <para><literal>id-type</literal>: the identifier type.</para>
</callout>
- <callout arearefs="component3">
- <para><literal>insert</literal>: do the mapped columns appear in
- SQL <literal>INSERTs</literal>?</para>
+ <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="component4">
- <para><literal>update</literal>: do the mapped columns appear in
- SQL <literal>UPDATEs</literal>?</para>
+ <callout arearefs="any4">
+ <para><literal>cascade</literal> (optional- defaults to
+ <literal>none</literal>): the cascade style.</para>
</callout>
- <callout arearefs="component5">
+ <callout arearefs="any5">
<para><literal>access</literal> (optional - defaults to
<literal>property</literal>): the strategy Hibernate uses 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. It
- requires build-time bytecode instrumentation.</para>
- </callout>
-
- <callout arearefs="component7">
+ <callout arearefs="any6">
<para><literal>optimistic-lock</literal> (optional - defaults to
- <literal>true</literal>): specifies that updates to this component
+ <literal>true</literal>): specifies that updates to this property
either do or do not require acquisition of the optimistic lock. It
- determines if a version increment should occur when this property
+ defines whether a version increment should occur if 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" /> for more information. This feature is
- not supported in annotations.</para>
</section>
<section id="mapping-declaration-properties" revision="2">
@@ -5233,145 +5035,343 @@
recommended.</para>
</section>
- <section id="mapping-types-anymapping" revision="2">
- <title>Any</title>
+ <section>
+ <title>Some hbm.xml specificities</title>
- <para>There is one more type of property mapping. The
- <classname>@Any</classname> mapping defines a polymorphic association to
- classes from multiple tables. This type of mapping requires more than
- one column. The first column contains the type of the associated entity.
- The remaining columns contain the identifier. It is impossible to
- specify a foreign key constraint for this kind of association. This is
- not the usual way of mapping polymorphic associations and you should use
- this only in special cases. For example, for audit logs, user session
- data, etc.</para>
+ <para>The hbm.xml structure has some specificities naturally not present
+ when using annotations, let's describe them briefly.</para>
- <para>The <classname>@Any</classname> annotation describes the column
- holding the metadata information. To link the value of the metadata
- information and an actual entity type, The
- <classname>@AnyDef</classname> and <classname>@AnyDefs</classname>
- annotations are used. The <literal>metaType</literal> attribute allows
- the application to specify a custom type that maps database column
- values to persistent classes that have identifier properties of the type
- specified by <literal>idType</literal>. You must specify the mapping
- from values of the <literal>metaType</literal> to class names.</para>
+ <section id="mapping-declaration-doctype" revision="3">
+ <title>Doctype</title>
- <programlisting language="JAVA" role="JAVA">@Any( metaColumn = @Column( name = "property_type" ), fetch=FetchType.EAGER )
- at AnyMetaDef(
- idType = "integer",
- metaType = "string",
- metaValues = {
- @MetaValue( value = "S", targetEntity = StringProperty.class ),
- @MetaValue( value = "I", targetEntity = IntegerProperty.class )
- } )
- at JoinColumn( name = "property_id" )
-public Property getMainProperty() {
- return mainProperty;
-}</programlisting>
+ <para>All XML mappings should declare the doctype shown. The actual
+ DTD can 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 the DTD declaration against the contents
+ of your classpath.</para>
- <para>Note that <classname>@AnyDef</classname> can be mutualized and
- reused. It is recommended to place it as a package metadata in this
- case.</para>
+ <section id="mapping-declaration-entity-resolution">
+ <title>EntityResolver</title>
- <programlisting language="JAVA" role="JAVA">//on a package
- at AnyMetaDef( name="property"
- idType = "integer",
- metaType = "string",
- metaValues = {
- @MetaValue( value = "S", targetEntity = StringProperty.class ),
- @MetaValue( value = "I", targetEntity = IntegerProperty.class )
- } )
-package org.hibernate.test.annotations.any;
+ <para>Hibernate will first attempt to resolve DTDs in its classpath.
+ 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 encounters a systemId starting with
+ <literal>http://hibernate.sourceforge.net/</literal>. The
+ resolver attempts to resolve these entities via the classloader
+ which loaded the Hibernate classes.</para>
+ </listitem>
-//in a class
- @Any( metaDef="property", metaColumn = @Column( name = "property_type" ), fetch=FetchType.EAGER )
- @JoinColumn( name = "property_id" )
- public Property getMainProperty() {
- return mainProperty;
- }</programlisting>
+ <listitem>
+ <para>a <literal>user namespace</literal> is recognized whenever
+ the resolver encounters 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>The hbm.xml equivalent is:</para>
+ <para>The following is an example of utilizing user
+ namespacing:</para>
- <programlisting role="XML"><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>
+ <programlisting language="XML" role="XML">
+<xi:include href="../extras/namespacing.xml_sample" parse="text"
+ xmlns:xi="http://www.w3.org/2001/XInclude" />
+</programlisting>
- <note>
- <para>You cannot mutualize the metadata in hbm.xml as you can in
- annotations.</para>
- </note>
+ <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>
+ </section>
+ </section>
- <programlistingco role="XML">
- <areaspec>
- <area coords="2" id="any1" />
+ <section id="mapping-declaration-mapping" revision="3">
+ <title>Hibernate-mapping</title>
- <area coords="3" id="any2" />
+ <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 they are specified, tablenames will be
+ qualified by the given schema and catalog names. If they are missing,
+ tablenames will be unqualified. The <literal>default-cascade</literal>
+ attribute specifies what cascade style should be assumed for
+ properties and collections that do not specify a
+ <literal>cascade</literal> attribute. By default, the
+ <literal>auto-import</literal> attribute allows you to use unqualified
+ class names in the query language.</para>
- <area coords="4" id="any3" />
+ <programlistingco role="XML">
+ <areaspec>
+ <area coords="2" id="hm1" />
- <area coords="5" id="any4" />
+ <area coords="3" id="hm2" />
- <area coords="6" id="any5" />
+ <area coords="4" id="hm3" />
- <area coords="7" id="any6" />
- </areaspec>
+ <area coords="5" id="hm4" />
- <programlisting><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>
+ <area coords="6" id="hm5" />
- <calloutlist>
- <callout arearefs="any1">
- <para><literal>name</literal>: the property name.</para>
- </callout>
+ <area coords="7" id="hm6" />
- <callout arearefs="any2">
- <para><literal>id-type</literal>: the identifier type.</para>
- </callout>
+ <area coords="8" id="hm7" />
+ </areaspec>
- <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>
+ <programlisting><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>
- <callout arearefs="any4">
- <para><literal>cascade</literal> (optional- defaults to
- <literal>none</literal>): the cascade style.</para>
- </callout>
+ <calloutlist>
+ <callout arearefs="hm1">
+ <para><literal>schema</literal> (optional): the name of a
+ database schema.</para>
+ </callout>
- <callout arearefs="any5">
- <para><literal>access</literal> (optional - defaults to
- <literal>property</literal>): the strategy Hibernate uses for
- accessing the property value.</para>
- </callout>
+ <callout arearefs="hm2">
+ <para><literal>catalog</literal> (optional): the name of a
+ database catalog.</para>
+ </callout>
- <callout arearefs="any6">
- <para><literal>optimistic-lock</literal> (optional - defaults to
- <literal>true</literal>): specifies that updates to this property
- either do or do not require acquisition of the optimistic lock. It
- defines whether a version increment should occur if this property
- is dirty.</para>
- </callout>
- </calloutlist>
- </programlistingco>
+ <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. It 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 unspecified
+ <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 use 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>. An
+ exception will result if you attempt to assign two classes to the same
+ "imported" name.</para>
+
+ <para>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. For example, <literal>Cat.hbm.xml</literal>,
+ <literal>Dog.hbm.xml</literal>, or if using inheritance,
+ <literal>Animal.hbm.xml</literal>.</para>
+ </section>
+
+ <section id="mapping-declaration-key">
+ <title>Key</title>
+
+ <para>The <literal><key></literal> element is featured a few
+ times within this guide. It appears anywhere the parent mapping
+ element defines a join to a new table that references the primary key
+ of the original table. It also defines the foreign key in the joined
+ table:</para>
+
+ <programlistingco role="XML">
+ <areaspec>
+ <area coords="2" id="key1" />
+
+ <area coords="3" id="key2" />
+
+ <area coords="4" id="key3" />
+
+ <area coords="5" id="key4" />
+
+ <area coords="6" id="key5" />
+
+ <area coords="7" id="key6" />
+ </areaspec>
+
+ <programlisting><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 can 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 original table. It is 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>For systems where delete performance is important, we recommend
+ that all keys should be defined
+ <literal>on-delete="cascade"</literal>. Hibernate uses 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 association to a
+ non-nullable foreign key, you <emphasis>must</emphasis> declare the
+ key column using <literal><key
+ not-null="true"></literal>.</para>
+ </section>
+
+ <section id="mapping-declaration-import">
+ <title>Import</title>
+
+ <para>If your application has two persistent classes with the same
+ name, and you do not want to specify the fully qualified package name
+ in Hibernate queries, classes can be "imported" explicitly, rather
+ than relying upon <literal>auto-import="true"</literal>. You can also
+ import classes and interfaces that are not explicitly mapped:</para>
+
+ <programlisting role="XML"><import class="java.lang.Object" rename="Universe"/></programlisting>
+
+ <programlistingco role="XML">
+ <areaspec>
+ <area coords="2" id="import1" />
+
+ <area coords="3" id="import2" />
+ </areaspec>
+
+ <programlisting><import
+ class="ClassName"
+ rename="ShortName"
+/></programlisting>
+
+ <calloutlist>
+ <callout arearefs="import1">
+ <para><literal>class</literal>: the fully qualified class name
+ of any Java class.</para>
+ </callout>
+
+ <callout arearefs="import2">
+ <para><literal>rename</literal> (optional - defaults to the
+ unqualified class name): a name that can be used in the query
+ language.</para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <note>
+ <para>This feature is unique to hbm.xml and is not supported in
+ annotations.</para>
+ </note>
+ </section>
+
+ <section id="mapping-column" revision="5">
+ <title>Column and formula elements</title>
+
+ <para>Mapping elements which accept 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. For example:</para>
+
+ <programlisting role="XML"><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"
+ read="SQL expression"
+ write="SQL expression"/></programlisting>
+
+ <programlisting role="XML"><formula>SQL expression</formula></programlisting>
+
+ <para>Most of the attributes on <literal>column</literal> provide a
+ means of tailoring the DDL during automatic schema generation. The
+ <literal>read</literal> and <literal>write</literal> attributes allow
+ you to specify custom SQL that Hibernate will use to access the
+ column's value. For more on this, see the discussion of <link
+ linkend="mapping-column-read-and-write">column read and write
+ expressions</link>.</para>
+
+ <para>The <literal>column</literal> and <literal>formula</literal>
+ elements can even be combined within the same property or association
+ mapping to express, for example, exotic join conditions.</para>
+
+ <programlisting role="XML"><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>
+ </section>
</section>
</section>
More information about the hibernate-commits
mailing list