[hibernate-commits] Hibernate SVN: r19961 - core/trunk/documentation/manual/src/main/docbook/en-US/content.
hibernate-commits at lists.jboss.org
hibernate-commits at lists.jboss.org
Fri Jul 16 11:27:49 EDT 2010
Author: hardy.ferentschik
Date: 2010-07-16 11:27:49 -0400 (Fri, 16 Jul 2010)
New Revision: 19961
Modified:
core/trunk/documentation/manual/src/main/docbook/en-US/content/performance.xml
core/trunk/documentation/manual/src/main/docbook/en-US/content/persistent_classes.xml
core/trunk/documentation/manual/src/main/docbook/en-US/content/query_sql.xml
core/trunk/documentation/manual/src/main/docbook/en-US/content/session_api.xml
Log:
HHH-5388 Added annotation documentation for named (native) queries, tuplizers and fetch profiles
Modified: core/trunk/documentation/manual/src/main/docbook/en-US/content/performance.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/performance.xml 2010-07-16 15:24:32 UTC (rev 19960)
+++ core/trunk/documentation/manual/src/main/docbook/en-US/content/performance.xml 2010-07-16 15:27:49 UTC (rev 19961)
@@ -532,14 +532,45 @@
<interfacename>org.hibernate.SessionFactory</interfacename> but enabled,
by name, on the <interfacename>org.hibernate.Session</interfacename>.
Once enabled on a <interfacename>org.hibernate.Session</interfacename>,
- the fetch profile wull be in affect for that
+ the fetch profile will be in affect for that
<interfacename>org.hibernate.Session</interfacename> until it is
explicitly disabled.</para>
<para>So what does that mean? Well lets explain that by way of an
- example. Say we have the following mappings:</para>
+ example which show the different available approaches to configure a
+ fetch profile:</para>
- <programlisting role="XML"><hibernate-mapping>
+ <example>
+ <title>Specifying a fetch profile using
+ <classname>@FetchProfile</classname></title>
+
+ <programlisting role="XML">@Entity
+ at FetchProfile(name = "customer-with-orders", fetchOverrides = {
+ @FetchProfile.FetchOverride(entity = Customer.class, association = "orders", mode = FetchMode.JOIN)
+})
+public class Customer {
+ @Id
+ @GeneratedValue
+ private long id;
+
+ private String name;
+
+ private long customerNumber;
+
+ @OneToMany
+ private Set<Order> orders;
+
+ // standard getter/setter
+ ...
+}</programlisting>
+ </example>
+
+ <example>
+ <title>Specifying a fetch profile using
+ <literal><fetch-profile></literal> outside
+ <literal><class></literal> node</title>
+
+ <programlisting role="XML"><hibernate-mapping>
<class name="Customer">
...
<set name="orders" inverse="true">
@@ -550,46 +581,65 @@
<class name="Order">
...
</class>
-</hibernate-mapping></programlisting>
-
- <para>Now normally when you get a reference to a particular customer,
- that customer's set of orders will be lazy meaning we will not yet have
- loaded those orders from the database. Normally this is a good thing.
- Now lets say that you have a certain use case where it is more efficient
- to load the customer and their orders together. One way certainly is to
- use "dynamic fetching" strategies via an HQL or criteria queries. But
- another option is to use a fetch profile to achieve that. Just add the
- following to your mapping:</para>
-
- <programlisting role="XML"><hibernate-mapping>
- ...
<fetch-profile name="customer-with-orders">
<fetch entity="Customer" association="orders" style="join"/>
</fetch-profile>
-</hibernate-mapping></programlisting>
+</hibernate-mapping>
+</programlisting>
+ </example>
- <para>or even:</para>
+ <example>
+ <title>Specifying a fetch profile using
+ <literal><fetch-profile></literal> inside
+ <literal><class></literal> node</title>
- <programlisting role="XML"><hibernate-mapping>
+ <programlisting role="XML"><hibernate-mapping>
<class name="Customer">
...
+ <set name="orders" inverse="true">
+ <key column="cust_id"/>
+ <one-to-many class="Order"/>
+ </set>
<fetch-profile name="customer-with-orders">
<fetch association="orders" style="join"/>
</fetch-profile>
</class>
- ...
-</hibernate-mapping></programlisting>
+ <class name="Order">
+ ...
+ </class>
+</hibernate-mapping>
+</programlisting>
+ </example>
- <para>Now the following code will actually load both the customer
- <emphasis>and their orders</emphasis>:</para>
+ <para>Now normally when you get a reference to a particular customer,
+ that customer's set of orders will be lazy meaning we will not yet have
+ loaded those orders from the database. Normally this is a good thing.
+ Now lets say that you have a certain use case where it is more efficient
+ to load the customer and their orders together. One way certainly is to
+ use "dynamic fetching" strategies via an HQL or criteria queries. But
+ another option is to use a fetch profile to achieve that. The following
+ code will load both the customer <emphasis>and</emphasis>their
+ orders:</para>
- <programlisting role="JAVA">
- Session session = ...;
- session.enableFetchProfile( "customer-with-orders" ); // name matches from mapping
- Customer customer = (Customer) session.get( Customer.class, customerId );
+ <example>
+ <title>Activating a fetch profile for a given
+ <classname>Session</classname></title>
+ <programlisting role="JAVA">Session session = ...;
+session.enableFetchProfile( "customer-with-orders" ); // name matches from mapping
+Customer customer = (Customer) session.get( Customer.class, customerId );
</programlisting>
+ </example>
+ <note>
+ <para><classname>@FetchProfile </classname>definitions are global and
+ it does not matter on which class you place them. You can place the
+ <classname>@FetchProfile</classname> annotation either onto a class or
+ package (package-info.java). In order to define multiple fetch
+ profiles for the same class or package
+ <classname>@FetchProfiles</classname> can be used.</para>
+ </note>
+
<para>Currently only join style fetch profiles are supported, but they
plan is to support additional styles. See <ulink
url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3414">HHH-3414</ulink>
Modified: core/trunk/documentation/manual/src/main/docbook/en-US/content/persistent_classes.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/persistent_classes.xml 2010-07-16 15:24:32 UTC (rev 19960)
+++ core/trunk/documentation/manual/src/main/docbook/en-US/content/persistent_classes.xml 2010-07-16 15:27:49 UTC (rev 19961)
@@ -1,4 +1,4 @@
-<?xml version='1.0' encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
@@ -22,39 +22,34 @@
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../HIBERNATE_-_Relational_Persistence_for_Idiomatic_Java.ent">
%BOOK_ENTITIES;
-
]>
-
<chapter id="persistent-classes" revision="2">
- <title>Persistent Classes</title>
+ <title>Persistent Classes</title>
- <para>
- Persistent classes are classes in an application that implement the entities
- of the business problem (e.g. Customer and Order in an E-commerce application).
- Not all instances of a persistent class are considered to be in the persistent
- state. For example, an instance can instead be transient or detached.
- </para>
+ <para>Persistent classes are classes in an application that implement the
+ entities of the business problem (e.g. Customer and Order in an E-commerce
+ application). Not all instances of a persistent class are considered to be
+ in the persistent state. For example, an instance can instead be transient
+ or detached.</para>
- <para>
- Hibernate works best if these classes follow some simple rules, also known
- as the Plain Old Java Object (POJO) programming model. However, none of these
- rules are hard requirements. Indeed, Hibernate3 assumes very little about
- the nature of your persistent objects. You can express a domain model in other
- ways (using trees of <literal>Map</literal> instances, for example).
- </para>
+ <para>Hibernate works best if these classes follow some simple rules, also
+ known as the Plain Old Java Object (POJO) programming model. However, none
+ of these rules are hard requirements. Indeed, Hibernate3 assumes very little
+ about the nature of your persistent objects. You can express a domain model
+ in other ways (using trees of <literal>Map</literal> instances, for
+ example).</para>
- <section id="persistent-classes-pojo">
- <title>A simple POJO example</title>
+ <section id="persistent-classes-pojo">
+ <title>A simple POJO example</title>
- <para>
- Most Java applications require a persistent class representing felines. For example:
- </para>
+ <para>Most Java applications require a persistent class representing
+ felines. For example:</para>
- <programlisting role="JAVA"><![CDATA[package eg;
+ <programlisting role="JAVA">package eg;
import java.util.Set;
import java.util.Date;
@@ -131,124 +126,110 @@
kitten.setLitterId( kittens.size() );
kittens.add(kitten);
}
-}]]></programlisting>
+}</programlisting>
- <para>
- The four main rules of persistent classes are explored in more detail in the following sections.
- </para>
+ <para>The four main rules of persistent classes are explored in more
+ detail in the following sections.</para>
+ <section id="persistent-classes-pojo-constructor" revision="1">
+ <title>Implement a no-argument constructor</title>
- <section id="persistent-classes-pojo-constructor" revision="1">
- <title>Implement a no-argument constructor</title>
+ <para><literal>Cat</literal> has a no-argument constructor. All
+ persistent classes must have a default constructor (which can be
+ non-public) so that Hibernate can instantiate them using
+ <literal>Constructor.newInstance()</literal>. It is recommended that you
+ have a default constructor with at least <emphasis>package</emphasis>
+ visibility for runtime proxy generation in Hibernate.</para>
+ </section>
- <para>
- <literal>Cat</literal> has a no-argument constructor. All persistent classes must
- have a default constructor (which can be non-public) so that Hibernate can instantiate
- them using <literal>Constructor.newInstance()</literal>. It is recommended that you have a
- default constructor with at least <emphasis>package</emphasis> visibility for runtime proxy
- generation in Hibernate.
- </para>
- </section>
+ <section id="persistent-classes-pojo-identifier" revision="2">
+ <title>Provide an identifier property (optional)</title>
- <section id="persistent-classes-pojo-identifier" revision="2">
- <title>Provide an identifier property (optional)</title>
+ <para><literal>Cat</literal> has a property called
+ <literal>id</literal>. This property maps to the primary key column of a
+ database table. The property might have been called anything, and its
+ type might have been any primitive type, any primitive "wrapper" type,
+ <literal>java.lang.String</literal> or
+ <literal>java.util.Date</literal>. If your legacy database table has
+ composite keys, you can use a user-defined class with properties of
+ these types (see the section on composite identifiers later in the
+ chapter.)</para>
- <para>
- <literal>Cat</literal> has a property called <literal>id</literal>. This property
- maps to the primary key column of a database table. The property might have been called
- anything, and its type might have been any primitive type, any primitive "wrapper"
- type, <literal>java.lang.String</literal> or <literal>java.util.Date</literal>. If
- your legacy database table has composite keys, you can use a user-defined class
- with properties of these types (see the section on composite identifiers later in the chapter.)
- </para>
+ <para>The identifier property is strictly optional. You can leave them
+ off and let Hibernate keep track of object identifiers internally. We do
+ not recommend this, however.</para>
- <para>
- The identifier property is strictly optional. You can leave them off and let Hibernate
- keep track of object identifiers internally. We do not recommend this, however.
- </para>
+ <para>In fact, some functionality is available only to classes that
+ declare an identifier property:</para>
- <para>
- In fact, some functionality is available only to classes that declare an
- identifier property:
- </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>Transitive reattachment for detached objects (cascade update
+ or cascade merge) - see <xref
+ linkend="objectstate-transitive" /></para>
+ </listitem>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Transitive reattachment for detached objects (cascade update or cascade
- merge) - see <xref linkend="objectstate-transitive"/>
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>Session.saveOrUpdate()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>Session.merge()</literal>
- </para>
- </listitem>
- </itemizedlist>
+ <listitem>
+ <para><literal>Session.saveOrUpdate()</literal></para>
+ </listitem>
- <para>
- We recommend that you declare consistently-named identifier properties on persistent
- classes and that you use a nullable (i.e., non-primitive) type.
- </para>
- </section>
+ <listitem>
+ <para><literal>Session.merge()</literal></para>
+ </listitem>
+ </itemizedlist>
- <section id="persistent-classes-pojo-final">
- <title>Prefer non-final classes (optional)</title>
- <para>
- A central feature of Hibernate, <emphasis>proxies</emphasis>, depends upon the
- persistent class being either non-final, or the implementation of an interface
- that declares all public methods.
- </para>
- <para>
- You can persist <literal>final</literal> classes that do not implement an interface
- with Hibernate. You will not, however, be able to use proxies for lazy association fetching which
- will ultimately limit your options for performance tuning.
- </para>
- <para>
- You should also avoid declaring <literal>public final</literal> methods on the
- non-final classes. If you want to use a class with a <literal>public final</literal>
- method, you must explicitly disable proxying by setting <literal>lazy="false"</literal>.
- </para>
- </section>
-
- <section id="persistent-classes-pojo-accessors" revision="2">
- <title>Declare accessors and mutators for persistent fields (optional)</title>
+ <para>We recommend that you declare consistently-named identifier
+ properties on persistent classes and that you use a nullable (i.e.,
+ non-primitive) type.</para>
+ </section>
- <para>
- <literal>Cat</literal> declares accessor methods for all its persistent fields.
- Many other ORM tools directly persist instance variables. It is
- better to provide an indirection between the relational schema and internal
- data structures of the class. By default, Hibernate persists JavaBeans style
- properties and recognizes method names of the form <literal>getFoo</literal>,
- <literal>isFoo</literal> and <literal>setFoo</literal>. If required, you can switch to direct
- field access for particular properties.
- </para>
+ <section id="persistent-classes-pojo-final">
+ <title>Prefer non-final classes (optional)</title>
- <para>
- Properties need <emphasis>not</emphasis> be declared public - Hibernate can
- persist a property with a default, <literal>protected</literal> or
- <literal>private</literal> get / set pair.
- </para>
+ <para>A central feature of Hibernate, <emphasis>proxies</emphasis>,
+ depends upon the persistent class being either non-final, or the
+ implementation of an interface that declares all public methods.</para>
- </section>
+ <para>You can persist <literal>final</literal> classes that do not
+ implement an interface with Hibernate. You will not, however, be able to
+ use proxies for lazy association fetching which will ultimately limit
+ your options for performance tuning.</para>
+ <para>You should also avoid declaring <literal>public final</literal>
+ methods on the non-final classes. If you want to use a class with a
+ <literal>public final</literal> method, you must explicitly disable
+ proxying by setting <literal>lazy="false"</literal>.</para>
</section>
- <section id="persistent-classes-inheritance">
- <title>Implementing inheritance</title>
+ <section id="persistent-classes-pojo-accessors" revision="2">
+ <title>Declare accessors and mutators for persistent fields
+ (optional)</title>
- <para>
- A subclass must also observe the first and second rules. It inherits its
- identifier property from the superclass, <literal>Cat</literal>. For example:
- </para>
+ <para><literal>Cat</literal> declares accessor methods for all its
+ persistent fields. Many other ORM tools directly persist instance
+ variables. It is better to provide an indirection between the relational
+ schema and internal data structures of the class. By default, Hibernate
+ persists JavaBeans style properties and recognizes method names of the
+ form <literal>getFoo</literal>, <literal>isFoo</literal> and
+ <literal>setFoo</literal>. If required, you can switch to direct field
+ access for particular properties.</para>
- <programlisting role="JAVA"><![CDATA[package eg;
+ <para>Properties need <emphasis>not</emphasis> be declared public -
+ Hibernate can persist a property with a default,
+ <literal>protected</literal> or <literal>private</literal> get / set
+ pair.</para>
+ </section>
+ </section>
+ <section id="persistent-classes-inheritance">
+ <title>Implementing inheritance</title>
+
+ <para>A subclass must also observe the first and second rules. It inherits
+ its identifier property from the superclass, <literal>Cat</literal>. For
+ example:</para>
+
+ <programlisting role="JAVA">package eg;
+
public class DomesticCat extends Cat {
private String name;
@@ -258,63 +239,59 @@
protected void setName(String name) {
this.name=name;
}
-}]]></programlisting>
- </section>
+}</programlisting>
+ </section>
- <section id="persistent-classes-equalshashcode" revision="1">
- <title>Implementing <literal>equals()</literal> and <literal>hashCode()</literal></title>
+ <section id="persistent-classes-equalshashcode" revision="1">
+ <title>Implementing <literal>equals()</literal> and
+ <literal>hashCode()</literal></title>
- <para>
- You have to override the <literal>equals()</literal> and <literal>hashCode()</literal>
- methods if you:
- </para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- intend to put instances of persistent classes in a <literal>Set</literal>
- (the recommended way to represent many-valued associations);
- <emphasis>and</emphasis>
- </para>
- </listitem>
- <listitem>
- <para>
- intend to use reattachment of detached instances
- </para>
- </listitem>
- </itemizedlist>
+ <para>You have to override the <literal>equals()</literal> and
+ <literal>hashCode()</literal> methods if you:</para>
- <para>
- Hibernate guarantees equivalence of persistent identity (database row) and Java identity
- only inside a particular session scope. When you mix instances retrieved in
- different sessions, you must implement <literal>equals()</literal> and
- <literal>hashCode()</literal> if you wish to have meaningful semantics for
- <literal>Set</literal>s.
- </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>intend to put instances of persistent classes in a
+ <literal>Set</literal> (the recommended way to represent many-valued
+ associations); <emphasis>and</emphasis></para>
+ </listitem>
- <para>
- The most obvious way is to implement <literal>equals()</literal>/<literal>hashCode()</literal>
- by comparing the identifier value of both objects. If the value is the same, both must
- be the same database row, because they are equal. If both are added to a <literal>Set</literal>,
- you will only have one element in the <literal>Set</literal>). Unfortunately, you cannot use that
- approach with generated identifiers. Hibernate will only assign identifier values to objects
- that are persistent; a newly created instance will not have any identifier value. Furthermore,
- if an instance is unsaved and currently in a <literal>Set</literal>, saving it will assign
- an identifier value to the object. If <literal>equals()</literal> and <literal>hashCode()</literal>
- are based on the identifier value, the hash code would change, breaking the contract of the
- <literal>Set</literal>. See the Hibernate website for a full discussion of this problem. This is not
- a Hibernate issue, but normal Java semantics of object identity and equality.
- </para>
+ <listitem>
+ <para>intend to use reattachment of detached instances</para>
+ </listitem>
+ </itemizedlist>
- <para>
- It is recommended that you implement <literal>equals()</literal> and <literal>hashCode()</literal>
- using <emphasis>Business key equality</emphasis>. Business key equality means that the
- <literal>equals()</literal> method compares only the properties that form the business
- key. It is a key that would identify our instance in the real world (a
- <emphasis>natural</emphasis> candidate key):
- </para>
+ <para>Hibernate guarantees equivalence of persistent identity (database
+ row) and Java identity only inside a particular session scope. When you
+ mix instances retrieved in different sessions, you must implement
+ <literal>equals()</literal> and <literal>hashCode()</literal> if you wish
+ to have meaningful semantics for <literal>Set</literal>s.</para>
- <programlisting role="JAVA"><![CDATA[public class Cat {
+ <para>The most obvious way is to implement
+ <literal>equals()</literal>/<literal>hashCode()</literal> by comparing the
+ identifier value of both objects. If the value is the same, both must be
+ the same database row, because they are equal. If both are added to a
+ <literal>Set</literal>, you will only have one element in the
+ <literal>Set</literal>). Unfortunately, you cannot use that approach with
+ generated identifiers. Hibernate will only assign identifier values to
+ objects that are persistent; a newly created instance will not have any
+ identifier value. Furthermore, if an instance is unsaved and currently in
+ a <literal>Set</literal>, saving it will assign an identifier value to the
+ object. If <literal>equals()</literal> and <literal>hashCode()</literal>
+ are based on the identifier value, the hash code would change, breaking
+ the contract of the <literal>Set</literal>. See the Hibernate website for
+ a full discussion of this problem. This is not a Hibernate issue, but
+ normal Java semantics of object identity and equality.</para>
+ <para>It is recommended that you implement <literal>equals()</literal> and
+ <literal>hashCode()</literal> using <emphasis>Business key
+ equality</emphasis>. Business key equality means that the
+ <literal>equals()</literal> method compares only the properties that form
+ the business key. It is a key that would identify our instance in the real
+ world (a <emphasis>natural</emphasis> candidate key):</para>
+
+ <programlisting role="JAVA">public class Cat {
+
...
public boolean equals(Object other) {
if (this == other) return true;
@@ -335,97 +312,85 @@
return result;
}
-}]]></programlisting>
+}</programlisting>
- <para>
- A business key does not have to be as solid as a database
- primary key candidate (see <xref linkend="transactions-basics-identity"/>).
- Immutable or unique properties are usually good
- candidates for a business key.
- </para>
+ <para>A business key does not have to be as solid as a database primary
+ key candidate (see <xref linkend="transactions-basics-identity" />).
+ Immutable or unique properties are usually good candidates for a business
+ key.</para>
+ </section>
- </section>
+ <section id="persistent-classes-dynamicmodels">
+ <title>Dynamic models</title>
- <section id="persistent-classes-dynamicmodels">
- <title>Dynamic models</title>
+ <note>
+ <title>Note</title>
-
- <note><title>Note</title>
-<para>
- <emphasis>The following features are currently considered
- experimental and may change in the near future.</emphasis>
-
- </para>
-</note>
- <para>
- Persistent entities do not necessarily have to be represented as POJO classes
- or as JavaBean objects at runtime. Hibernate also supports dynamic models
- (using <literal>Map</literal>s of <literal>Map</literal>s at runtime) and the
- representation of entities as DOM4J trees. With this approach, you do not
- write persistent classes, only mapping files.
- </para>
+ <para><emphasis>The following features are currently considered
+ experimental and may change in the near future.</emphasis></para>
+ </note>
- <para>
- By default, Hibernate works in normal POJO mode. You can set a default entity
- representation mode for a particular <literal>SessionFactory</literal> using the
- <literal>default_entity_mode</literal> configuration option (see
- <xref linkend="configuration-optional-properties"/>).
- </para>
+ <para>Persistent entities do not necessarily have to be represented as
+ POJO classes or as JavaBean objects at runtime. Hibernate also supports
+ dynamic models (using <literal>Map</literal>s of <literal>Map</literal>s
+ at runtime) and the representation of entities as DOM4J trees. With this
+ approach, you do not write persistent classes, only mapping files.</para>
- <para>
- The following examples demonstrate the representation using <literal>Map</literal>s.
- First, in the mapping file an <literal>entity-name</literal> has to be declared
- instead of, or in addition to, a class name:
- </para>
+ <para>By default, Hibernate works in normal POJO mode. You can set a
+ default entity representation mode for a particular
+ <literal>SessionFactory</literal> using the
+ <literal>default_entity_mode</literal> configuration option (see <xref
+ linkend="configuration-optional-properties" />).</para>
- <programlisting role="XML"><![CDATA[<hibernate-mapping>
+ <para>The following examples demonstrate the representation using
+ <literal>Map</literal>s. First, in the mapping file an
+ <literal>entity-name</literal> has to be declared instead of, or in
+ addition to, a class name:</para>
- <class entity-name="Customer">
+ <programlisting role="XML"><hibernate-mapping>
- <id name="id"
+ <class entity-name="Customer">
+
+ <id name="id"
type="long"
- column="ID">
- <generator class="sequence"/>
- </id>
+ column="ID">
+ <generator class="sequence"/>
+ </id>
- <property name="name"
+ <property name="name"
column="NAME"
- type="string"/>
+ type="string"/>
- <property name="address"
+ <property name="address"
column="ADDRESS"
- type="string"/>
+ type="string"/>
- <many-to-one name="organization"
+ <many-to-one name="organization"
column="ORGANIZATION_ID"
- class="Organization"/>
+ class="Organization"/>
- <bag name="orders"
+ <bag name="orders"
inverse="true"
lazy="false"
- cascade="all">
- <key column="CUSTOMER_ID"/>
- <one-to-many class="Order"/>
- </bag>
+ cascade="all">
+ <key column="CUSTOMER_ID"/>
+ <one-to-many class="Order"/>
+ </bag>
- </class>
+ </class>
-</hibernate-mapping>]]></programlisting>
+</hibernate-mapping></programlisting>
- <para>
+ <para>Even though associations are declared using target class names, the
+ target type of associations can also be a dynamic entity instead of a
+ POJO.</para>
- Even though associations are declared using target class names,
- the target type of associations can also be a dynamic entity instead
- of a POJO.
- </para>
+ <para>After setting the default entity mode to
+ <literal>dynamic-map</literal> for the <literal>SessionFactory</literal>,
+ you can, at runtime, work with <literal>Map</literal>s of
+ <literal>Map</literal>s:</para>
- <para>
- After setting the default entity mode to <literal>dynamic-map</literal>
- for the <literal>SessionFactory</literal>, you can, at runtime, work with
- <literal>Map</literal>s of <literal>Map</literal>s:
- </para>
-
- <programlisting role="JAVA"><![CDATA[Session s = openSession();
+ <programlisting role="JAVA">Session s = openSession();
Transaction tx = s.beginTransaction();
// Create a customer
@@ -444,22 +409,19 @@
s.save("Organization", foobar);
tx.commit();
-s.close();]]></programlisting>
+s.close();</programlisting>
- <para>
- One of the main advantages of dynamic mapping is quick turnaround time for prototyping,
- without the need for entity class implementation. However, you lose compile-time
- type checking and will likely deal with many exceptions at runtime. As a result of
- the Hibernate mapping, the database schema can easily be normalized and sound,
- allowing to add a proper domain model implementation on top later on.
- </para>
+ <para>One of the main advantages of dynamic mapping is quick turnaround
+ time for prototyping, without the need for entity class implementation.
+ However, you lose compile-time type checking and will likely deal with
+ many exceptions at runtime. As a result of the Hibernate mapping, the
+ database schema can easily be normalized and sound, allowing to add a
+ proper domain model implementation on top later on.</para>
- <para>
- Entity representation modes can also be set on a per <literal>Session</literal>
- basis:
- </para>
+ <para>Entity representation modes can also be set on a per
+ <literal>Session</literal> basis:</para>
- <programlisting role="JAVA"><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
+ <programlisting role="JAVA">Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
// Create a customer
Map david = new HashMap();
@@ -470,112 +432,118 @@
dynamicSession.close()
...
// Continue on pojoSession
-]]></programlisting>
+</programlisting>
+ <para>Please note that the call to <literal>getSession()</literal> using
+ an <literal>EntityMode</literal> is on the <literal>Session</literal> API,
+ not the <literal>SessionFactory</literal>. That way, the new
+ <literal>Session</literal> shares the underlying JDBC connection,
+ transaction, and other context information. This means you do not have to
+ call <literal>flush()</literal> and <literal>close()</literal> on the
+ secondary <literal>Session</literal>, and also leave the transaction and
+ connection handling to the primary unit of work.</para>
- <para>
- Please note that the call to <literal>getSession()</literal> using an
- <literal>EntityMode</literal> is on the <literal>Session</literal> API, not the
- <literal>SessionFactory</literal>. That way, the new <literal>Session</literal>
- shares the underlying JDBC connection, transaction, and other context
- information. This means you do not have to call <literal>flush()</literal>
- and <literal>close()</literal> on the secondary <literal>Session</literal>, and
- also leave the transaction and connection handling to the primary unit of work.
- </para>
+ <para>More information about the XML representation capabilities can be
+ found in <xref linkend="xml" />.</para>
+ </section>
- <para>
- More information about the XML representation capabilities can be found
- in <xref linkend="xml"/>.
- </para>
+ <section id="persistent-classes-tuplizers" revision="1">
+ <title>Tuplizers</title>
- </section>
+ <para><literal>org.hibernate.tuple.Tuplizer</literal>, and its
+ sub-interfaces, are responsible for managing a particular representation
+ of a piece of data given that representation's
+ <literal>org.hibernate.EntityMode</literal>. If a given piece of data is
+ thought of as a data structure, then a tuplizer is the thing that knows
+ how to create such a data structure and how to extract values from and
+ inject values into such a data structure. For example, for the POJO entity
+ mode, the corresponding tuplizer knows how create the POJO through its
+ constructor. It also knows how to access the POJO properties using the
+ defined property accessors.</para>
- <section id="persistent-classes-tuplizers" revision="1">
- <title>Tuplizers</title>
+ <para>There are two high-level types of Tuplizers, represented by the
+ <literal>org.hibernate.tuple.entity.EntityTuplizer</literal> and
+ <literal>org.hibernate.tuple.component.ComponentTuplizer</literal>
+ interfaces. <literal>EntityTuplizer</literal>s are responsible for
+ managing the above mentioned contracts in regards to entities, while
+ <literal>ComponentTuplizer</literal>s do the same for components.</para>
- <para>
- <literal>org.hibernate.tuple.Tuplizer</literal>, and its sub-interfaces, are responsible
- for managing a particular representation of a piece of data given that representation's
- <literal>org.hibernate.EntityMode</literal>. If a given piece of data is thought of as
- a data structure, then a tuplizer is the thing that knows how to create such a data structure
- and how to extract values from and inject values into such a data structure. For example,
- for the POJO entity mode, the corresponding tuplizer knows how create the POJO through its
- constructor. It also knows how to access the POJO properties using the defined property accessors.
- </para>
+ <para>Users can also plug in their own tuplizers. Perhaps you require that
+ a <literal>java.util.Map</literal> implementation other than
+ <literal>java.util.HashMap</literal> be used while in the dynamic-map
+ entity-mode. Or perhaps you need to define a different proxy generation
+ strategy than the one used by default. Both would be achieved by defining
+ a custom tuplizer implementation. Tuplizer definitions are attached to the
+ entity or component mapping they are meant to manage. Going back to the
+ example of our customer entity <xref
+ linkend="example-defining-tuplizer-using-annotations" /> shows how to
+ configure tuplizers using annotations whereas <xref
+ linkend="example-defining-tuplizer-using-mapping-file" /> shows how to do
+ the same thing using Hibernate mapping files.</para>
- <para>
- There are two high-level types of Tuplizers, represented by the
- <literal>org.hibernate.tuple.entity.EntityTuplizer</literal> and <literal>org.hibernate.tuple.component.ComponentTuplizer</literal>
- interfaces. <literal>EntityTuplizer</literal>s are responsible for managing the above mentioned
- contracts in regards to entities, while <literal>ComponentTuplizer</literal>s do the same for
- components.
- </para>
+ <example id="example-defining-tuplizer-using-annotations">
+ <title>Mapping custom tuplizers using annotations</title>
- <para>
- Users can also plug in their own tuplizers. Perhaps you require that a <literal>java.util.Map</literal>
- implementation other than <literal>java.util.HashMap</literal> be used while in the
- dynamic-map entity-mode. Or perhaps you need to define a different proxy generation strategy
- than the one used by default. Both would be achieved by defining a custom tuplizer
- implementation. Tuplizer definitions are attached to the entity or component mapping they
- are meant to manage. Going back to the example of our customer entity:
- </para>
+ <programlisting role="XML">@Entity
+ at Tuplizer(impl = DynamicEntityTuplizer.class)
+public interface Cuisine {
+ @Id
+ @GeneratedValue
+ public Long getId();
+ public void setId(Long id);
- <programlisting role="XML"><![CDATA[<hibernate-mapping>
- <class entity-name="Customer">
- <!--
+ public String getName();
+ public void setName(String name);
+
+ @Tuplizer(impl = DynamicComponentTuplizer.class)
+ public Country getCountry();
+ public void setCountry(Country country);
+}</programlisting>
+ </example>
+
+ <example>
+ <title id="example-defining-tuplizer-using-mapping-file">Mapping custom
+ tuplizers using mapping files</title>
+
+ <programlisting role="XML"><hibernate-mapping>
+ <class entity-name="Customer">
+ <!--
Override the dynamic-map entity-mode
tuplizer for the customer entity
- -->
- <tuplizer entity-mode="dynamic-map"
- class="CustomMapTuplizerImpl"/>
+ -->
+ <tuplizer entity-mode="dynamic-map"
+ class="CustomMapTuplizerImpl"/>
- <id name="id" type="long" column="ID">
- <generator class="sequence"/>
- </id>
+ <id name="id" type="long" column="ID">
+ <generator class="sequence"/>
+ </id>
- <!-- other properties -->
+ <!-- other properties -->
...
- </class>
-</hibernate-mapping>
+ </class>
+</hibernate-mapping>
+</programlisting>
+ </example>
+ </section>
+ <section id="persistent-classes-entity-name-resolver" revision="0">
+ <title>EntityNameResolvers</title>
-public class CustomMapTuplizerImpl
- extends org.hibernate.tuple.entity.DynamicMapEntityTuplizer {
- // override the buildInstantiator() method to plug in our custom map...
- protected final Instantiator buildInstantiator(
- org.hibernate.mapping.PersistentClass mappingInfo) {
- return new CustomMapInstantiator( mappingInfo );
- }
+ <para>The <interfacename>org.hibernate.EntityNameResolver</interfacename>
+ interface is a contract for resolving the entity name of a given entity
+ instance. The interface defines a single method
+ <methodname>resolveEntityName</methodname> which is passed the entity
+ instance and is expected to return the appropriate entity name (null is
+ allowed and would indicate that the resolver does not know how to resolve
+ the entity name of the given entity instance). Generally speaking, an
+ <interfacename>org.hibernate.EntityNameResolver</interfacename> is going
+ to be most useful in the case of dynamic models. One example might be
+ using proxied interfaces as your domain model. The hibernate test suite
+ has an example of this exact style of usage under the
+ <package>org.hibernate.test.dynamicentity.tuplizer2</package>. Here is
+ some of the code from that package for illustration.</para>
- private static final class CustomMapInstantiator
- extends org.hibernate.tuple.DynamicMapInstantitor {
- // override the generateMap() method to return our custom map...
- protected final Map generateMap() {
- return new CustomMap();
- }
- }
-}]]></programlisting>
-
-
- </section>
-
-
- <section id="persistent-classes-entity-name-resolver" revision="0">
- <title>EntityNameResolvers</title>
-
- <para>
- The <interfacename>org.hibernate.EntityNameResolver</interfacename> interface is a contract for resolving the
- entity name of a given entity instance. The interface defines a single method <methodname>resolveEntityName</methodname>
- which is passed the entity instance and is expected to return the appropriate entity name (null is allowed and
- would indicate that the resolver does not know how to resolve the entity name of the given entity instance).
- Generally speaking, an <interfacename>org.hibernate.EntityNameResolver</interfacename> is going to be most
- useful in the case of dynamic models. One example might be using proxied interfaces as your domain model. The
- hibernate test suite has an example of this exact style of usage under the
- <package>org.hibernate.test.dynamicentity.tuplizer2</package>. Here is some of the code from that package
- for illustration.
- </para>
-
- <programlisting role="JAVA">
+ <programlisting role="JAVA">
/**
* A very trivial JDK Proxy InvocationHandler implementation where we proxy an interface as
* the domain model and simply store persistent state in an internal Map. This is an extremely
@@ -686,25 +654,23 @@
}
</programlisting>
- <para>
- In order to register an <interfacename>org.hibernate.EntityNameResolver</interfacename> users must either:
- <orderedlist>
- <listitem>
- <para>
- Implement a custom <link linkend="persistent-classes-tuplizers">Tuplizer</link>, implementing
- the <methodname>getEntityNameResolvers</methodname> method.
- </para>
- </listitem>
- <listitem>
- <para>
- Register it with the <classname>org.hibernate.impl.SessionFactoryImpl</classname> (which is the
- implementation class for <interfacename>org.hibernate.SessionFactory</interfacename>) using the
- <methodname>registerEntityNameResolver</methodname> method.
- </para>
- </listitem>
- </orderedlist>
- </para>
- </section>
+ <para>In order to register an
+ <interfacename>org.hibernate.EntityNameResolver</interfacename> users must
+ either: <orderedlist>
+ <listitem>
+ <para>Implement a custom <link
+ linkend="persistent-classes-tuplizers">Tuplizer</link>, implementing
+ the <methodname>getEntityNameResolvers</methodname> method.</para>
+ </listitem>
+ <listitem>
+ <para>Register it with the
+ <classname>org.hibernate.impl.SessionFactoryImpl</classname> (which
+ is the implementation class for
+ <interfacename>org.hibernate.SessionFactory</interfacename>) using
+ the <methodname>registerEntityNameResolver</methodname>
+ method.</para>
+ </listitem>
+ </orderedlist></para>
+ </section>
</chapter>
-
Modified: core/trunk/documentation/manual/src/main/docbook/en-US/content/query_sql.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/query_sql.xml 2010-07-16 15:24:32 UTC (rev 19960)
+++ core/trunk/documentation/manual/src/main/docbook/en-US/content/query_sql.xml 2010-07-16 15:27:49 UTC (rev 19961)
@@ -1,4 +1,4 @@
-<?xml version='1.0' encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
@@ -22,13 +22,11 @@
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../HIBERNATE_-_Relational_Persistence_for_Idiomatic_Java.ent">
%BOOK_ENTITIES;
-
]>
-
<chapter id="querysql" revision="2">
<title>Native SQL</title>
@@ -46,8 +44,8 @@
<para>Execution of native SQL queries is controlled via the
<literal>SQLQuery</literal> interface, which is obtained by calling
- <literal>Session.createSQLQuery()</literal>. The following sections describe how
- to use this API for querying.</para>
+ <literal>Session.createSQLQuery()</literal>. The following sections
+ describe how to use this API for querying.</para>
<section>
<title>Scalar queries</title>
@@ -55,12 +53,12 @@
<para>The most basic SQL query is to get a list of scalars
(values).</para>
- <programlisting role="JAVA"><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").list();
+ <programlisting role="JAVA">sess.createSQLQuery("SELECT * FROM CATS").list();
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
-]]></programlisting>
+</programlisting>
- <para>These will return a List of Object arrays (Object[]) with
- scalar values for each column in the CATS table. Hibernate will use
+ <para>These will return a List of Object arrays (Object[]) with scalar
+ values for each column in the CATS table. Hibernate will use
ResultSetMetadata to deduce the actual order and types of the returned
scalar values.</para>
@@ -68,11 +66,11 @@
<literal>ResultSetMetadata</literal>, or simply to be more explicit in
what is returned, one can use <literal>addScalar()</literal>:</para>
- <programlisting role="JAVA"><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
+ <programlisting role="JAVA">sess.createSQLQuery("SELECT * FROM CATS")
.addScalar("ID", Hibernate.LONG)
.addScalar("NAME", Hibernate.STRING)
.addScalar("BIRTHDATE", Hibernate.DATE)
-]]></programlisting>
+</programlisting>
<para>This query specified:</para>
@@ -97,15 +95,16 @@
<para>It is possible to leave out the type information for all or some
of the scalars.</para>
- <programlisting role="JAVA"><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
+ <programlisting role="JAVA">sess.createSQLQuery("SELECT * FROM CATS")
.addScalar("ID", Hibernate.LONG)
.addScalar("NAME")
.addScalar("BIRTHDATE")
-]]></programlisting>
+</programlisting>
<para>This is essentially the same query as before, but now
- <literal>ResultSetMetaData</literal> is used to determine the type of NAME
- and BIRTHDATE, where as the type of ID is explicitly specified.</para>
+ <literal>ResultSetMetaData</literal> is used to determine the type of
+ NAME and BIRTHDATE, where as the type of ID is explicitly
+ specified.</para>
<para>How the java.sql.Types returned from ResultSetMetaData is mapped
to Hibernate types is controlled by the Dialect. If a specific type is
@@ -122,9 +121,9 @@
shows how to get entity objects from a native sql query via
<literal>addEntity()</literal>.</para>
- <programlisting role="JAVA"><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class);
+ <programlisting role="JAVA">sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class);
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);
-]]></programlisting>
+</programlisting>
<para>This query specified:</para>
@@ -150,8 +149,8 @@
example for a <literal>many-to-one</literal> to a
<literal>Dog</literal>:</para>
- <programlisting role="JAVA"><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);
-]]></programlisting>
+ <programlisting role="JAVA">sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);
+</programlisting>
<para>This will allow cat.getDog() to function properly.</para>
</section>
@@ -164,10 +163,10 @@
done via the <literal>addJoin()</literal> method, which allows you to
join in an association or collection.</para>
- <programlisting role="JAVA"><![CDATA[sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID")
+ <programlisting role="JAVA">sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID")
.addEntity("cat", Cat.class)
.addJoin("cat.dog");
-]]></programlisting>
+</programlisting>
<para>In this example, the returned <literal>Cat</literal>'s will have
their <literal>dog</literal> property fully initialized without any
@@ -177,16 +176,16 @@
<literal>Cat</literal> had a one-to-many to <literal>Dog</literal>
instead.</para>
- <programlisting role="JAVA"><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID")
+ <programlisting role="JAVA">sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID")
.addEntity("cat", Cat.class)
.addJoin("cat.dogs");
-]]></programlisting>
+</programlisting>
- <para>
- At this stage you are reaching the limits of what is possible with native queries, without starting to
- enhance the sql queries to make them usable in Hibernate. Problems can arise when returning
- multiple entities of the same type or when the default alias/column names are not enough.
- </para>
+ <para>At this stage you are reaching the limits of what is possible with
+ native queries, without starting to enhance the sql queries to make them
+ usable in Hibernate. Problems can arise when returning multiple entities
+ of the same type or when the default alias/column names are not
+ enough.</para>
</section>
<section>
@@ -200,29 +199,25 @@
<para>Column alias injection is needed in the following query (which
most likely will fail):</para>
- <programlisting role="JAVA"><![CDATA[sess.createSQLQuery("SELECT c.*, m.* FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ <programlisting role="JAVA">sess.createSQLQuery("SELECT c.*, m.* FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
.addEntity("cat", Cat.class)
.addEntity("mother", Cat.class)
-]]></programlisting>
+</programlisting>
-
+ <para>The query was intended to return two Cat instances per row: a cat
+ and its mother. The query will, however, fail because there is a
+ conflict of names; the instances are mapped to the same column names.
+ Also, on some databases the returned column aliases will most likely be
+ on the form "c.ID", "c.NAME", etc. which are not equal to the columns
+ specified in the mappings ("ID" and "NAME").</para>
- <para>
- The query was intended to return two Cat instances per
- row: a cat and its mother. The query will, however, fail because there is a conflict of
- names; the instances are mapped to the same column names. Also, on some
- databases the returned column aliases will most likely be on the form
- "c.ID", "c.NAME", etc. which are not equal to the columns specified in
- the mappings ("ID" and "NAME").
- </para>
-
<para>The following form is not vulnerable to column name
duplication:</para>
- <programlisting role="JAVA"><![CDATA[sess.createSQLQuery("SELECT {cat.*}, {mother.*} FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ <programlisting role="JAVA">sess.createSQLQuery("SELECT {cat.*}, {mother.*} FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
.addEntity("cat", Cat.class)
.addEntity("mother", Cat.class)
-]]></programlisting>
+</programlisting>
<para>This query specified:</para>
@@ -238,35 +233,35 @@
</itemizedlist>
<para>The {cat.*} and {mother.*} notation used above is a shorthand for
- "all properties". Alternatively, you can list the columns explicitly, but
- even in this case Hibernate injects the SQL column aliases for
- each property. The placeholder for a column alias is just the property
- name qualified by the table alias. In the following example, you retrieve
+ "all properties". Alternatively, you can list the columns explicitly,
+ but even in this case Hibernate injects the SQL column aliases for each
+ property. The placeholder for a column alias is just the property name
+ qualified by the table alias. In the following example, you retrieve
Cats and their mothers from a different table (cat_log) to the one
- declared in the mapping metadata. You can even use the
- property aliases in the where clause.</para>
+ declared in the mapping metadata. You can even use the property aliases
+ in the where clause.</para>
- <programlisting role="JAVA"><![CDATA[String sql = "SELECT ID as {c.id}, NAME as {c.name}, " +
+ <programlisting role="JAVA">String sql = "SELECT ID as {c.id}, NAME as {c.name}, " +
"BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
"FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
List loggedCats = sess.createSQLQuery(sql)
.addEntity("cat", Cat.class)
.addEntity("mother", Cat.class).list()
-]]></programlisting>
+</programlisting>
<section id="querysql-aliasreferences" revision="2">
<title>Alias and property references</title>
- <para>In most cases the above alias injection is needed. For
- queries relating to more complex mappings, like composite properties,
+ <para>In most cases the above alias injection is needed. For queries
+ relating to more complex mappings, like composite properties,
inheritance discriminators, collections etc., you can use specific
aliases that allow Hibernate to inject the proper aliases.</para>
- <para>The following table shows the different ways you can use
- the alias injection. Please note that the alias names in the result are simply examples;
- each alias will have a unique and probably different name when
- used.</para>
+ <para>The following table shows the different ways you can use the
+ alias injection. Please note that the alias names in the result are
+ simply examples; each alias will have a unique and probably different
+ name when used.</para>
<table frame="topbot" id="aliasinjection-summary">
<title>Alias injection names</title>
@@ -378,13 +373,14 @@
<section>
<title>Returning non-managed entities</title>
- <para>It is possible to apply a ResultTransformer to native SQL queries, allowing it to return non-managed entities.</para>
+ <para>It is possible to apply a ResultTransformer to native SQL queries,
+ allowing it to return non-managed entities.</para>
- <programlisting role="JAVA"><![CDATA[sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS")
- .setResultTransformer(Transformers.aliasToBean(CatDTO.class))]]></programlisting>
-
- <para>This query specified:</para>
+ <programlisting role="JAVA">sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS")
+ .setResultTransformer(Transformers.aliasToBean(CatDTO.class))</programlisting>
+ <para>This query specified:</para>
+
<itemizedlist>
<listitem>
<para>the SQL query string</para>
@@ -394,19 +390,18 @@
<para>a result transformer</para>
</listitem>
</itemizedlist>
-
- <para>
- The above query will return a list of <literal>CatDTO</literal> which has been instantiated and injected the values of NAME and BIRTHNAME into its corresponding
- properties or fields.
- </para>
+
+ <para>The above query will return a list of <literal>CatDTO</literal>
+ which has been instantiated and injected the values of NAME and
+ BIRTHNAME into its corresponding properties or fields.</para>
</section>
<section>
<title>Handling inheritance</title>
- <para>Native SQL queries which query for entities that are mapped as part
- of an inheritance must include all properties for the baseclass and all
- its subclasses.</para>
+ <para>Native SQL queries which query for entities that are mapped as
+ part of an inheritance must include all properties for the baseclass and
+ all its subclasses.</para>
</section>
<section>
@@ -415,46 +410,56 @@
<para>Native SQL queries support positional as well as named
parameters:</para>
- <programlisting role="JAVA"><![CDATA[Query query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class);
+ <programlisting role="JAVA">Query query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class);
List pusList = query.setString(0, "Pus%").list();
query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like :name").addEntity(Cat.class);
-List pusList = query.setString("name", "Pus%").list(); ]]></programlisting>
+List pusList = query.setString("name", "Pus%").list(); </programlisting>
</section>
-
-
-
</section>
<section id="querysql-namedqueries" revision="3">
<title>Named SQL queries</title>
- <para>Named SQL queries can be defined in the mapping document and called
- in exactly the same way as a named HQL query. In this case, you do
+ <para>Named SQL queries can also be defined in the mapping document and
+ called in exactly the same way as a named HQL query (see <xref
+ linkend="objectstate-querying-executing-named" />). In this case, you do
<emphasis>not</emphasis> need to call
<literal>addEntity()</literal>.</para>
- <programlisting role="XML"><![CDATA[<sql-query name="persons">
- <return alias="person" class="eg.Person"/>
+ <example>
+ <title>Named sql query using the <sql-query> maping
+ element</title>
+
+ <programlisting role="XML"><sql-query name="persons">
+ <return alias="person" class="eg.Person"/>
SELECT person.NAME AS {person.name},
person.AGE AS {person.age},
person.SEX AS {person.sex}
FROM PERSON person
WHERE person.NAME LIKE :namePattern
-</sql-query>]]></programlisting>
+</sql-query></programlisting>
+ </example>
- <programlisting role="JAVA"><![CDATA[List people = sess.getNamedQuery("persons")
+ <example>
+ <title>Execution of a named query</title>
+
+ <programlisting role="JAVA">List people = sess.getNamedQuery("persons")
.setString("namePattern", namePattern)
.setMaxResults(50)
- .list();]]></programlisting>
+ .list();</programlisting>
+ </example>
- <para>The <literal><return-join></literal> element is use to join associations and
- the <literal><load-collection></literal> element is used to define queries which initialize collections,
- </para>
+ <para>The <literal><return-join></literal> element is use to join
+ associations and the <literal><load-collection></literal> element is
+ used to define queries which initialize collections,</para>
- <programlisting role="XML"><![CDATA[<sql-query name="personsWith">
- <return alias="person" class="eg.Person"/>
- <return-join alias="address" property="person.mailingAddress"/>
+ <example>
+ <title>Named sql query with association</title>
+
+ <programlisting role="XML"><sql-query name="personsWith">
+ <return alias="person" class="eg.Person"/>
+ <return-join alias="address" property="person.mailingAddress"/>
SELECT person.NAME AS {person.name},
person.AGE AS {person.age},
person.SEX AS {person.sex},
@@ -466,31 +471,40 @@
JOIN ADDRESS address
ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
WHERE person.NAME LIKE :namePattern
-</sql-query>]]></programlisting>
+</sql-query></programlisting>
+ </example>
<para>A named SQL query may return a scalar value. You must declare the
column alias and Hibernate type using the
<literal><return-scalar></literal> element:</para>
- <programlisting role="XML"><![CDATA[<sql-query name="mySqlQuery">
- <return-scalar column="name" type="string"/>
- <return-scalar column="age" type="long"/>
- SELECT p.NAME AS name,
+ <example>
+ <title>Named query returning a scalar</title>
+
+ <programlisting role="XML"><sql-query name="mySqlQuery">
+ <return-scalar column="name" type="string"/>
+ <return-scalar column="age" type="long"/>
+ SELECT p.NAME AS name,
p.AGE AS age,
FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
-</sql-query>]]></programlisting>
+</sql-query></programlisting>
+ </example>
<para>You can externalize the resultset mapping information in a
- <literal><resultset></literal> element which will allow you to either reuse them across
- several named queries or through the
+ <literal><resultset></literal> element which will allow you to
+ either reuse them across several named queries or through the
<literal>setResultSetMapping()</literal> API.</para>
- <programlisting role="XML"><![CDATA[<resultset name="personAddress">
- <return alias="person" class="eg.Person"/>
- <return-join alias="address" property="person.mailingAddress"/>
-</resultset>
+ <example>
+ <title><resultset> mapping used to externalize mapping
+ information</title>
-<sql-query name="personsWith" resultset-ref="personAddress">
+ <programlisting role="XML"><resultset name="personAddress">
+ <return alias="person" class="eg.Person"/>
+ <return-join alias="address" property="person.mailingAddress"/>
+</resultset>
+
+<sql-query name="personsWith" resultset-ref="personAddress">
SELECT person.NAME AS {person.name},
person.AGE AS {person.age},
person.SEX AS {person.sex},
@@ -502,64 +516,308 @@
JOIN ADDRESS address
ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
WHERE person.NAME LIKE :namePattern
-</sql-query>]]></programlisting>
+</sql-query></programlisting>
+ </example>
- <para>You can, alternatively, use the resultset mapping information in your
- hbm files directly in java code.</para>
+ <para>You can, alternatively, use the resultset mapping information in
+ your hbm files directly in java code.</para>
- <programlisting role="JAVA"><![CDATA[List cats = sess.createSQLQuery(
+ <example>
+ <title>Programmatically specifying the result mapping information
+ </title>
+
+ <programlisting role="JAVA">List cats = sess.createSQLQuery(
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
)
.setResultSetMapping("catAndKitten")
- .list();]]></programlisting>
+ .list();</programlisting>
+ </example>
+ <para>So far we have only looked at externalizing SQL queries using
+ Hibernate mapping files. The same concept is also available with
+ anntations and is called named native queries. You can use
+ <classname>@NamedNativeQuery</classname>
+ (<classname>@NamedNativeQueries</classname>) in conjunction with
+ <literal>@SqlResultSetMapping</literal>
+ (<literal>@SqlResultSetMappings</literal>). Like
+ <literal>@NamedQuery</literal>, <classname>@NamedNativeQuery</classname>
+ and <literal>@SqlResultSetMapping</literal> can be defined at class level,
+ but their scope is global to the application. Lets look at a view
+ examples.</para>
+
+ <para><xref
+ linkend="example-named-native-query-annotation-with-result-set-mapping" />
+ shows how 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. In the example 2 entities, <literal>Night</literal> and
+ <literal>Area</literal>, are returned and each property is declared and
+ associated to a column name, actually the column name retrieved by the
+ query. </para>
+
+ <para>In <xref linkend="example-implicit-result-set-mapping" /> the result
+ set mapping is implicit. We only describe the entity class of the result
+ set mapping. The property / column mappings is done using the entity
+ mapping values. In this case the model property is bound to the model_txt
+ column. </para>
+
+ <para>Finally, 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.
+ This can be seen in <xref
+ linkend="example-field-result-annotation-with-associations" />.</para>
+
+ <example id="example-named-native-query-annotation-with-result-set-mapping">
+ <title>Named SQL query using <classname>@NamedNativeQuery</classname>
+ together with <classname>@SqlResultSetMapping</classname></title>
+
+ <programlisting language="JAVA" role="JAVA">@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",
+ resultSetMapping="joinMapping")
+ at SqlResultSetMapping(name="joinMapping", entities={
+ @EntityResult(entityClass=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>
+ </example>
+
+ <example id="example-implicit-result-set-mapping">
+ <title>Implicit result set mapping</title>
+
+ <programlisting language="JAVA" role="JAVA">@Entity
+ at SqlResultSetMapping(name="implicit",
+ entities=@EntityResult(entityClass=SpaceShip.class))
+ at NamedNativeQuery(name="implicitSample",
+ query="select * from SpaceShip",
+ resultSetMapping="implicit")
+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>
+ </example>
+
+ <example id="example-field-result-annotation-with-associations">
+ <title>Using dot notation in @FieldResult for specifying associations
+ </title>
+
+ <programlisting language="JAVA" role="JAVA">@Entity
+ at SqlResultSetMapping(name="compositekey",
+ entities=@EntityResult(entityClass=SpaceShip.class,
+ fields = {
+ @FieldResult(name="name", column = "name"),
+ @FieldResult(name="model", column = "model"),
+ @FieldResult(name="speed", column = "speed"),
+ @FieldResult(name="captain.firstname", column = "firstn"),
+ @FieldResult(name="captain.lastname", column = "lastn"),
+ @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>
+ </example>
+
+ <tip>
+ <para>If you retrieve a single entity using the default mapping, you can
+ specify the <literal>resultClass</literal> attribute instead of
+ <literal>resultSetMapping</literal>:</para>
+
+ <programlisting language="JAVA" role="JAVA">@NamedNativeQuery(name="implicitSample", query="select * from SpaceShip", resultClass=SpaceShip.class)
+public class SpaceShip {</programlisting>
+ </tip>
+
+ <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>
+
+ <example>
+ <title>Scalar values via <classname>@ColumnResult</classname></title>
+
+ <programlisting language="JAVA" role="JAVA">@SqlResultSetMapping(name="scalar", columns=@ColumnResult(name="dimension"))
+ at NamedNativeQuery(name="scalar", query="select length*width as dimension from SpaceShip", resultSetMapping="scalar")</programlisting>
+ </example>
+
+ <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>
+
<section id="propertyresults">
<title>Using return-property to explicitly specify column/alias
names</title>
- <para>You can explicitly
- tell Hibernate what column aliases to use with <literal><return-property></literal>, instead of using the
- <literal>{}</literal>-syntax to let Hibernate inject its own
- aliases.For example:</para>
+ <para>You can explicitly tell Hibernate what column aliases to use with
+ <literal><return-property></literal>, instead of using the
+ <literal>{}</literal>-syntax to let Hibernate inject its own aliases.For
+ example:</para>
- <programlisting role="XML"><![CDATA[<sql-query name="mySqlQuery">
- <return alias="person" class="eg.Person">
- <return-property name="name" column="myName"/>
- <return-property name="age" column="myAge"/>
- <return-property name="sex" column="mySex"/>
- </return>
+ <programlisting role="XML"><sql-query name="mySqlQuery">
+ <return alias="person" class="eg.Person">
+ <return-property name="name" column="myName"/>
+ <return-property name="age" column="myAge"/>
+ <return-property name="sex" column="mySex"/>
+ </return>
SELECT person.NAME AS myName,
person.AGE AS myAge,
person.SEX AS mySex,
FROM PERSON person WHERE person.NAME LIKE :name
-</sql-query>
-]]></programlisting>
+</sql-query>
+</programlisting>
<para><literal><return-property></literal> also works with
multiple columns. This solves a limitation with the
<literal>{}</literal>-syntax which cannot allow fine grained control of
multi-column properties.</para>
- <programlisting role="XML"><![CDATA[<sql-query name="organizationCurrentEmployments">
- <return alias="emp" class="Employment">
- <return-property name="salary">
- <return-column name="VALUE"/>
- <return-column name="CURRENCY"/>
- </return-property>
- <return-property name="endDate" column="myEndDate"/>
- </return>
+ <programlisting role="XML"><sql-query name="organizationCurrentEmployments">
+ <return alias="emp" class="Employment">
+ <return-property name="salary">
+ <return-column name="VALUE"/>
+ <return-column name="CURRENCY"/>
+ </return-property>
+ <return-property name="endDate" column="myEndDate"/>
+ </return>
SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
FROM EMPLOYMENT
WHERE EMPLOYER = :id AND ENDDATE IS NULL
ORDER BY STARTDATE ASC
-</sql-query>]]></programlisting>
+</sql-query></programlisting>
- <para>In this example
- <literal><return-property></literal> was used in combination with the
- <literal>{}</literal>-syntax for injection. This allows users to choose how
- they want to refer column and properties.</para>
+ <para>In this example <literal><return-property></literal> was
+ used in combination with the <literal>{}</literal>-syntax for injection.
+ This allows users to choose how they want to refer column and
+ properties.</para>
<para>If your mapping has a discriminator you must use
<literal><return-discriminator></literal> to specify the
@@ -569,13 +827,13 @@
<section id="sp_query" revision="1">
<title>Using stored procedures for querying</title>
- <para>Hibernate3 provides support for queries via stored procedures
- and functions. Most of the following documentation is equivalent for
- both. The stored procedure/function must return a resultset as the first
+ <para>Hibernate3 provides support for queries via stored procedures and
+ functions. Most of the following documentation is equivalent for both.
+ The stored procedure/function must return a resultset as the first
out-parameter to be able to work with Hibernate. An example of such a
stored function in Oracle 9 and higher is as follows:</para>
- <programlisting role="XML"><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
+ <programlisting role="XML">CREATE OR REPLACE FUNCTION selectAllEmployments
RETURN SYS_REFCURSOR
AS
st_cursor SYS_REFCURSOR;
@@ -586,40 +844,41 @@
REGIONCODE, EID, VALUE, CURRENCY
FROM EMPLOYMENT;
RETURN st_cursor;
- END;]]></programlisting>
+ END;</programlisting>
<para>To use this query in Hibernate you need to map it via a named
query.</para>
- <programlisting role="XML"><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
- <return alias="emp" class="Employment">
- <return-property name="employee" column="EMPLOYEE"/>
- <return-property name="employer" column="EMPLOYER"/>
- <return-property name="startDate" column="STARTDATE"/>
- <return-property name="endDate" column="ENDDATE"/>
- <return-property name="regionCode" column="REGIONCODE"/>
- <return-property name="id" column="EID"/>
- <return-property name="salary">
- <return-column name="VALUE"/>
- <return-column name="CURRENCY"/>
- </return-property>
- </return>
+ <programlisting role="XML"><sql-query name="selectAllEmployees_SP" callable="true">
+ <return alias="emp" class="Employment">
+ <return-property name="employee" column="EMPLOYEE"/>
+ <return-property name="employer" column="EMPLOYER"/>
+ <return-property name="startDate" column="STARTDATE"/>
+ <return-property name="endDate" column="ENDDATE"/>
+ <return-property name="regionCode" column="REGIONCODE"/>
+ <return-property name="id" column="EID"/>
+ <return-property name="salary">
+ <return-column name="VALUE"/>
+ <return-column name="CURRENCY"/>
+ </return-property>
+ </return>
{ ? = call selectAllEmployments() }
-</sql-query>]]></programlisting>
+</sql-query></programlisting>
- <para>Stored procedures currently only return scalars and
- entities. <literal><return-join></literal> and
+ <para>Stored procedures currently only return scalars and entities.
+ <literal><return-join></literal> and
<literal><load-collection></literal> are not supported.</para>
<section id="querysql-limits-storedprocedures" revision="1">
<title>Rules/limitations for using stored procedures</title>
- <para>You cannot use stored procedures with Hibernate unless you follow some procedure/function
- rules. If they do not follow those rules they are
- not usable with Hibernate. If you still want to use these procedures
- you have to execute them via <literal>session.connection()</literal>.
- The rules are different for each database, since database vendors have
- different stored procedure semantics/syntax.</para>
+ <para>You cannot use stored procedures with Hibernate unless you
+ follow some procedure/function rules. If they do not follow those
+ rules they are not usable with Hibernate. If you still want to use
+ these procedures you have to execute them via
+ <literal>session.connection()</literal>. The rules are different for
+ each database, since database vendors have different stored procedure
+ semantics/syntax.</para>
<para>Stored procedure queries cannot be paged with
<literal>setFirstResult()/setMaxResults()</literal>.</para>
@@ -647,10 +906,10 @@
<itemizedlist spacing="compact">
<listitem>
<para>The procedure must return a result set. Note that since
- these servers can return multiple result sets and update
- counts, Hibernate will iterate the results and take the first
- result that is a result set as its return value. Everything else
- will be discarded.</para>
+ these servers can return multiple result sets and update counts,
+ Hibernate will iterate the results and take the first result that
+ is a result set as its return value. Everything else will be
+ discarded.</para>
</listitem>
<listitem>
@@ -666,63 +925,61 @@
<section id="querysql-cud">
<title>Custom SQL for create, update and delete</title>
- <para>Hibernate3 can use custom SQL for create, update, and delete operations.
- The SQL can be overridden at the statement level or inidividual column level. This
- section describes statement overrides. For columns, see
- <xref linkend="mapping-column-read-and-write"/>.
- </para>
- <para>
- The class and collection persisters in Hibernate already contain a set of
- configuration time generated strings (insertsql, deletesql, updatesql etc.).
- The mapping tags
- <literal><sql-insert></literal>,
+ <para>Hibernate3 can use custom SQL for create, update, and delete
+ operations. The SQL can be overridden at the statement level or
+ inidividual column level. This section describes statement overrides. For
+ columns, see <xref linkend="mapping-column-read-and-write" />.</para>
+
+ <para>The class and collection persisters in Hibernate already contain a
+ set of configuration time generated strings (insertsql, deletesql,
+ updatesql etc.). The mapping tags <literal><sql-insert></literal>,
<literal><sql-delete></literal>, and
<literal><sql-update></literal> override these strings:</para>
- <programlisting role="XML"><![CDATA[<class name="Person">
- <id name="id">
- <generator class="increment"/>
- </id>
- <property name="name" not-null="true"/>
- <sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
- <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
- <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
-</class>]]></programlisting>
+ <programlisting role="XML"><class name="Person">
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <property name="name" not-null="true"/>
+ <sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
+ <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
+ <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
+</class></programlisting>
- <para>The SQL is directly executed in your database, so you can
- use any dialect you like. This will reduce the portability of
- your mapping if you use database specific SQL.</para>
+ <para>The SQL is directly executed in your database, so you can use any
+ dialect you like. This will reduce the portability of your mapping if you
+ use database specific SQL.</para>
<para>Stored procedures are supported if the <literal>callable</literal>
attribute is set:</para>
- <programlisting role="XML"><![CDATA[<class name="Person">
- <id name="id">
- <generator class="increment"/>
- </id>
- <property name="name" not-null="true"/>
- <sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
- <sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
- <sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
-</class>]]></programlisting>
+ <programlisting role="XML"><class name="Person">
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <property name="name" not-null="true"/>
+ <sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
+ <sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
+ <sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
+</class></programlisting>
- <para>The order of the positional parameters is vital, as they
- must be in the same sequence as Hibernate expects them.</para>
+ <para>The order of the positional parameters is vital, as they must be in
+ the same sequence as Hibernate expects them.</para>
<para>You can view the expected order by enabling debug logging for the
<literal>org.hibernate.persister.entity</literal> level. With this level
enabled, Hibernate will print out the static SQL that is used to create,
- update, delete etc. entities. To view the expected sequence, do
- not include your custom SQL in the mapping files, as this will override the
+ update, delete etc. entities. To view the expected sequence, do not
+ include your custom SQL in the mapping files, as this will override the
Hibernate generated static SQL.</para>
- <para>The stored procedures are in most cases
- required to return the number of rows inserted, updated and deleted, as
- Hibernate has some runtime checks for the success of the statement.
- Hibernate always registers the first statement parameter as a numeric
- output parameter for the CUD operations:</para>
+ <para>The stored procedures are in most cases required to return the
+ number of rows inserted, updated and deleted, as Hibernate has some
+ runtime checks for the success of the statement. Hibernate always
+ registers the first statement parameter as a numeric output parameter for
+ the CUD operations:</para>
- <programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
+ <programlisting>CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
RETURN NUMBER IS
BEGIN
@@ -734,7 +991,7 @@
return SQL%ROWCOUNT;
-END updatePerson;]]></programlisting>
+END updatePerson;</programlisting>
</section>
<section id="querysql-load">
@@ -742,59 +999,58 @@
<para>You can also declare your own SQL (or HQL) queries for entity
loading. As with inserts, updates, and deletes, this can be done at the
- individual column level as described in
- <xref linkend="mapping-column-read-and-write"/>
- or at the statement level. Here is an example of a statement level override:
- </para>
+ individual column level as described in <xref
+ linkend="mapping-column-read-and-write" /> or at the statement level. Here
+ is an example of a statement level override:</para>
- <programlisting role="XML"><![CDATA[<sql-query name="person">
- <return alias="pers" class="Person" lock-mode="upgrade"/>
+ <programlisting role="XML"><sql-query name="person">
+ <return alias="pers" class="Person" lock-mode="upgrade"/>
SELECT NAME AS {pers.name}, ID AS {pers.id}
FROM PERSON
WHERE ID=?
FOR UPDATE
-</sql-query>]]></programlisting>
+</sql-query></programlisting>
<para>This is just a named query declaration, as discussed earlier. You
can reference this named query in a class mapping:</para>
- <programlisting role="XML"><![CDATA[<class name="Person">
- <id name="id">
- <generator class="increment"/>
- </id>
- <property name="name" not-null="true"/>
- <loader query-ref="person"/>
-</class>]]></programlisting>
+ <programlisting role="XML"><class name="Person">
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <property name="name" not-null="true"/>
+ <loader query-ref="person"/>
+</class></programlisting>
<para>This even works with stored procedures.</para>
<para>You can even define a query for collection loading:</para>
- <programlisting role="XML"><![CDATA[<set name="employments" inverse="true">
- <key/>
- <one-to-many class="Employment"/>
- <loader query-ref="employments"/>
-</set>]]></programlisting>
+ <programlisting role="XML"><set name="employments" inverse="true">
+ <key/>
+ <one-to-many class="Employment"/>
+ <loader query-ref="employments"/>
+</set></programlisting>
- <programlisting role="XML"><![CDATA[<sql-query name="employments">
- <load-collection alias="emp" role="Person.employments"/>
+ <programlisting role="XML"><sql-query name="employments">
+ <load-collection alias="emp" role="Person.employments"/>
SELECT {emp.*}
FROM EMPLOYMENT emp
WHERE EMPLOYER = :id
ORDER BY STARTDATE ASC, EMPLOYEE ASC
-</sql-query>]]></programlisting>
+</sql-query></programlisting>
- <para>You can also define an entity loader that loads a collection by
- join fetching:</para>
+ <para>You can also define an entity loader that loads a collection by join
+ fetching:</para>
- <programlisting role="XML"><![CDATA[<sql-query name="person">
- <return alias="pers" class="Person"/>
- <return-join alias="emp" property="pers.employments"/>
+ <programlisting role="XML"><sql-query name="person">
+ <return alias="pers" class="Person"/>
+ <return-join alias="emp" property="pers.employments"/>
SELECT NAME AS {pers.*}, {emp.*}
FROM PERSON pers
LEFT OUTER JOIN EMPLOYMENT emp
ON pers.ID = emp.PERSON_ID
WHERE ID=?
-</sql-query>]]></programlisting>
+</sql-query></programlisting>
</section>
</chapter>
Modified: core/trunk/documentation/manual/src/main/docbook/en-US/content/session_api.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/session_api.xml 2010-07-16 15:24:32 UTC (rev 19960)
+++ core/trunk/documentation/manual/src/main/docbook/en-US/content/session_api.xml 2010-07-16 15:27:49 UTC (rev 19961)
@@ -454,22 +454,63 @@
<section id="objectstate-querying-executing-named" revision="1">
<title>Externalizing named queries</title>
- <para>You can also define named queries in the mapping document.
- Remember to use a <literal>CDATA</literal> section if your query
- contains characters that could be interpreted as markup.</para>
+ <para>Queries can also be configured as so called named queries using
+ annotations or Hibernate mapping documents.
+ <literal>@NamedQuery</literal> and <literal>@NamedQueries</literal>
+ can be defined at the class level as seen in <xref
+ linkend="example-named-query-annotation" /> . 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 role="XML"><query name="ByNameAndMaximumWeight"><![CDATA[
+ <example id="example-named-query-annotation">
+ <title>Defining a named query using
+ <classname>@NamedQuery</classname></title>
+
+ <programlisting language="JAVA" role="JAVA">@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>
+ </example>
+
+ <para>Using a mapping document can be configured using the
+ <literal><query></literal> node. Remember to use a
+ <literal>CDATA</literal> section if your query contains characters
+ that could be interpreted as markup.</para>
+
+ <example>
+ <title>Defining a named query using
+ <literal><query></literal></title>
+
+ <programlisting role="XML"><query name="ByNameAndMaximumWeight"><![CDATA[
from eg.DomesticCat as cat
where cat.name = ?
and cat.weight > ?
] ]></query></programlisting>
+ </example>
- <para>Parameter binding and executing is done programatically:</para>
+ <para>Parameter binding and executing is done programatically as seen
+ in <xref linkend="example-parameter-binding-named-query" />.</para>
- <programlisting role="JAVA">Query q = sess.getNamedQuery("ByNameAndMaximumWeight");
+ <example id="example-parameter-binding-named-query">
+ <title>Parameter binding of a named query</title>
+
+ <programlisting role="JAVA">Query q = sess.getNamedQuery("ByNameAndMaximumWeight");
q.setString(0, name);
q.setInt(1, minWeight);
List cats = q.list();</programlisting>
+ </example>
<para>The actual program code is independent of the query language
that is used. You can also define native SQL queries in metadata, or
@@ -1042,7 +1083,7 @@
<note>
<para>CascadeType.ALL also covers Hibernate specific operations like
- save-update, lock etc... </para>
+ save-update, lock etc...</para>
</note>
<para>A special cascade style, <literal>delete-orphan</literal>, applies
More information about the hibernate-commits
mailing list