[hibernate-commits] Hibernate SVN: r11160 - in
branches/HAN_SPLIT/HibernateExt/search/doc/reference: en and
1 other directories.
hibernate-commits at lists.jboss.org
hibernate-commits at lists.jboss.org
Wed Feb 7 01:23:01 EST 2007
Author: epbernard
Date: 2007-02-07 01:23:00 -0500 (Wed, 07 Feb 2007)
New Revision: 11160
Added:
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/architecture.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/batchindex.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/configuration.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/mapping.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/query.xml
Removed:
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/entity.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/lucene.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/setup.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/validator.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/xml-overriding.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/fr/
branches/HAN_SPLIT/HibernateExt/search/doc/reference/zh_cn/
Modified:
branches/HAN_SPLIT/HibernateExt/search/doc/reference/build.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/master.xml
Log:
Search documentation
Modified: branches/HAN_SPLIT/HibernateExt/search/doc/reference/build.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/build.xml 2007-02-06 23:46:27 UTC (rev 11159)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/build.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -9,17 +9,9 @@
<!-- TRANSLATOR: Duplicate this call for your language -->
<antcall target="lang.all">
- <param name="docname" value="hibernate_annotations"/>
+ <param name="docname" value="hibernate_search"/>
<param name="lang" value="en"/>
</antcall>
- <antcall target="lang.all">
- <param name="docname" value="hibernate_annotations"/>
- <param name="lang" value="zh_cn"/>
- </antcall>
- <antcall target="lang.all">
- <param name="docname" value="hibernate_annotations"/>
- <param name="lang" value="fr"/>
- </antcall>
</target>
</project>
Modified: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/master.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/master.xml 2007-02-06 23:46:27 UTC (rev 11159)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/master.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -1,79 +1,57 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
-"../../../../../Hibernate3/doc/reference/support/docbook-dtd/docbookx.dtd" [
-<!ENTITY setup SYSTEM "modules/setup.xml">
-<!ENTITY entity SYSTEM "modules/entity.xml">
-<!ENTITY xml-overriding SYSTEM "modules/xml-overriding.xml">
-<!ENTITY validator SYSTEM "modules/validator.xml">
-<!ENTITY lucene SYSTEM "modules/lucene.xml">
-]>
+ "../../../../../Hibernate3/doc/reference/support/docbook-dtd/docbookx.dtd" [
+ <!ENTITY architecture SYSTEM "modules/architecture.xml">
+ <!ENTITY configuration SYSTEM "modules/configuration.xml">
+ <!ENTITY mapping SYSTEM "modules/mapping.xml">
+ <!ENTITY query SYSTEM "modules/query.xml">
+ <!ENTITY batchindex SYSTEM "modules/batchindex.xml">
+ ]>
<book lang="en">
<bookinfo>
- <title>Hibernate Annotations</title>
+ <title>Hibernate Search</title>
+ <subtitle>Apache <trademark>Lucene</trademark>
+ Integration</subtitle>
<subtitle>Reference Guide</subtitle>
- <releaseinfo>3.2.1.GA</releaseinfo>
+ <releaseinfo>3.2.2.beta1</releaseinfo>
<mediaobject>
<imageobject>
- <imagedata fileref="images/hibernate_logo_a.png" format="png" />
+ <imagedata fileref="images/hibernate_logo_a.png" format="png"/>
</imageobject>
</mediaobject>
</bookinfo>
<toc></toc>
- <preface id="preface" revision="1">
+ <preface id="preface" revision="2">
<title>Preface</title>
- <para>Hibernate, like all other object/relational mapping tools, requires
- metadata that governs the transformation of data from one representation
- to the other (and vice versa). In Hibernate 2.x, mapping metadata is most
- of the time declared in XML text files. Another option is XDoclet,
- utilizing Javadoc source code annotations and a preprocessor at compile
- time. The same kind of annotation support is now available in the standard
- JDK, although more powerful and better supported by tools. IntelliJ IDEA,
- and Eclipse for example, support auto-completion and syntax highlighting
- of JDK 5.0 annotations. Annotations are compiled into the bytecode and
- read at runtime (in Hibernate's case on startup) using reflection, so no
- external XML files are needed.</para>
+ <para>Full text search engines like <productname>Apache Lucene</productname>
+ are a very powerful technology to
+bring free text/efficient queries to applications. If suffers several mismatches
+when dealing with a object domain model (keeping the index up to date, mismatch
+between the index structure and the domain model, querying mismatch...)
+Hibernate Search indexes your domain model thanks to a few annotations, takes
+care of the database / index synchronization and brings you back regular managed
+objects from free text queries.
+Hibernate Search is using <ulink url="http://lucene.apache.org">Apache Lucene</ulink>
+under the cover.</para>
- <para>The EJB3 specification recognizes the interest and the success of
- the transparent object/relational mapping paradigm. The EJB3 specification
- standardizes the basic APIs and the metadata needed for any
- object/relational persistence mechanism. <emphasis>Hibernate
- EntityManager</emphasis> implements the programming interfaces and
- lifecycle rules as defined by the EJB3 persistence specification. Together
- with <emphasis>Hibernate Annotations</emphasis>, this wrapper implements a
- complete (and standalone) EJB3 persistence solution on top of the mature
- Hibernate core. You may use a combination of all three together,
- annotations without EJB3 programming interfaces and lifecycle, or even
- pure native Hibernate, depending on the business and technical needs of
- your project. You can at all times fall back to Hibernate native APIs, or
- if required, even to native JDBC and SQL.</para>
-
- <para>This release is based on the final release of the EJB 3.0 / JPA
- specification (aka JSP-220) and support all the specification features
- (including the optional ones). Most of the Hibernate features and
- extensions are also available through Hibernate specific annotations
- compared to the specification are also available. While the Hibernate
- feature coverage is now very high, some are still missing. The eventual
- goal is to cover all of them. See the JIRA road map section for more
- informations.</para>
-
- <para>If you are moving from previous Hibernate Annotations versions,
- please have a look at <uri>http://www.hibernate.org/371.html</uri> for a
- migration guide.</para>
+ <para>Hibernate Search is a work in progress and new features are cooking in
+ this area. So expect some compatibility changes in subsequent
+ versions.</para>
</preface>
- &setup;
+ &architecture;
- &entity;
+ &configuration;
- &xml-overriding;
+ &mapping;
- &validator;
+ &query;
- &lucene;
+ &batchindex;
</book>
\ No newline at end of file
Copied: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/architecture.xml (from rev 11154, branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/lucene.xml)
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/architecture.xml (rev 0)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/architecture.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<chapter id="search-architecture">
+ <title>Architecture</title>
+
+ <para>Hibernate Search is made of an indexing engine and an index search
+ engine. Both are backed by Apache Lucene.
+ </para>
+
+ <para>When an entity is inserted, updated or removed to/from the database,
+ <productname>Hibernate Search</productname>
+ will keep track of this event
+ (through the Hibernate event system) and schedule an index update. When
+ out of transaction, the update is executed right after the actual database
+ operation. It is however recommended, for both your database and Hibernate
+ Search, to execute your operation in a transaction (whether JDBC or JTA).
+ When in a transaction, the index update is schedule for the transaction
+ commit (and discarded in case of transaction rollback). You can think of
+ this as the regular (infamous) autocommit vs transactional behavior. From
+ a performance perspective, the
+ <emphasis>in transaction</emphasis>
+ mode is
+ recommended. All the index updates are handled for you without you having
+ to use the Apache Lucene APIs.
+ </para>
+
+ <para>To interact with Apache Lucene indexes, Hibernate Search has the
+ notion of
+ <classname>DirectoryProvider</classname>
+ . A directory provider
+ will manage a given Lucene
+ <classname>Directory</classname>
+ type. You can
+ configure directory providers to adjust the directory target.
+ </para>
+
+ <para>
+ <productname>Hibernate Search</productname>
+ can also use a Lucene
+ index to search an entity and return a (list of) managed entity saving you
+ from the tedious Object / Lucene Document mapping and low level Lucene
+ APIs. The application code use the unified
+ <classname>org.hibernate.Query</classname>
+ API exactly the way a HQL or
+ native query would be done.
+ </para>
+</chapter>
\ No newline at end of file
Copied: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/batchindex.xml (from rev 11154, branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/lucene.xml)
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/batchindex.xml (rev 0)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/batchindex.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="search-batchindex">
+ <title>Indexing</title>
+
+ <para>It is sometimes useful to index an object event if this object is not
+ inserted nor updated to the database. This is especially true when you want
+ to build your index the first time. You can achieve that goal using the
+ <classname>FullTextSession</classname> .</para>
+
+ <programlisting>FullTextSession fullTextSession = Search.createFullTextSession(session);
+Transaction tx = fullTextSession.beginTransaction();
+for (Customer customer : customers) {
+ <emphasis role="bold">fullTextSession.index(customer);</emphasis>
+}
+tx.commit(); //index are written at commit time </programlisting>
+
+ <para>For maximum efficiency, Hibernate Search batch index operations which
+ and execute them at commit time (Note: you don't need to use
+ <classname>org.hibernate.Transaction</classname> in a JTA
+ environment).</para>
+</chapter>
\ No newline at end of file
Copied: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/configuration.xml (from rev 11154, branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/lucene.xml)
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/configuration.xml (rev 0)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/configuration.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="search-configuration">
+ <title>Configuration</title>
+
+ <section id="search-configuration-directory" revision="1">
+ <title>Directory configuration</title>
+
+ <para>Apache Lucene has a notion of Directory where the index is stored.
+ The Directory implementation can be customized but Lucene comes bundled
+ with a file system and a full memory implementation.
+ <productname>Hibernate Search</productname> has the notion of
+ <literal>DirectoryProvider</literal> that handle the configuration and the
+ initialization of the Lucene Directory.</para>
+
+ <table>
+ <title>List of built-in Directory Providers</title>
+
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry align="center">Class</entry>
+
+ <entry align="center">description</entry>
+
+ <entry align="center">Properties</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>org.hibernate.search.store.FSDirectoryProvider</entry>
+
+ <entry>File system based directory. The directory used will be
+ <indexBase>/< <literal>@Indexed.name</literal>
+ ></entry>
+
+ <entry><literal>indexBase</literal> : Base directory</entry>
+ </row>
+
+ <row>
+ <entry>org.hibernate.search.store.RAMDirectoryProvider</entry>
+
+ <entry>Memory based directory, the directory will be uniquely
+ indentified by the <literal>@Indexed.name</literal>
+ element</entry>
+
+ <entry>none</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>If the built-in directory providers does not fit your needs, you can
+ write your own directory provider by implementing the
+ <classname>org.hibernate.store.DirectoryProvider</classname>
+ interface</para>
+
+ <para>Each indexed entity is associated to a Lucene index (an index can be
+ shared by several entities but this is not usually the case). You can
+ configure the index through properties prefixed by
+ <constant>hibernate.search.</constant>
+ <replaceable>indexname</replaceable> . Default properties inherited to all
+ indexes can be defined using the prefix
+ <constant>hibernate.search.default.</constant></para>
+
+ <para>To define the directory provider of a given index, you use the
+ <constant>hibernate.search. <replaceable>indexname</replaceable>
+ .directory_provider </constant></para>
+
+ <programlisting>hibernate.search.default.directory_provider org.hibernate.search.store.FSDirectoryProvider
+hibernate.search.default.indexBase=/usr/lucene/indexes
+
+hibernate.search.Rules.directory_provider org.hibernate.search.store.RAMDirectoryProvider </programlisting>
+
+ <para>applied on</para>
+
+ <programlisting>@Indexed(name="Status")
+public class Status { ... }
+
+ at Indexed(name="Rules")
+public class Rule { ... }
+ </programlisting>
+
+ <para>will create a file system directory in
+ <filename>/usr/lucene/indexes/Status</filename> where the Status entities
+ will be indexed, and use an in memory directory named
+ <literal>Rules</literal> where Rule entities will be indexed.</para>
+
+ <para>So you can easily defined common rules like the directory provider
+ and base directory, and overide those default later on on a per index
+ basis.</para>
+
+ <para>Writing your own <classname>DirectoryProvider</classname> , you can
+ benefit this configuration mechanism too.</para>
+ </section>
+
+ <section id="search-configuration-event" revision="1">
+ <title>Enabling automatic indexing</title>
+
+ <para>Finally, we enable the <literal>SearchEventListener</literal> for
+ the three Hibernate events that occur after changes are executed to the
+ database.</para>
+
+ <programlisting><hibernate-configuration>
+ ...
+ <event type="post-update"
+ <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
+ </event>
+ <event type="post-insert"
+ <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
+ </event>
+ <event type="post-delete"
+ <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
+ </event>
+</hibernate-configuration></programlisting>
+ </section>
+</chapter>
\ No newline at end of file
Deleted: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/entity.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/entity.xml 2007-02-06 23:46:27 UTC (rev 11159)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/entity.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -1,3432 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<chapter id="entity">
- <title>Entity Beans</title>
-
- <sect1 id="entity-overview" revision="1">
- <title>Intro</title>
-
- <para>This section covers EJB 3.0 (aka JPA) entity annotations and
- Hibernate-specific extensions.</para>
- </sect1>
-
- <sect1 id="entity-mapping" revision="2">
- <title>Mapping with EJB3/JPA Annotations</title>
-
- <para>EJB3 entities are plain POJOs. Actually they represent the exact
- same concept as the Hibernate persistent entities. Their mappings are
- defined through JDK 5.0 annotations (an XML descriptor syntax for
- overriding is defined in the EJB3 specification). Annotations can be split
- in two categories, the logical mapping annotations (allowing you to
- describe the object model, the class associations, etc.) and the physical
- mapping annotations (describing the physical schema, tables, columns,
- indexes, etc). We will mix annotations from both categories in the
- following code examples.</para>
-
- <para>EJB3 annotations are in the <literal>javax.persistence.*</literal>
- package. Most JDK 5 compliant IDE (like Eclipse, IntelliJ IDEA and
- Netbeans) can autocomplete annotation interfaces and attributes for you
- (even without a specific "EJB3" module, since EJB3 annotations are plain
- JDK 5 annotations).</para>
-
- <para>For more and runnable concrete examples read the JBoss EJB 3.0
- tutorial or review the Hibernate Annotations test suite. Most of the unit
- tests have been designed to represent a concrete example and be a
- inspiration source.</para>
-
- <sect2>
- <title>Declaring an entity bean</title>
-
- <para>Every bound persistent POJO class is an entity bean and is
- declared using the <literal>@Entity</literal> annotation (at the class
- level):</para>
-
- <programlisting>
- at Entity
-public class Flight implements Serializable {
- Long id;
-
- @Id
- public Long getId() { return id; }
-
- public void setId(Long id) { this.id = id; }
-}
- </programlisting>
-
- <para><literal>@Entity</literal> declares the class as an entity bean
- (i.e. a persistent POJO class), <literal>@Id</literal> declares the
- identifier property of this entity bean. The other mapping declarations
- are implicit. This configuration by exception concept is central to the
- new EJB3 specification and a major improvement. The class Flight is
- mapped to the Flight table, using the column id as its primary key
- column.</para>
-
- <para>Depending on whether you annotate fields or methods, the access
- type used by Hibernate will be <literal>field</literal> or
- <literal>property</literal>. The EJB3 spec requires that you declare
- annotations on the element type that will be accessed, i.e. the getter
- method if you use <literal>property</literal> access, the field if you
- use <literal>field</literal> access. Mixing EJB3 annotations in both
- fields and methods should be avoided. Hibernate will guess the access
- type from the position of <literal>@Id</literal> or
- <literal>@EmbeddedId</literal>.</para>
-
- <sect3>
- <title>Defining the table</title>
-
- <para><literal>@Table</literal> is set at the class level; it allows
- you to define the table, catalog, and schema names for your entity
- bean mapping. If no <literal>@Table</literal> is defined the default
- values are used: the unqualified class name of the entity.</para>
-
- <programlisting>
- at Entity
- at Table(name="tbl_sky")
-public class Sky implements Serializable {
-...
- </programlisting>
-
- <para>The <literal>@Table</literal> element also contains a
- <literal>schema</literal> and a <literal>catalog</literal> attributes,
- if they need to be defined. You can also define unique constraints to
- the table using the <literal>@UniqueConstraint</literal> annotation in
- conjunction with <literal>@Table</literal> (for a unique constraint
- bound to a single column, refer to <literal>@Column</literal>).</para>
-
- <programlisting>@Table(name="tbl_sky",
- <emphasis role="bold">uniqueConstraints = {@UniqueConstraint(columnNames={"month", "day"})}</emphasis>
-)</programlisting>
-
- <para>A unique constraint is applied to the tuple month, day. Note
- that the <literal>columnNames</literal> array refers to the logical
- column names.</para>
-
- <remark>The logical column name is defined by the Hibernate
- NamingStrategy implementation. The default EJB3 naming strategy use
- the physical column name as the logical column name. Note that this
- may be different than the property name (if the column name is
- explicit). Unless you override the NamingStrategy, you shouldn't worry
- about that.</remark>
- </sect3>
-
- <sect3>
- <title>Versioning for optimistic locking</title>
-
- <para>You can add optimistic locking capability to an entity bean
- using the <literal>@Version</literal> annotation:</para>
-
- <programlisting>
- at Entity
-public class Flight implements Serializable {
-...
- @Version
- @Column(name="OPTLOCK")
- public Integer getVersion() { ... }
-} </programlisting>
-
- <para>The version property will be mapped to the
- <literal>OPTLOCK</literal> column, and the entity manager will use it
- to detect conflicting updates (preventing lost updates you might
- otherwise see with the last-commit-wins strategy).</para>
-
- <para>The version column may be a numeric (the recommended solution)
- or a timestamp as per the EJB3 spec. Hibernate support any kind of
- type provided that you define and implement the appropriate
- <classname>UserVersionType</classname>.</para>
- </sect3>
- </sect2>
-
- <sect2>
- <title>Mapping simple properties</title>
-
- <sect3>
- <title>Declaring basic property mappings</title>
-
- <para>Every non static non transient property (field or method) of an
- entity bean is considered persistent, unless you annotate it as
- <literal>@Transient</literal>. Not having an annotation for your
- property is equivalent to the appropriate <literal>@Basic</literal>
- annotation. The <literal>@Basic</literal> annotation allows you to
- declare the fetching strategy for a property:</para>
-
- <programlisting>public transient int counter; //transient property
-
-private String firstname; //persistent property
-
- at Transient
-String getLengthInMeter() { ... } //transient property
-
-String getName() {... } // persistent property
-
- at Basic
-int getLength() { ... } // persistent property
-
- at Basic(fetch = FetchType.LAZY)
-String getDetailedComment() { ... } // persistent property
-
- at Temporal(TemporalType.TIME)
-java.util.Date getDepartureTime() { ... } // persistent property
-
- at Enumerated(STRING)
-Starred getNote() { ... } //enum persisted as String in database</programlisting>
-
- <para><literal>counter</literal>, a transient field, and
- <literal>lengthInMeter</literal>, a method annotated as
- <literal>@Transient</literal>, and will be ignored by the entity
- manager. <literal>name</literal>, <literal>length</literal>, and
- <literal>firstname</literal> properties are mapped persistent and
- eagerly fetched (the default for simple properties). The
- <literal>detailedComment</literal> property value will be lazily
- fetched from the database once a lazy property of the entity is
- accessed for the first time. Usually you don't need to lazy simple
- properties (not to be confused with lazy association fetching).</para>
-
- <note>
- <para>To enable property level lazy fetching, your classes have to
- be instrumented: bytecode is added to the original one to enable
- such feature, please refer to the Hibernate reference documentation.
- If your classes are not instrumented, property level lazy loading is
- silently ignored.</para>
- </note>
-
- <para>The recommended alternative is to use the projection capability
- of EJB-QL or Criteria queries.</para>
-
- <para>EJB3 support property mapping of all basic types supported by
- Hibernate (all basic Java types , their respective wrappers and
- serializable classes). Hibernate Annotations support out of the box
- Enum type mapping either into a ordinal column (saving the enum
- ordinal) or a string based column (saving the enum string
- representation): the persistence representation, defaulted to ordinal,
- can be overriden through the <literal>@Enumerated</literal> annotation
- as shown in the <literal>note</literal> property example.</para>
-
- <para>In core Java APIs, the temporal precision is not defined. When
- dealing with temporal data you might want to describe the expected
- precision in database. Temporal data can have <literal>DATE</literal>,
- <literal>TIME</literal>, or <literal>TIMESTAMP</literal> precision (ie
- the actual date, only the time, or both). Use the
- <literal>@Temporal</literal> annotation to fine tune that.</para>
-
- <para><literal>@Lob</literal> indicates that the property should be
- persisted in a Blob or a Clob depending on the property type:
- <classname>java.sql.Clob</classname>,
- <classname>Character[]</classname>, <classname>char[]</classname> and
- java.lang.<classname>String</classname> will be persisted in a Clob.
- <classname>java.sql.Blob</classname>, <classname>Byte[]</classname>,
- <classname>byte[] </classname>and serializable type will be persisted
- in a Blob.</para>
-
- <programlisting>
- at Lob
-public String getFullText() {
- return fullText;
-}
-
- at Lob
-public byte[] getFullCode() {
- return fullCode;
-}
- </programlisting>
-
- <para>If the property type implements
- <classname>java.io.Serializable</classname> and is not a basic type,
- and if the property is not annotated with <literal>@Lob</literal>,
- then the Hibernate <literal>serializable</literal> type is
- used.</para>
- </sect3>
-
- <sect3>
- <title>Declaring column attributes</title>
-
- <para>The column(s) used for a property mapping can be defined using
- the <literal>@Column</literal> annotation. Use it to override default
- values (see the EJB3 specification for more information on the
- defaults). You can use this annotation at the property level for
- properties that are:</para>
-
- <itemizedlist>
- <listitem>
- <para>not annotated at all</para>
- </listitem>
-
- <listitem>
- <para>annotated with <literal>@Basic</literal></para>
- </listitem>
-
- <listitem>
- <para>annotated with <literal>@Version</literal></para>
- </listitem>
-
- <listitem>
- <para>annotated with <literal>@Lob</literal></para>
- </listitem>
-
- <listitem>
- <para>annotated with <literal>@Temporal</literal></para>
- </listitem>
-
- <listitem>
- <para>annotated with
- <literal>@org.hibernate.annotations.CollectionOfElements</literal>
- (for Hibernate only)</para>
- </listitem>
- </itemizedlist>
-
- <programlisting>
- at Entity
-public class Flight implements Serializable {
-...
- at Column(updatable = false, name = "flight_name", nullable = false, length=50)
-public String getName() { ... }
- </programlisting>
-
- <para>The <literal>name</literal> property is mapped to the
- <literal>flight_name</literal> column, which is not nullable, has a
- length of 50 and is not updatable (making the property
- immutable).</para>
-
- <para>This annotation can be applied to regular properties as well as
- <literal>@Id</literal> or <literal>@Version</literal>
- properties.</para>
-
- <programlistingco>
- <areaspec>
- <area coords="2 55" id="hm1" />
-
- <area coords="3 55" id="hm2" />
-
- <area coords="4 55" id="hm3" />
-
- <area coords="5 55" id="hm4" />
-
- <area coords="6 55" id="hm5" />
-
- <area coords="7 55" id="hm6" />
-
- <area coords="8 55" id="hm7" />
-
- <area coords="9 55" id="hm8" />
-
- <area coords="10 55" id="hm9" />
-
- <area coords="11 55" id="hm10" />
- </areaspec>
-
- <programlisting>@Column(
- name="columnName";
- boolean unique() default false;
- boolean nullable() default true;
- boolean insertable() default true;
- boolean updatable() default true;
- String columnDefinition() default "";
- String table() default "";
- int length() default 255;
- int precision() default 0; // decimal precision
- int scale() default 0; // decimal scale</programlisting>
-
- <calloutlist>
- <callout arearefs="hm1">
- <para><literal>name</literal> (optional): the column name
- (default to the property name)</para>
- </callout>
-
- <callout arearefs="hm2">
- <para><literal>unique</literal> (optional): set a unique
- constraint on this column or not (default false)</para>
- </callout>
-
- <callout arearefs="hm3">
- <para><literal>nullable</literal> (optional): set the column as
- nullable (default false).</para>
- </callout>
-
- <callout arearefs="hm4">
- <para><literal>insertable</literal> (optional): whether or not
- the column will be part of the insert statement (default
- true)</para>
- </callout>
-
- <callout arearefs="hm5">
- <para><literal>updatable</literal> (optional): whether or not
- the column will be part of the update statement (default
- true)</para>
- </callout>
-
- <callout arearefs="hm6">
- <para><literal>columnDefinition</literal> (optional): override
- the sql DDL fragment for this particular column (non
- portable)</para>
- </callout>
-
- <callout arearefs="hm7">
- <para><literal>table</literal> (optional): define the targeted
- table (default primary table)</para>
- </callout>
-
- <callout arearefs="hm8">
- <para><literal><literal>length</literal></literal> (optional):
- column length (default 255)</para>
- </callout>
-
- <callout arearefs="hm8">
- <para><literal><literal>precision</literal></literal>
- (optional): column decimal precision (default 0)</para>
- </callout>
-
- <callout arearefs="hm10">
- <para><literal><literal>scale</literal></literal> (optional):
- column decimal scale if useful (default 0)</para>
- </callout>
- </calloutlist>
- </programlistingco>
- </sect3>
-
- <sect3>
- <title>Embedded objects (aka components)</title>
-
- <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>
- at 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>
- at Embeddable
-public class Address implements Serializable {
- String city;
- Country nationality; //no overriding here
-}
- </programlisting>
-
- <programlisting>
- at 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>A embeddable object inherit the access type of its owning entity
- (note that you can override that using the Hibernate specific
- <literal>@AccessType</literal> annotations (see <xref
- linkend="entity-hibspec" />).</para>
-
- <para>The <literal>Person</literal> entity bean 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 EJB3 defaults. Overriding
- columns of embedded objects of embedded objects is currently not
- supported in the EJB3 spec, however, Hibernate Annotations supports it
- through dotted expressions.</para>
-
- <para><programlisting> @Embedded
- @AttributeOverrides( {
- @AttributeOverride(name="city", column = @Column(name="fld_city") )
- @AttributeOverride(name="<emphasis role="bold">nationality.iso2</emphasis>", column = @Column(name="nat_Iso2") ),
- @AttributeOverride(name="<emphasis role="bold">nationality.name</emphasis>", column = @Column(name="nat_CountryName") )
- //nationality columns in homeAddress are overridden
- } )
- Address homeAddress;</programlisting>Hibernate Annotations supports one
- more feature that is not explicitly supported by the EJB3
- 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>While not supported by the EJB3 specification, Hibernate
- Annotations allows you to use association annotations in an embeddable
- object (ie <literal>@*ToOne</literal> nor
- <literal>@*ToMany</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: at least one of
- the columns will have to be explicit. Hibernate goes beyond the EJB3
- spec and allows you to enhance the defaulting mechanism through the
- <classname>NamingStrategy</classname>.
- <classname>DefaultComponentSafeNamingStrategy</classname> is a small
- improvement over the default EJB3NamingStrategy that allows embedded
- objects to be defaulted even if used twice in the same entity.</para>
- </sect3>
-
- <sect3>
- <title>Non-annotated property defaults</title>
-
- <para>If a property is not annotated, the following rules
- apply:</para>
-
- <itemizedlist>
- <listitem>
- If the property is of a single type, it is mapped as @Basic
- </listitem>
-
- <listitem>
- Otherwise, if the type of the property is annotated as @Embeddable, it is mapped as @Embedded
- </listitem>
-
- <listitem>
- Otherwise, if the type of the property is Serializable, it is mapped as @Basic in a column holding the object in its serialized version
- </listitem>
-
- <listitem>
- Otherwise, if the type of the property is java.sql.Clob or java.sql.Blob, it is mapped as @Lob with the appropriate LobType
- </listitem>
- </itemizedlist>
- </sect3>
- </sect2>
-
- <sect2 id="entity-mapping-identifier" label=""
- xreflabel="Mapping identifier properties">
- <title>Mapping identifier properties</title>
-
- <para>The <literal>@Id</literal> annotation lets you define which
- property is the identifier of your entity bean. This property can be set
- by the application itself or be generated by Hibernate (preferred). You
- can define the identifier generation strategy thanks to the
- <literal>@GeneratedValue</literal> annotation:</para>
-
- <itemizedlist>
- <listitem>
- AUTO - either identity column, sequence or table depending on the underlying DB
- </listitem>
-
- <listitem>
- TABLE - table holding the id
- </listitem>
-
- <listitem>
- IDENTITY - identity column
- </listitem>
-
- <listitem>
- SEQUENCE - sequence
- </listitem>
- </itemizedlist>
-
- <para>Hibernate provides more id generators than the basic EJB3 ones.
- Check <xref linkend="entity-hibspec" /> for more informations.</para>
-
- <para>The following example shows a sequence generator using the
- SEQ_STORE configuration (see below)</para>
-
- <programlisting>
- at Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE")
-public Integer getId() { ... }
- </programlisting>
-
- <para>The next example uses the identity generator:</para>
-
- <programlisting>
- at Id @GeneratedValue(strategy=GenerationType.IDENTITY)
-public Long getId() { ... }
- </programlisting>
-
- <para>The <literal>AUTO</literal> generator is the preferred type for
- portable applications (across several DB vendors). The identifier
- generation configuration can be shared for several
- <literal>@Id</literal> mappings with the generator attribute. There are
- several configurations available through
- <literal>@SequenceGenerator</literal> and
- <literal>@TableGenerator</literal>. The scope of a generator can be the
- application or the class. Class-defined generators are not visible
- outside the class and can override application level generators.
- Application level generators are defined at XML level (see <xref
- linkend="xml-overriding" />):</para>
-
- <programlisting><table-generator name="EMP_GEN"
- table="GENERATOR_TABLE"
- pk-column-name="key"
- value-column-name="hi"
- pk-column-value="EMP"
- allocation-size="20"/>
-
-//and the annotation equivalent
-
- at javax.persistence.TableGenerator(
- name="EMP_GEN",
- table="GENERATOR_TABLE",
- pkColumnName = "key",
- valueColumnName = "hi"
- pkColumnValue="EMP",
- allocationSize=20
-)
-
-<sequence-generator name="SEQ_GEN"
- sequence-name="my_sequence"
- allocation-size="20"/>
-
-//and the annotation equivalent
-
- at javax.persistence.SequenceGenerator(
- name="SEQ_GEN",
- sequenceName="my_sequence",
- allocationSize=20
-)
- </programlisting>
-
- <para>If JPA XML (like <filename>META-INF/orm.xml</filename>) is used to
- define thegenerators, <literal>EMP_GEN</literal> and
- <literal>SEQ_GEN</literal> are application level generators.
- <literal>EMP_GEN</literal> defines a table based id generator using the
- hilo algorithm with a <literal>max_lo</literal> of 20. The hi value is
- kept in a <literal>table</literal> "<literal>GENERATOR_TABLE</literal>".
- The information is kept in a row where <literal>pkColumnName</literal>
- "key" is equals to <literal>pkColumnValue</literal>
- "<literal>EMP</literal>" and column <literal>valueColumnName</literal>
- "<literal>hi</literal>" contains the the next high value used.</para>
-
- <para><literal>SEQ_GEN</literal> defines a sequence generator using a
- sequence named <literal>my_sequence</literal>. The allocation size used
- for this sequence based hilo algorithm is 20. Note that this version of
- Hibernate Annotations does not handle <literal>initialValue</literal> in
- the sequence generator. The default allocation size is 50, so if you
- want to use a sequence and pickup the value each time, you must set the
- allocation size to 1.</para>
-
- <note>
- <para>Package level definition is no longer supported by the EJB 3.0
- specification. However, you can use the
- <literal>@GenericGenerator</literal> at the package level (see <xref
- linkend="entity-hibspec-identifier" />).</para>
- </note>
-
- <para>The next example shows the definition of a sequence generator in a
- class scope:</para>
-
- <programlisting>
- at Entity
- at javax.persistence.SequenceGenerator(
- name="SEQ_STORE",
- sequenceName="my_sequence"
-)
-public class Store implements Serializable {
- private Long id;
-
- @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE")
- public Long getId() { return id; }
-}
- </programlisting>
-
- <para>This class will use a sequence named my_sequence and the SEQ_STORE
- generator is not visible in other classes. Note that you can check the
- Hibernate Annotations tests in the org.hibernate.test.metadata.id
- package for more examples.</para>
-
- <para>You can define a composite primary key through several
- syntaxes:</para>
-
- <itemizedlist>
- <listitem>
- annotate the component property as @Id and make the component class @Embeddable
- </listitem>
-
- <listitem>
- annotate the component property as @EmbeddedId
- </listitem>
-
- <listitem>
- annotate the class as @IdClass and annotate each property of the entity involved in the primary key with @Id
- </listitem>
- </itemizedlist>
-
- <para>While quite common to the EJB2 developer,
- <literal>@IdClass</literal> is likely new for Hibernate users. The
- composite primary key class corresponds to multiple fields or properties
- of the entity class, and the names of primary key fields or properties
- in the primary key class and those of the entity class must match and
- their types must be the same. Let's look at an example:</para>
-
- <programlisting>@Entity
-<emphasis role="bold">@IdClass(FootballerPk.class)</emphasis>
-public class Footballer {
- //part of the id key
- <emphasis role="bold">@Id</emphasis> public String getFirstname() {
- return firstname;
- }
-
- public void setFirstname(String firstname) {
- this.firstname = firstname;
- }
-
- //part of the id key
- <emphasis role="bold">@Id</emphasis> public String getLastname() {
- return lastname;
- }
-
- public void setLastname(String lastname) {
- this.lastname = lastname;
- }
-
- public String getClub() {
- return club;
- }
-
- public void setClub(String club) {
- this.club = club;
- }
-
- //appropriate equals() and hashCode() implementation
-}
-
- at Embeddable
-public class FootballerPk implements Serializable {
- //same name and type as in Footballer
- public String getFirstname() {
- return firstname;
- }
-
- public void setFirstname(String firstname) {
- this.firstname = firstname;
- }
-
- //same name and type as in Footballer
- public String getLastname() {
- return lastname;
- }
-
- public void setLastname(String lastname) {
- this.lastname = lastname;
- }
-
- //appropriate equals() and hashCode() implementation
-}
-</programlisting>
-
- <para>As you may have seen, <literal>@IdClass</literal> points to the
- corresponding primary key class.</para>
-
- <para>While not supported by the EJB3 specification, Hibernate allows
- you to define associations inside a composite identifier. Simply use the
- regular annotations for that</para>
-
- <programlisting>@Entity
- at AssociationOverride( name="id.channel", joinColumns = @JoinColumn(name="chan_id") )
-public class TvMagazin {
- @EmbeddedId public TvMagazinPk id;
- @Temporal(TemporalType.TIME) Date time;
-}
-
- at Embeddable
-public class TvMagazinPk implements Serializable {
- @ManyToOne
- public Channel channel;
- public String name;
- @ManyToOne
- public Presenter presenter;
-}
-</programlisting>
- </sect2>
-
- <sect2>
- <title>Mapping inheritance</title>
-
- <para>EJB3 supports the three types of inheritance:</para>
-
- <itemizedlist>
- <listitem>
- Table per Class Strategy: the <union-class> element in Hibernate
- </listitem>
-
- <listitem>
- Single Table per Class Hierarchy Strategy: the <subclass> element in Hibernate
- </listitem>
-
- <listitem>
- Joined Subclass Strategy: the <joined-subclass> element in Hibernate
- </listitem>
- </itemizedlist>
-
- <para>The chosen strategy is declared at the class level of the top
- level entity in the hierarchy using the <literal>@Inheritance</literal>
- annotation.</para>
-
- <note>
- <para>Annotating interfaces is currently not supported.</para>
- </note>
-
- <sect3>
- <title>Table per class</title>
-
- <para>This strategy has many drawbacks (esp. with polymorphic queries
- and associations) explained in the EJB3 spec, the Hibernate reference
- documentation, Hibernate in Action, and many other places. Hibernate
- work around most of them implementing this strategy using <literal>SQL
- UNION</literal> queries. It is commonly used for the top level of an
- inheritance hierarchy:</para>
-
- <programlisting>
- at Entity
- at Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
-public class Flight implements Serializable {
- </programlisting>
-
- <para>This strategy support one to many associations provided that
- they are bidirectional. This strategy does not support the
- <literal>IDENTITY</literal> generator strategy: the id has to be
- shared across several tables. Consequently, when using this strategy,
- you should not use <literal>AUTO </literal>nor
- <literal>IDENTITY</literal>.</para>
- </sect3>
-
- <sect3>
- <title>Single table per class hierarchy</title>
-
- <para>All properties of all super- and subclasses are mapped into the
- same table, instances are distinguished by a special discriminator
- column:</para>
-
- <programlisting>
- at 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><classname>Plane</classname> is the superclass, it defines the
- inheritance strategy <literal>InheritanceType.SINGLE_TABLE</literal>.
- It also defines the discriminator column through the
- <literal>@DiscriminatorColumn</literal> annotation, a discriminator
- column can also define the discriminator type. Finally, the
- <literal>@DiscriminatorValue</literal> annotation defines the value
- used to differentiate a class in the hierarchy. All of these
- attributes have sensible default values. The default name of the
- discriminator column is <literal>DTYPE</literal>. The default
- discriminator value is the entity name (as defined in
- <literal>@Entity.name</literal>) for DiscriminatorType.STRING.
- <classname>A320</classname> is a subclass; you only have to define
- discriminator value if you don't want to use the default value. The
- strategy and the discriminator type are implicit.</para>
-
- <para><literal>@Inheritance</literal> and
- <literal>@DiscriminatorColumn</literal> should only be defined at the
- top of the entity hierarchy.</para>
- </sect3>
-
- <sect3>
- <title>Joined subclasses</title>
-
- <para>The<literal> @PrimaryKeyJoinColumn</literal> and
- <literal>@PrimaryKeyJoinColumns</literal> annotations define the
- primary key(s) of the joined subclass table:</para>
-
- <programlisting>
- at Entity
- at Inheritance(strategy=InheritanceType.JOINED)
-public class Boat implements Serializable { ... }
-
- at Entity
-public class Ferry extends Boat { ... }
-
- at Entity
- at PrimaryKeyJoinColumn(name="BOAT_ID")
-public class AmericaCupClass extends Boat { ... }
- </programlisting>
-
- <para>All of the above entities use the <literal>JOINED</literal>
- strategy, the <literal>Ferry</literal> table is joined with the
- <literal>Boat</literal> table using the same primary key names. The
- <literal>AmericaCupClass</literal> table is joined with
- <literal>Boat</literal> using the join condition <code>Boat.id =
- AmericaCupClass.BOAT_ID</code>.</para>
- </sect3>
-
- <sect3>
- <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>@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 access type (field or methods), is inherited from the root
- entity, unless you use the Hibernate annotation
- <literal>@AccessType</literal></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>@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>
- </sect3>
- </sect2>
-
- <sect2 id="entity-mapping-association">
- <title>Mapping entity bean associations/relationships</title>
-
- <sect3>
- <title>One-to-one</title>
-
- <para>You can associate entity beans through a one-to-one relationship
- using <literal>@OneToOne</literal>. There are three cases for
- one-to-one associations: either the associated entities share the same
- primary keys values, a foreign key is held by one of the entities
- (note that this FK column in the database should be constrained unique
- to simulate one-to-one multiplicity), or a association table is used
- to store the link between the 2 entities (a unique constraint has to
- be defined on each fk to ensure the one to one multiplicity)</para>
-
- <para>First, we map a real one-to-one association using shared primary
- keys:</para>
-
- <programlisting>
- at Entity
-public class Body {
- @Id
- public Long getId() { return id; }
-
- @OneToOne(cascade = CascadeType.ALL)
- @PrimaryKeyJoinColumn
- public Heart getHeart() {
- return heart;
- }
- ...
-}
- </programlisting>
-
- <programlisting>
- at Entity
-public class Heart {
- @Id
- public Long getId() { ...}
-}
- </programlisting>
-
- <para>The one to one is marked as true by using the
- <literal>@PrimaryKeyJoinColumn</literal> annotation.</para>
-
- <para>In the following example, the associated entities are linked
- through a foreign key column:</para>
-
- <programlisting>
- at Entity
-public class Customer implements Serializable {
- @OneToOne(cascade = CascadeType.ALL)
- <emphasis role="bold">@JoinColumn(name="passport_fk")</emphasis>
- public Passport getPassport() {
- ...
- }
-
- at Entity
-public class Passport implements Serializable {
- @OneToOne(<emphasis role="bold">mappedBy = "passport"</emphasis>)
- public Customer getOwner() {
- ...
-}
- </programlisting>
-
- <para>A <classname>Customer</classname> is linked to a
- <classname>Passport</classname>, with a foreign key column named
- <literal>passport_fk</literal> in the <literal>Customer</literal>
- table. The join column is declared with the
- <literal>@JoinColumn</literal> annotation which looks like the
- <literal>@Column</literal> annotation. It has one more parameters
- named <literal>referencedColumnName</literal>. This parameter declares
- the column in the targeted entity that will be used to the join. Note
- that when using
- <literal><literal>referencedColumnName</literal></literal> to a non
- primary key column, the associated class has to be
- <classname>Serializable</classname>. Also note that the
- <literal><literal>referencedColumnName</literal></literal> to a non
- primary key column has to be mapped to a property having a single
- column (other cases might not work).</para>
-
- <para>The association may be bidirectional. In a bidirectional
- relationship, one of the sides (and only one) has to be the owner: the
- owner is responsible for the association column(s) update. To declare
- a side as <emphasis>not</emphasis> responsible for the relationship,
- the attribute <literal>mappedBy</literal> is used.
- <literal>mappedBy</literal> refers to the property name of the
- association on the owner side. In our case, this is
- <literal>passport</literal>. As you can see, you don't have to (must
- not) declare the join column since it has already been declared on the
- owners side.</para>
-
- <para>If no <literal>@JoinColumn</literal> is declared on the owner
- side, the defaults apply. A join column(s) will be created in the
- owner table and its name will be the concatenation of the name of the
- relationship in the owner side, <keycap>_</keycap> (underscore), and
- the name of the primary key column(s) in the owned side. In this
- example <literal>passport_id</literal> because the property name is
- <literal>passport</literal> and the column id of <literal>Passport
- </literal>is <literal>id</literal>.</para>
-
- <para>The third possibility (using an association table) is very
- exotic.</para>
-
- <programlisting>
- at Entity
-public class Customer implements Serializable {
- @OneToOne(cascade = CascadeType.ALL)
- <emphasis role="bold">@JoinTable(name = "CustomerPassports"
- joinColumns = @JoinColumn(name="customer_fk"),
- inverseJoinColumns = @JoinColumns(name="passport_fk")</emphasis>
- )
- public Passport getPassport() {
- ...
- }
-
- at Entity
-public class Passport implements Serializable {
- @OneToOne(<emphasis role="bold">mappedBy = "passport"</emphasis>)
- public Customer getOwner() {
- ...
-}
- </programlisting>
-
- <para>A <classname>Customer</classname> is linked to a
- <classname>Passport</classname> through a association table named
- <literal>CustomerPassports</literal> ; this association table has a
- foreign key column named <literal>passport_fk</literal> pointing to
- the <literal>Passport</literal> table (materialized by the
- <literal>inverseJoinColumn</literal>, and a foreign key column named
- <literal>customer_fk</literal> pointing to the
- <literal>Customer</literal> table materialized by the
- <literal>joinColumns</literal> attribute.</para>
-
- <para>You must declare the join table name and the join columns
- explicitly in such a mapping.</para>
- </sect3>
-
- <sect3>
- <title>Many-to-one</title>
-
- <para>Many-to-one associations are declared at the property level with
- the annotation <literal>@ManyToOne</literal>:</para>
-
- <programlisting>
- at Entity()
-public class Flight implements Serializable {
- <emphasis role="bold">@ManyToOne</emphasis>( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
- @JoinColumn(name="COMP_ID")
- public Company getCompany() {
- return company;
- }
- ...
-}
- </programlisting>
-
- <para>The <literal>@JoinColumn</literal> attribute is optional, the
- default value(s) is like in one to one, the concatenation of the name
- of the relationship in the owner side, <keycap>_</keycap>
- (underscore), and the name of the primary key column in the owned
- side. In this example <literal>company_id</literal> because the
- property name is <literal>company</literal> and the column id of
- Company is <literal>id</literal>.</para>
-
- <para><literal>@ManyToOne</literal> has a parameter named
- <literal>targetEntity</literal> which describes the target entity
- name. You usually don't need this parameter since the default value
- (the type of the property that stores the association) is good in
- almost all cases. However this is useful when you want to use
- interfaces as the return type instead of the regular entity.</para>
-
- <programlisting>
- at Entity()
-public class Flight implements Serializable {
- @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, <emphasis
- role="bold">targetEntity=CompanyImpl.class</emphasis> )
- @JoinColumn(name="COMP_ID")
- public Company getCompany() {
- return company;
- }
- ...
-}
-
-public interface Company {
- ...
- </programlisting>
-
- <para>You can alse map a many to one association through an
- association table. This association table described by the
- <literal>@JoinTable</literal> annotation will contains a foreign key
- referencing back the entity table (through
- <literal>@JoinTable.joinColumns</literal>) and a a foreign key
- referencing the target entity table (through
- <literal>@JoinTable.inverseJoinColumns</literal>).</para>
-
- <programlisting>
- at Entity()
-public class Flight implements Serializable {
- @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
- <emphasis role="bold">@JoinTable(name="Flight_Company",
- joinColumns = @JoinColumn(name="FLIGHT_ID"),
- inverseJoinColumns = @JoinColumns(name="COMP_ID")
- )</emphasis>
- public Company getCompany() {
- return company;
- }
- ...
-}
- </programlisting>
- </sect3>
-
- <sect3 id="entity-mapping-association-collections" revision="1">
- <title>Collections</title>
-
- <sect4 id="entity-mapping-association-collections-overview"
- revision="1">
- <title>Overview</title>
-
- <para>You can map <classname>Collection</classname>,
- <literal>List</literal> (ie ordered lists, not indexed lists),
- <literal>Map</literal> and <classname>Set</classname>. The EJB3
- specification describes how to map an ordered list (ie a list
- ordered at load time) using
- <literal>@javax.persistence.OrderBy</literal> annotation: this
- annotation takes into parameter a list of comma separated (target
- entity) properties to order the collection by (eg <code>firstname
- asc, age desc</code>), if the string is empty, the collection will
- be ordered by id. For true indexed
- collections, please refer to the <xref linkend="entity-hibspec" />.
- EJB3 allows you to map Maps using as a key one of the target entity
- property using <literal>@MapKey(name="myProperty")</literal>
- (myProperty is a property name in the target entity). When using
- <literal>@MapKey</literal> (without property name), the target
- entity primary key is used. The map key uses the same column as the
- property pointed out: there is no additional column defined to hold
- the map key, and it does make sense since the map key actually
- represent a target property. Be aware that once loaded, the key is
- no longer kept in sync with the property, in other words, if you
- change the property value, the key will not change automatically in
- your Java model (for true map support please refers to <xref
- linkend="entity-hibspec" />). Many people confuse
- <literal><map></literal> capabilities and
- <literal>@MapKey</literal> ones. These are two different features.
- <literal>@MapKey</literal> still has some limitations, please check
- the forum or the JIRA tracking system for more informations.</para>
-
- <para>Hibernate has several notions of collections.</para>
-
- <para></para>
-
- <table>
- <title>Collections semantics</title>
-
- <tgroup cols="3">
- <colspec colname="c1" />
-
- <colspec colname="c2" />
-
- <colspec colname="c3" colnum="2" />
-
- <thead>
- <row>
- <entry>Semantic</entry>
-
- <entry>java representation</entry>
-
- <entry>annotations</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>Bag semantic</entry>
-
- <entry>java.util.List, java.util.Collection</entry>
-
- <entry>@org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany</entry>
- </row>
-
- <row>
- <entry>Bag semantic with primary key (withtout the
- limitations of Bag semantic)</entry>
-
- <entry>java.util.List, java.util.Collection</entry>
-
- <entry>(@org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany) and @CollectionId</entry>
- </row>
-
- <row>
- <entry>List semantic</entry>
-
- <entry>java.util.List</entry>
-
- <entry>(@org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany) and
- @org.hibernate.annotations.IndexColumn</entry>
- </row>
-
- <row>
- <entry>Set semantic</entry>
-
- <entry>java.util.Set</entry>
-
- <entry>@org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany</entry>
- </row>
-
- <row>
- <entry>Map semantic</entry>
-
- <entry>java.util.Map</entry>
-
- <entry>(@org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany) and (nothing or
- @org.hibernate.annotations.MapKey/MapKeyManyToMany for true
- map support, OR @javax.persistence.MapKey</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <remark>So specifically, java.util.List collections without
- @org.hibernate.annotations.IndexColumn are going to be considered as
- bags.</remark>
-
- <para>Collection of primitive, core type or embedded objects is not
- supported by the EJB3 specification. Hibernate Annotations allows
- them however (see <xref linkend="entity-hibspec" />).</para>
-
- <programlisting>@Entity public class City {
- @OneToMany(mappedBy="city")
- <emphasis role="bold">@OrderBy("streetName")</emphasis>
- public List<Street> getStreets() {
- return streets;
- }
-...
-}
-
- at Entity public class Street {
- <emphasis role="bold">public String getStreetName()</emphasis> {
- return streetName;
- }
-
- @ManyToOne
- public City getCity() {
- return city;
- }
- ...
-}
-
-
- at Entity
-public class Software {
- @OneToMany(mappedBy="software")
- <emphasis role="bold">@MapKey(name="codeName")</emphasis>
- public Map<String, Version> getVersions() {
- return versions;
- }
-...
-}
-
- at Entity
- at Table(name="tbl_version")
-public class Version {
- <emphasis role="bold">public String getCodeName()</emphasis> {...}
-
- @ManyToOne
- public Software getSoftware() { ... }
-...
-}</programlisting>
-
- <para>So <literal>City</literal> has a collection of
- <literal>Street</literal>s that are ordered by
- <literal>streetName</literal> (of <literal>Street</literal>) when
- the collection is loaded. <literal>Software</literal> has a map of
- <literal>Version</literal>s which key is the
- <literal>Version</literal> <literal>codeName</literal>.</para>
-
- <para>Unless the collection is a generic, you will have to define
- <literal>targetEntity</literal>. This is a annotation attribute that
- take the target entity class as a value.</para>
- </sect4>
-
- <sect4 id="entity-mapping-association-collection-onetomany"
- revision="2">
- <title>One-to-many</title>
-
- <para>One-to-many associations are declared at the property level
- with the annotation <literal>@OneToMany</literal>. One to many
- associations may be bidirectional.</para>
-
- <sect5>
- <title>Bidirectional</title>
-
- <para>Since many to one are (almost) always the owner side of a
- bidirectional relationship in the EJB3 spec, the one to many
- association is annotated by <literal>@OneToMany( mappedBy=...
- )</literal></para>
-
- <programlisting>@Entity
-public class Troop {
- @OneToMany(mappedBy="troop")
- public Set<Soldier> getSoldiers() {
- ...
-}
-
- at Entity
-public class Soldier {
- @ManyToOne
- @JoinColumn(name="troop_fk")
- public Troop getTroop() {
- ...
-} </programlisting>
-
- <para><classname>Troop</classname> has a bidirectional one to many
- relationship with <literal>Soldier</literal> through the
- <literal>troop</literal> property. You don't have to (must not)
- define any physical mapping in the <literal>mappedBy</literal>
- side.</para>
-
- <para>To map a bidirectional one to many, with the one-to-many
- side as the owning side, you have to remove the
- <literal>mappedBy</literal> element and set the many to one
- <literal>@JoinColumn</literal> as insertable and updatable to
- false. This solution is obviously not optimized and will produce
- some additional UPDATE statements.</para>
-
- <programlisting>@Entity
-public class Troop {
- @OneToMany
- @JoinColumn(name="troop_fk") //we need to duplicate the physical information
- public Set<Soldier> getSoldiers() {
- ...
-}
-
- at Entity
-public class Soldier {
- @ManyToOne
- @JoinColumn(name="troop_fk", insertable=false, updatable=false)
- public Troop getTroop() {
- ...
-}</programlisting>
- </sect5>
-
- <sect5>
- <title>Unidirectional</title>
-
- <para>A unidirectional one to many using a foreign key column in
- the owned entity is not that common and not really recommended. We
- strongly advise you to use a join table for this kind of
- association (as explained in the next section). This kind of
- association is described through a
- <literal>@JoinColumn</literal></para>
-
- <programlisting>
- at Entity
-public class Customer implements Serializable {
- @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
- @JoinColumn(name="CUST_ID")
- public Set<Ticket> getTickets() {
- ...
-}
-
- at Entity
-public class Ticket implements Serializable {
- ... //no bidir
-}
- </programlisting>
-
- <para><literal>Customer</literal> describes a unidirectional
- relationship with <literal>Ticket</literal> using the join column
- <literal>CUST_ID</literal>.</para>
- </sect5>
-
- <sect5>
- <title>Unidirectional with join table</title>
-
- <para>A unidirectional one to many with join table is much
- preferred. This association is described through an
- <literal>@JoinTable</literal>.</para>
-
- <programlisting>
- at Entity
-public class Trainer {
- @OneToMany
- @JoinTable(
- name="TrainedMonkeys",
- joinColumns = { @JoinColumn( name="trainer_id") },
- inverseJoinColumns = @JoinColumn( name="monkey_id")
- )
- public Set<Monkey> getTrainedMonkeys() {
- ...
-}
-
- at Entity
-public class Monkey {
- ... //no bidir
-}
- </programlisting>
-
- <para><literal>Trainer</literal> describes a unidirectional
- relationship with <classname>Monkey</classname> using the join
- table <classname>TrainedMonkeys</classname>, with a foreign key
- <literal>trainer_id</literal> to <literal>Trainer</literal>
- (<literal>joinColumns</literal>) and a foreign key
- <literal>monkey_id</literal> to <literal>Monkey</literal>
- (<literal>inversejoinColumns</literal>).</para>
- </sect5>
-
- <sect5 id="entity-mapping-association-collection-manytomany-default"
- revision="1">
- <title>Defaults</title>
-
- <para>Without describing any physical mapping, a unidirectional
- one to many with join table is used. The table name is the
- concatenation of the owner table name, <keycap>_</keycap>, and the
- other side table name. The foreign key name(s) referencing the
- owner table is the concatenation of the owner table,
- <keycap>_</keycap>, and the owner primary key column(s) name. The
- foreign key name(s) referencing the other side is the
- concatenation of the owner property name, <keycap>_</keycap>, and
- the other side primary key column(s) name. A unique constraint is
- added to the foreign key referencing the other side table to
- reflect the one to many.</para>
-
- <programlisting>
- at Entity
-public class Trainer {
- @OneToMany
- public Set<Tiger> getTrainedTigers() {
- ...
-}
-
- at Entity
-public class Tiger {
- ... //no bidir
-}
- </programlisting>
-
- <para><classname>Trainer</classname> describes a unidirectional
- relationship with <classname>Tiger</classname> using the join
- table <literal>Trainer_Tiger</literal>, with a foreign key
- <literal>trainer_id</literal> to <literal>Trainer</literal> (table
- name, <keycap>_</keycap>, trainer id) and a foreign key
- <literal>trainedTigers_id</literal> to <literal>Monkey</literal>
- (property name, <keycap>_</keycap>, Tiger primary column).</para>
- </sect5>
- </sect4>
-
- <sect4 id="eentity-mapping-association-collection-manytomany"
- revision="">
- <title>Many-to-many</title>
-
- <sect5>
- <title>Definition</title>
-
- <para>A many-to-many association is defined logically using the
- <literal>@ManyToMany</literal> annotation. You also have to
- describe the association table and the join conditions using the
- <literal>@JoinTable</literal> annotation. If the association is
- bidirectional, one side has to be the owner and one side has to be
- the inverse end (ie. it will be ignored when updating the
- relationship values in the association table):</para>
-
- <programlisting>
- at Entity
-public class Employer implements Serializable {
- @ManyToMany(
- targetEntity=org.hibernate.test.metadata.manytomany.Employee.class,
- cascade={CascadeType.PERSIST, CascadeType.MERGE}
- )
- @JoinTable(
- name="EMPLOYER_EMPLOYEE",
- joinColumns={@JoinColumn(name="EMPER_ID")},
- inverseJoinColumns={@JoinColumn(name="EMPEE_ID")}
- )
- public Collection getEmployees() {
- return employees;
- }
- ...
-}
- </programlisting>
-
- <programlisting>
- at Entity
-public class Employee implements Serializable {
- @ManyToMany(
- cascade={CascadeType.PERSIST, CascadeType.MERGE},
- mappedBy="employees"
- targetEntity=Employer.class
- )
- public Collection getEmployers() {
- return employers;
- }
-}
- </programlisting>
-
- <para>We've already shown the many declarations and the detailed
- attributes for associations. We'll go deeper in the
- <literal>@JoinTable</literal> description, it defines a
- <literal>name</literal>, an array of join columns (an array in
- annotation is defined using { A, B, C }), and an array of inverse
- join columns. The latter ones are the columns of the association
- table which refer to the <classname>Employee</classname> primary
- key (the "other side").</para>
-
- <para>As seen previously, the other side don't have to (must not)
- describe the physical mapping: a simple
- <literal>mappedBy</literal> argument containing the owner side
- property name bind the two.</para>
- </sect5>
-
- <sect5>
- <title>Default values</title>
-
- <para>As any other annotations, most values are guessed in a many
- to many relationship. Without describing any physical mapping in a
- unidirectional many to many the following rules applied. The table
- name is the concatenation of the owner table name,
- <keycap>_</keycap> and the other side table name. The foreign key
- name(s) referencing the owner table is the concatenation of the
- owner table name, <keycap>_</keycap> and the owner primary key
- column(s). The foreign key name(s) referencing the other side is
- the concatenation of the owner property name, <keycap>_</keycap>,
- and the other side primary key column(s). These are the same rules
- used for a unidirectional one to many relationship.</para>
-
- <programlisting>
- at Entity
-public class Store {
- @ManyToMany(cascade = CascadeType.PERSIST)
- public Set<City> getImplantedIn() {
- ...
- }
-}
-
- at Entity
-public class City {
- ... //no bidirectional relationship
-}
- </programlisting>
-
- <para>A <literal>Store_City</literal> is used as the join table.
- The <literal>Store_id</literal> column is a foreign key to the
- <literal>Store</literal> table. The
- <literal>implantedIn_id</literal> column is a foreign key to the
- <literal>City</literal> table.</para>
-
- <para>Without describing any physical mapping in a bidirectional
- many to many the following rules applied. The table name is the
- concatenation of the owner table name, <keycap>_</keycap> and the
- other side table name. The foreign key name(s) referencing the
- owner table is the concatenation of the other side property name,
- <keycap>_</keycap>, and the owner primary key column(s). The
- foreign key name(s) referencing the other side is the
- concatenation of the owner property name, <keycap>_</keycap>, and
- the other side primary key column(s). These are the same rules
- used for a unidirectional one to many relationship.</para>
-
- <programlisting>
- at Entity
-public class Store {
- @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
- public Set<Customer> getCustomers() {
- ...
- }
-}
-
- at Entity
-public class Customer {
- @ManyToMany(mappedBy="customers")
- public Set<Store> getStores() {
- ...
- }
-}
- </programlisting>
-
- <para>A <literal>Store_Customer</literal> is used as the join
- table. The <literal>stores_id</literal> column is a foreign key to
- the <literal>Store</literal> table. The
- <literal>customers_id</literal> column is a foreign key to the
- <literal>Customer</literal> table.</para>
- </sect5>
- </sect4>
- </sect3>
-
- <sect3>
- <title>Transitive persistence with cascading</title>
-
- <para>You probably have noticed the <literal>cascade</literal>
- attribute taking an array of <classname>CascadeType</classname> as a
- value. The cascade concept in EJB3 is very is similar to the
- transitive persistence and cascading of operations in Hibernate, but
- with slightly different semantics and cascading types:</para>
-
- <itemizedlist>
- <listitem>
- CascadeType.PERSIST: cascades the persist (create) operation to associated entities persist() is called or if the entity is managed
- </listitem>
-
- <listitem>
- CascadeType.MERGE: cascades the merge operation to associated entities if merge() is called or if the entity is managed
- </listitem>
-
- <listitem>
- CascadeType.REMOVE: cascades the remove operation to associated entities if delete() is called
- </listitem>
-
- <listitem>
- CascadeType.REFRESH: cascades the refresh operation to associated entities if refresh() is called
- </listitem>
-
- <listitem>
- CascadeType.ALL: all of the above
- </listitem>
- </itemizedlist>
-
- <para>Please refer to the chapter 6.3 of the EJB3 specification for
- more information on cascading and create/merge semantics.</para>
- </sect3>
-
- <sect3 id="entity-mapping-association-fetching" revision="1">
- <title>Association fetching</title>
-
- <para>You have the ability to either eagerly or lazily fetch
- associated entities. The <literal>fetch</literal> parameter can be set
- to <literal>FetchType.LAZY</literal> or
- <literal>FetchType.EAGER</literal>. <literal>EAGER</literal> will try
- to use an outer join select to retrieve the associated object, while
- <literal>LAZY</literal> will only trigger a select when the associated
- object is accessed for the first time. <literal>@OneToMany</literal>
- and <literal>@ManyToMany</literal> associations are defaulted to
- <literal>LAZY</literal> and <literal>@OneToOne</literal> and
- <literal>@ManyToOne</literal> are defaulted to
- <literal>EAGER</literal>. For more information about static fetching,
- check <xref linkend="entity-hibspec-singleassoc-fetching" />.</para>
-
- <para>The recommanded approach is to use <literal>LAZY</literal> onn
- all static fetching definitions and override this choice dynamically
- through JPA-QL. JPA-QL has a <literal>fetch</literal> keyword that
- allows you to override laziness when doing a particular query. This is
- very useful to improve performance and is decided on a use case to use
- case basis.</para>
- </sect3>
- </sect2>
-
- <sect2>
- <title>Mapping composite primary and foreign keys</title>
-
- <para>Composite primary keys use a embedded class as the primary key
- representation, so you'd use the <literal>@Id</literal> and
- <literal>@Embeddable</literal> annotations. Alternatively, you can use
- the <literal>@EmbeddedId</literal> annotation. Note that the dependent
- class has to be serializable and implements
- <methodname>equals()</methodname>/<methodname>hashCode()</methodname>.
- You can also use <literal>@IdClass</literal> as described in <xref
- linkend="entity-mapping-identifier" />.</para>
-
- <programlisting>
- at Entity
-public class RegionalArticle implements Serializable {
-
- @Id
- public RegionalArticlePk getPk() { ... }
-}
-
- at Embeddable
-public class RegionalArticlePk implements Serializable { ... }
- </programlisting>
-
- <para>or alternatively</para>
-
- <programlisting>
- at Entity
-public class RegionalArticle implements Serializable {
-
- @EmbeddedId
- public RegionalArticlePk getPk() { ... }
-}
-
-public class RegionalArticlePk implements Serializable { ... }
- </programlisting>
-
- <para><literal>@Embeddable</literal> inherit the access type of its
- owning entity unless the Hibernate specific annotation
- <literal>@AccessType</literal> is used. Composite foreign keys (if not
- using the default sensitive values) are defined on associations using
- the <literal>@JoinColumns</literal> element, which is basically an array
- of <literal>@JoinColumn</literal>. It is considered a good practice to
- express <literal>referencedColumnNames</literal> explicitly. Otherwise,
- Hibernate will suppose that you use the same order of columns as in the
- primary key declaration.</para>
-
- <programlisting>
- at Entity
-public class Parent implements Serializable {
- @Id
- public ParentPk id;
- public int age;
-
- @OneToMany(cascade=CascadeType.ALL)
- @JoinColumns ({
- @JoinColumn(name="parentCivility", referencedColumnName = "isMale"),
- @JoinColumn(name="parentLastName", referencedColumnName = "lastName"),
- @JoinColumn(name="parentFirstName", referencedColumnName = "firstName")
- })
- public Set<Child> children; //unidirectional
- ...
-}
- </programlisting>
-
- <programlisting>
- at Entity
-public class Child implements Serializable {
- @Id @GeneratedValue
- public Integer id;
-
- @ManyToOne
- @JoinColumns ({
- @JoinColumn(name="parentCivility", referencedColumnName = "isMale"),
- @JoinColumn(name="parentLastName", referencedColumnName = "lastName"),
- @JoinColumn(name="parentFirstName", referencedColumnName = "firstName")
- })
- public Parent parent; //unidirectional
-}
- </programlisting>
-
- <programlisting>
- at Embeddable
-public class ParentPk implements Serializable {
- String firstName;
- String lastName;
- ...
-}
- </programlisting>
-
- <para>Note the explicit usage of the
- <literal>referencedColumnName</literal>.</para>
- </sect2>
-
- <sect2>
- <title>Mapping secondary tables</title>
-
- <para>You can map a single entity bean to several tables 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>
- at Entity
- at Table(name="MainCat")
-<emphasis role="bold">@SecondaryTables({
- @SecondaryTable(name="Cat1", pkJoinColumns={
- @PrimaryKeyJoinColumn(name="cat_id", referencedColumnName="id")
- ),
- @SecondaryTable(name="Cat2", uniqueConstraints={@UniqueConstraint(columnNames={"storyPart2"})})
-})</emphasis>
-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;
- }
-
- <emphasis role="bold">@Column(table="Cat1")</emphasis>
- public String getStoryPart1() {
- return storyPart1;
- }
-
- <emphasis role="bold">@Column(table="Cat2")</emphasis>
- 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>Check out the JBoss EJB 3 tutorial or the Hibernate Annotations
- unit test suite for more examples.</para>
- </sect2>
- </sect1>
-
- <sect1 id="entity-mapping-query">
- <title>Mapping Queries</title>
-
- <sect2 id="entity-mapping-query-hql" label="Mapping JPAQL/HQL queries"
- revision="1">
- <title>Mapping JPAQL/HQL queries</title>
-
- <para>You can map EJBQL/HQL queries using annotations.
- <literal>@NamedQuery</literal> and <literal>@NamedQueries</literal> can
- be defined at the class level or in a JPA XML file. However their
- definitions are global to the session factory/entity manager factory
- scope. A named query is defined by its name and the actual query
- string.</para>
-
- <programlisting><entity-mappings>
- <named-query name="plane.getAll">
- <query>select p from Plane p</query>
- </named-query>
- ...
-</entity-mappings>
-...
-
- at Entity
- at NamedQuery(name="night.moreRecentThan", query="select n from Night n where n.date >= :date")
-public class Night {
- ...
-}
-
-public class MyDao {
- doStuff() {
- Query q = s.getNamedQuery("night.moreRecentThan");
- q.setDate( "date", aMonthAgo );
- List results = q.list();
- ...
- }
- ...
-}
- </programlisting>
-
- <para>You can also provide some hints to a query through an array of
- <literal>QueryHint</literal> through a <literal>hints</literal>
- attribute.</para>
-
- <para>The availabe Hibernate hints are</para>
-
- <para></para>
-
- <table>
- <title>Query hints</title>
-
- <tgroup cols="2">
- <thead>
- <colspec colname="c1" />
-
- <colspec colname="c2" colnum="2" />
-
- <row>
- <entry>hint</entry>
-
- <entry colname="c2">description</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>org.hibernate.cacheable</entry>
-
- <entry>Whether the query should interact with the second level
- cache (defualt to false)</entry>
- </row>
-
- <row>
- <entry>org.hibernate.cacheRegion</entry>
-
- <entry>Cache region name (default used otherwise)</entry>
- </row>
-
- <row>
- <entry>org.hibernate.timeout</entry>
-
- <entry>Query timeout</entry>
- </row>
-
- <row>
- <entry>org.hibernate.fetchSize</entry>
-
- <entry>resultset fetch size</entry>
- </row>
-
- <row>
- <entry>org.hibernate.flushMode</entry>
-
- <entry>Flush mode used for this query</entry>
- </row>
-
- <row>
- <entry>org.hibernate.cacheMode</entry>
-
- <entry>Cache mode used for this query</entry>
- </row>
-
- <row>
- <entry>org.hibernate.readOnly</entry>
-
- <entry>Entities loaded by this query should be in read only mode
- or not (default to false)</entry>
- </row>
-
- <row>
- <entry>org.hibernate.comment</entry>
-
- <entry>Query comment added to the generated SQL</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect2>
-
- <sect2 id="entity-mapping-query-native" revision="2">
- <title>Mapping native queries</title>
-
- <para>You can also map a native query (ie a plain SQL query). To achieve
- that, you need to describe the SQL resultset structure using
- <literal>@SqlResultSetMapping</literal> (or
- <literal>@SqlResultSetMappings</literal> if you plan to define several
- resulset mappings). Like <literal>@NamedQuery</literal>, a
- <literal>@SqlResultSetMapping</literal> can be defined at class level or
- in a JPA XML file. However its scope is global to the
- application.</para>
-
- <para>As we will see, a <literal>resultSetMapping</literal> parameter is
- defined in <literal>@NamedNativeQuery</literal>, it represents the name
- of a defined <literal>@SqlResultSetMapping</literal>. The resultset
- mapping declares the entities retrieved by this native query. Each field
- of the entity is bound to an SQL alias (or column name). All fields of
- the entity including the ones of subclasses and the foreign key columns
- of related entities have to be present in the SQL query. Field
- definitions are optional provided that they map to the same column name
- as the one declared on the class property.</para>
-
- <para><programlisting>@NamedNativeQuery(name="night&area", query="select night.id nid, night.night_duration, "
- + " night.night_date, area.id aid, night.area_id, area.name "
- + "from Night night, Area area where night.area_id = area.id", <emphasis
- role="bold">resultSetMapping="joinMapping"</emphasis>)
- at SqlResultSetMapping(name="joinMapping", entities={
- @EntityResult(entityClass=org.hibernate.test.annotations.query.Night.class, fields = {
- @FieldResult(name="id", column="nid"),
- @FieldResult(name="duration", column="night_duration"),
- @FieldResult(name="date", column="night_date"),
- @FieldResult(name="area", column="area_id"),
- discriminatorColumn="disc"
- }),
- @EntityResult(entityClass=org.hibernate.test.annotations.query.Area.class, fields = {
- @FieldResult(name="id", column="aid"),
- @FieldResult(name="name", column="name")
- })
- }
-)</programlisting></para>
-
- <para>In the above example, the <literal>night&area</literal> named
- query use the <literal>joinMapping</literal> result set mapping. This
- mapping returns 2 entities, <literal>Night</literal> and
- <literal>Area</literal>, each property is declared and associated to a
- column name, actually the column name retrieved by the query. Let's now
- see an implicit declaration of the property / column.</para>
-
- <programlisting>@Entity
-<emphasis role="bold">@SqlResultSetMapping(name="implicit", entities=@EntityResult(entityClass=org.hibernate.test.annotations.query.SpaceShip.class))
- at NamedNativeQuery(name="implicitSample", query="select * from SpaceShip", resultSetMapping="implicit")</emphasis>
-public class SpaceShip {
- private String name;
- private String model;
- private double speed;
-
- @Id
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- @Column(name="model_txt")
- public String getModel() {
- return model;
- }
-
- public void setModel(String model) {
- this.model = model;
- }
-
- public double getSpeed() {
- return speed;
- }
-
- public void setSpeed(double speed) {
- this.speed = speed;
- }
-}</programlisting>
-
- <para>In this example, we only describe the entity member of the result
- set mapping. The property / column mappings is done using the entity
- mapping values. In this case the <literal>model</literal> property is
- bound to the <literal>model_txt </literal>column. If the association to
- a related entity involve a composite primary key, a
- <literal>@FieldResult</literal> element should be used for each foreign
- key column. The <literal>@FieldResult</literal> name is composed of the
- property name for the relationship, followed by a dot ("."), followed by
- the name or the field or property of the primary key.</para>
-
- <programlisting>@Entity
- at SqlResultSetMapping(name="compositekey",
- entities=@EntityResult(entityClass=org.hibernate.test.annotations.query.SpaceShip.class,
- fields = {
- @FieldResult(name="name", column = "name"),
- @FieldResult(name="model", column = "model"),
- @FieldResult(name="speed", column = "speed"),
-<emphasis role="bold"> @FieldResult(name="captain.firstname", column = "firstn"),
- @FieldResult(name="captain.lastname", column = "lastn"),</emphasis>
- @FieldResult(name="dimensions.length", column = "length"),
- @FieldResult(name="dimensions.width", column = "width")
- }),
- columns = { @ColumnResult(name = "surface"),
- @ColumnResult(name = "volume") } )
-
- at NamedNativeQuery(name="compositekey",
- query="select name, model, speed, lname as lastn, fname as firstn, length, width, length * width as surface from SpaceShip",
- resultSetMapping="compositekey")
-} )
-public class SpaceShip {
- private String name;
- private String model;
- private double speed;
- private Captain captain;
- private Dimensions dimensions;
-
- @Id
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- @ManyToOne(fetch= FetchType.LAZY)
- @JoinColumns( {
- @JoinColumn(name="fname", referencedColumnName = "firstname"),
- @JoinColumn(name="lname", referencedColumnName = "lastname")
- } )
- public Captain getCaptain() {
- return captain;
- }
-
- public void setCaptain(Captain captain) {
- this.captain = captain;
- }
-
- public String getModel() {
- return model;
- }
-
- public void setModel(String model) {
- this.model = model;
- }
-
- public double getSpeed() {
- return speed;
- }
-
- public void setSpeed(double speed) {
- this.speed = speed;
- }
-
- public Dimensions getDimensions() {
- return dimensions;
- }
-
- public void setDimensions(Dimensions dimensions) {
- this.dimensions = dimensions;
- }
-}
-
- at Entity
- at IdClass(Identity.class)
-public class Captain implements Serializable {
- private String firstname;
- private String lastname;
-
- @Id
- public String getFirstname() {
- return firstname;
- }
-
- public void setFirstname(String firstname) {
- this.firstname = firstname;
- }
-
- @Id
- public String getLastname() {
- return lastname;
- }
-
- public void setLastname(String lastname) {
- this.lastname = lastname;
- }
-}
-</programlisting>
-
- <note>
- <para>If you look at the dimension property, you'll see that Hibernate
- supports the dotted notation for embedded objects (you can even have
- nested embedded objects). EJB3 implementations do not have to support
- this feature, we do :-)</para>
- </note>
-
- <para>If you retrieve a single entity and if you use the default
- mapping, you can use the <literal>resultClass</literal> attribute
- instead of <literal>resultSetMapping</literal>:</para>
-
- <programlisting><emphasis role="bold">@NamedNativeQuery(name="implicitSample", query="select * from SpaceShip",
- resultClass=SpaceShip.class)</emphasis>
-public class SpaceShip {</programlisting>
-
- <para>In some of your native queries, you'll have to return scalar
- values, for example when building report queries. You can map them in
- the <literal>@SqlResultsetMapping</literal> through
- <literal>@ColumnResult</literal>. You actually can even mix, entities
- and scalar returns in the same native query (this is probably not that
- common though).</para>
-
- <programlisting><emphasis role="bold">@SqlResultSetMapping(name="scalar", columns=@ColumnResult(name="dimension"))
- at NamedNativeQuery(name="scalar", query="select length*width as dimension from SpaceShip", resultSetMapping="scalar")</emphasis></programlisting>
-
- <para>An other query hint specific to native queries has been
- introduced: <literal>org.hibernate.callable</literal> which can be true
- or false depending on whether the query is a stored procedure or
- not.</para>
- </sect2>
- </sect1>
-
- <sect1 id="entity-hibspec" xreflabel="Hibernate Annotation Extensions">
- <title>Hibernate Annotation Extensions</title>
-
- <para>Hibernate 3.1 offers a variety of additional annotations that you
- can mix/match with your EJB 3 entities. They have been designed as a
- natural extension of EJB3 annotations.</para>
-
- <para>To empower the EJB3 capabilities, hibernate provides specific
- annotations that match hibernate features. The
- <classname>org.hibernate.annotations</classname> package contains all
- these annotations extensions.</para>
-
- <sect2 id="entity-hibspec-entity" revision="2">
- <title>Entity</title>
-
- <para>You can fine tune some of the actions done by Hibernate on
- entities beyond what the EJB3 spec offers.</para>
-
- <para><classname>@org.hibernate.annotations.Entity</classname> adds
- additional metadata that may be needed beyond what is defined in the
- standard <literal>@Entity</literal> <itemizedlist>
- <listitem>
- mutable: whether this entity is mutable or not
- </listitem>
-
- <listitem>
- dynamicInsert: allow dynamic SQL for inserts
- </listitem>
-
- <listitem>
- dynamicUpdate: allow dynamic SQL for updates
- </listitem>
-
- <listitem>
- selectBeforeUpdate: Specifies that Hibernate should never perform an SQL UPDATE unless it is certain that an object is actually modified.
- </listitem>
-
- <listitem>
- polymorphism: whether the entity polymorphism is of PolymorphismType.IMPLICIT (default) or PolymorphismType.EXPLICIT
- </listitem>
-
- <listitem>
- persister: allow the overriding of the default persister implementation
- </listitem>
-
- <listitem>
- optimisticLock: optimistic locking strategy (OptimisticLockType.VERSION, OptimisticLockType.NONE, OptimisticLockType.DIRTY or OptimisticLockType.ALL)
- </listitem>
- </itemizedlist></para>
-
- <para><note>
- <para>@javax.persistence.Entity is still mandatory,
- @org.hibernate.annotations.Entity is not a replacement.</para>
- </note></para>
-
- <para>Here are some additional Hibernate annotation extensions</para>
-
- <para><literal>@org.hibernate.annotations.BatchSize</literal> allows you
- to define the batch size when fetching instances of this entity ( eg.
- <literal>@BatchSize(size=4)</literal> ). When loading a given entity,
- Hibernate will then load all the uninitialized entities of the same type
- in the persistence context up to the batch size.</para>
-
- <para><literal>@org.hibernate.annotations.Proxy</literal> defines the
- laziness attributes of the entity. lazy (default to true) define whether
- the class is lazy or not. proxyClassName is the interface used to
- generate the proxy (default is the class itself).</para>
-
- <para><literal>@org.hibernate.annotations.Where</literal> defines an
- optional SQL WHERE clause used when instances of this class is
- retrieved.</para>
-
- <para><literal>@org.hibernate.annotations.Check</literal> defines an
- optional check constraints defined in the DDL statetement.</para>
-
- <para><literal>@OnDelete(action=OnDeleteAction.CASCADE)</literal> on
- joined subclasses: use a SQL cascade delete on deletion instead of the
- regular Hibernate mechanism.</para>
-
- <para><literal>@Table(appliesTo="tableName", indexes = {
- @Index(name="index1", columnNames={"column1", "column2"} ) } )</literal>
- creates the defined indexes on the columns of table
- <literal>tableName</literal>. This can be applied on the primary table
- or any secondary table. The <literal>@Tables</literal> annotation allows
- your to apply indexes on different tables. This annotation is expected
- where <literal>@javax.persistence.Table</literal> or
- <literal>@javax.persistence.SecondaryTable</literal>(s) occurs.</para>
-
- <note>
- <para><literal>@org.hibernate.annotations.Table</literal> is a
- complement, not a replacement to
- <literal>@javax.persistence.Table</literal>. Especially, if you want
- to change the default name of a table, you must use
- <literal>@javax.persistence.Ta