Second batch of doco updates
git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@4366 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
7225b36735
commit
8c6da481a6
|
@ -62,22 +62,22 @@
|
|||
|
||||
|
||||
|
||||
<sect2 id="mapping-declaration-doctype">
|
||||
<sect2 id="mapping-declaration-doctype" revision="1">
|
||||
<title>Doctype</title>
|
||||
|
||||
<para>
|
||||
All XML mappings should declare the doctype shown. The actual DTD may be found
|
||||
at the URL above, in the directory <literal>hibernate-x.x.x/src/net/sf/hibernate
|
||||
</literal> or in <literal>hibernate.jar</literal>. Hibernate will always look for
|
||||
at the URL above, in the directory <literal>hibernate-x.x.x/src/org/hibernate
|
||||
</literal> or in <literal>hibernate3.jar</literal>. Hibernate will always look for
|
||||
the DTD in its classpath first.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="mapping-declaration-mapping">
|
||||
<sect2 id="mapping-declaration-mapping" revision="1">
|
||||
<title>hibernate-mapping</title>
|
||||
|
||||
<para>
|
||||
This element has three optional attributes. The <literal>schema</literal> attribute
|
||||
This element has several optional attributes. The <literal>schema</literal> attribute
|
||||
specifies that tables referred to by this mapping belong to the named schema. If specified,
|
||||
tablenames will be qualified by the given schema name. If missing, tablenames will be
|
||||
unqualified. The <literal>default-cascade</literal> attribute specifies what cascade style
|
||||
|
@ -92,10 +92,12 @@
|
|||
<area id="hm2" coords="3 55"/>
|
||||
<area id="hm3" coords="4 55"/>
|
||||
<area id="hm4" coords="5 55"/>
|
||||
</areaspec>
|
||||
<area id="hm5" coords="6 55"/>
|
||||
</areaspec>
|
||||
<programlisting><![CDATA[<hibernate-mapping
|
||||
schema="schemaName"
|
||||
default-cascade="none|save-update"
|
||||
default-access="field|property|ClassName"
|
||||
auto-import="true|false"
|
||||
package="package.name"
|
||||
/>]]></programlisting>
|
||||
|
@ -112,13 +114,20 @@
|
|||
</para>
|
||||
</callout>
|
||||
<callout arearefs="hm3">
|
||||
<para>
|
||||
<literal>default-access</literal> (optional - defaults to <literal>property</literal>):
|
||||
The strategy Hibernate should use for accessing all properties. Can be a custom
|
||||
implementation of <literal>PropertyAccessor</literal>.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="hm4">
|
||||
<para>
|
||||
<literal>auto-import</literal> (optional - defaults to <literal>true</literal>):
|
||||
Specifies whether we can use unqualified class names (of classes in this mapping)
|
||||
in the query language.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="hm4">
|
||||
<callout arearefs="hm5">
|
||||
<para>
|
||||
<literal>package</literal> (optional): Specifies a package prefix to assume for
|
||||
unqualified class names in the mapping document.
|
||||
|
@ -133,10 +142,10 @@
|
|||
to assign two classes to the same "imported" name.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="mapping-declaration-class">
|
||||
<title>class</title>
|
||||
<sect2 id="mapping-declaration-class" revision="1">
|
||||
<title>class, dynamic-class</title>
|
||||
|
||||
<para>
|
||||
You may declare a persistent class using the <literal>class</literal> element:
|
||||
|
@ -159,7 +168,12 @@
|
|||
<area id="class13" coords="14 55"/>
|
||||
<area id="class14" coords="15 55"/>
|
||||
<area id="class15" coords="16 55"/>
|
||||
</areaspec>
|
||||
<area id="class16" coords="17 55"/>
|
||||
<area id="class17" coords="18 55"/>
|
||||
<area id="class18" coords="19 55"/>
|
||||
<area id="class19" coords="20 55"/>
|
||||
<area id="class20" coords="21 55"/>
|
||||
</areaspec>
|
||||
<programlisting><![CDATA[<class
|
||||
name="ClassName"
|
||||
table="tableName"
|
||||
|
@ -176,6 +190,11 @@
|
|||
batch-size="N"
|
||||
optimistic-lock="none|version|dirty|all"
|
||||
lazy="true|false"
|
||||
entity-name="EntityName"
|
||||
catalog="catalog"
|
||||
check="arbitrary sql check condition"
|
||||
rowid="TODO"
|
||||
subselect="TODO"
|
||||
/>]]></programlisting>
|
||||
<calloutlist>
|
||||
<callout arearefs="class1">
|
||||
|
@ -274,6 +293,33 @@
|
|||
interface.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="class16">
|
||||
<para>
|
||||
<literal>entity-name</literal> (optional): TODO
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="class17">
|
||||
<para>
|
||||
<literal>catalog</literal> (optional): The name of a database catalog used for this
|
||||
class and its table.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="class18">
|
||||
<para>
|
||||
<literal>check</literal> (optional): A SQL expression used to generate a multi-row
|
||||
<emphasis>check</emphasis> constraint for automatic schema generation.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="class19">
|
||||
<para>
|
||||
<literal>rowid</literal> (optional): TODO
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="class19">
|
||||
<para>
|
||||
<literal>subselect</literal> (optional): TODO
|
||||
</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
</programlistingco>
|
||||
|
||||
|
@ -367,6 +413,69 @@
|
|||
what <literal>unsaved-value</literal> strategy, or an instance will be detected as
|
||||
transient.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
TODO: Document entity name and dynamic class
|
||||
</para>
|
||||
|
||||
<para>
|
||||
TODO: Document subselect and and synchronize for view simulation
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="mapping-declaration-join">
|
||||
<title>join</title>
|
||||
|
||||
<para>
|
||||
Using the <literal><join></literal> element, it is possible to map
|
||||
properties of one class to several tables.
|
||||
</para>
|
||||
|
||||
<programlistingco>
|
||||
<areaspec>
|
||||
<area id="join1" coords="2 50"/>
|
||||
<area id="join2" coords="3 50" />
|
||||
<area id="join3" coords="4 50"/>
|
||||
<area id="join4" coords="5 50" />
|
||||
</areaspec>
|
||||
<programlisting><![CDATA[<join
|
||||
table="tablename"
|
||||
schema="owner"
|
||||
catalog="catalog"
|
||||
sequential-select="true|false"
|
||||
/>]]></programlisting>
|
||||
|
||||
<calloutlist>
|
||||
<callout arearefs="join1">
|
||||
<para>
|
||||
<literal>tabe</literal>: The name of the joined table.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="join2">
|
||||
<para>
|
||||
<literal>schema</literal> (optional): Override the schema name specified by
|
||||
the root <literal><hibernate-mapping></literal> element.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="join3">
|
||||
<para>
|
||||
<literal>catalog</literal> (optional): Name of the database catalog.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="join4">
|
||||
<para>
|
||||
<literal>sequential-select</literal> (optional - defaults to <literal>true</literal>):
|
||||
TODO: Document join behavior
|
||||
</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
</programlistingco>
|
||||
|
||||
<para>
|
||||
TODO: Document join with an example
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="mapping-declaration-id">
|
||||
|
@ -445,7 +554,7 @@
|
|||
legacy data with composite keys. We strongly discourage its use for anything else.
|
||||
</para>
|
||||
|
||||
<sect3 id="mapping-declaration-id-generator">
|
||||
<sect3 id="mapping-declaration-id-generator" revision="1">
|
||||
<title>generator</title>
|
||||
|
||||
<para>
|
||||
|
@ -544,6 +653,14 @@
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><literal>guid</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
uses the string-based GUID algorithm available in MS SQL Server and MySQL.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><literal>native</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
|
@ -738,7 +855,7 @@
|
|||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="mapping-declaration-discriminator" revision="1">
|
||||
<sect2 id="mapping-declaration-discriminator" revision="2">
|
||||
<title>discriminator</title>
|
||||
|
||||
<para>
|
||||
|
@ -757,12 +874,14 @@
|
|||
<area id="discriminator2" coords="3 40" />
|
||||
<area id="discriminator3" coords="4 40" />
|
||||
<area id="discriminator4" coords="5 40" />
|
||||
<area id="discriminator5" coords="6 40" />
|
||||
</areaspec>
|
||||
<programlisting><![CDATA[<discriminator
|
||||
column="discriminator_column"
|
||||
type="discriminator_type"
|
||||
force="true|false"
|
||||
insert="true|false"
|
||||
formula="arbitrary sql expression"
|
||||
/>]]></programlisting>
|
||||
<calloutlist>
|
||||
<callout arearefs="discriminator1">
|
||||
|
@ -791,6 +910,12 @@
|
|||
of a mapped composite identifier.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="discriminator5">
|
||||
<para>
|
||||
<literal>formula</literal> (optional)
|
||||
an arbitrary SQL expression that is executed when a type has to be evaluated
|
||||
</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
</programlistingco>
|
||||
|
||||
|
@ -805,6 +930,14 @@
|
|||
"extra" discriminator values that are not mapped to a persistent class. This will not
|
||||
usually be the case.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Using the <literal>formula</literal> attribute you can declare an arbitrary SQL expression
|
||||
that will be used to evaluate the type of a row:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<discriminator formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end" type="integer"/>]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="mapping-declaration-version">
|
||||
|
@ -936,7 +1069,7 @@
|
|||
</sect2>
|
||||
|
||||
|
||||
<sect2 id="mapping-declaration-property">
|
||||
<sect2 id="mapping-declaration-property" revision="1">
|
||||
<title>property</title>
|
||||
|
||||
<para>
|
||||
|
@ -1025,11 +1158,6 @@
|
|||
char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob</literal>).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of a subclass of <literal>PersistentEnum</literal> (eg. <literal>eg.Color</literal>).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of a serializable Java class.
|
||||
|
@ -1061,6 +1189,10 @@
|
|||
<literal>org.hibernate.property.PropertyAccessor</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
TODO: Document the nested column formula="" attribute with an example
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="mapping-declaration-manytoone" revision="1">
|
||||
|
@ -1601,6 +1733,22 @@
|
|||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="mapping-declaration-unionsubclass">
|
||||
<title>union-subclass</title>
|
||||
|
||||
<para>
|
||||
Another option is to map only the concrete classes of an inheritance hierarchy
|
||||
(as in table-per-concrete-class) to tables, but not the superclass. This strategy
|
||||
has some problems with polymorphic associations, which can be avoided with a
|
||||
<literal><union-subclass></literal> mapping.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
See the documentation chapter about Inheritance Mapping for more details.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="mapping-declaration-collections">
|
||||
<title>map, set, list, bag</title>
|
||||
|
||||
|
@ -1693,7 +1841,7 @@
|
|||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="mapping-types-basictypes">
|
||||
<sect2 id="mapping-types-basictypes" revision="1">
|
||||
<title>Basic value types</title>
|
||||
|
||||
<para>
|
||||
|
@ -1798,7 +1946,7 @@
|
|||
Maps serializable Java types to an appropriate SQL binary type. You
|
||||
may also indicate the Hibernate type <literal>serializable</literal> with
|
||||
the name of a serializable Java class or interface that does not default
|
||||
to a basic type or implement <literal>PersistentEnum</literal>.
|
||||
to a basic type.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -1831,47 +1979,6 @@
|
|||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="mapping-types-enum">
|
||||
<title>Persistent enum types</title>
|
||||
|
||||
<para>
|
||||
An <emphasis>enumerated</emphasis> type is a common Java idiom where a class has
|
||||
a constant (small) number of immutable instances. You may create a persistent
|
||||
enumerated type by implementing <literal>org.hibernate.PersistentEnum</literal>,
|
||||
defining the operations <literal>toInt()</literal> and <literal>fromInt()</literal>:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
import org.hibernate.PersistentEnum;
|
||||
|
||||
public class Color implements PersistentEnum {
|
||||
private final int code;
|
||||
private Color(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
public static final Color TABBY = new Color(0);
|
||||
public static final Color GINGER = new Color(1);
|
||||
public static final Color BLACK = new Color(2);
|
||||
|
||||
public int toInt() { return code; }
|
||||
|
||||
public static Color fromInt(int code) {
|
||||
switch (code) {
|
||||
case 0: return TABBY;
|
||||
case 1: return GINGER;
|
||||
case 2: return BLACK;
|
||||
default: throw new RuntimeException("Unknown color code");
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
The Hibernate type name is simply the name of the enumerated class, in this case
|
||||
<literal>eg.Color</literal>.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
|
||||
<sect2 id="mapping-types-custom">
|
||||
<title>Custom value types</title>
|
||||
|
||||
|
@ -2051,5 +2158,126 @@ public class Color implements PersistentEnum {
|
|||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="mapping-xdoclet">
|
||||
<title>Using XDOclet markup</title>
|
||||
|
||||
<para>
|
||||
Many Hibernate users prefer to embed mapping information directly in sourcecode using
|
||||
XDoclet <literal>@hibernate.tags</literal>. We will not cover this approach in this
|
||||
document, since strictly it is considered part of XDoclet. However, we include the
|
||||
following example of the <literal>Cat</literal> class with XDoclet mappings.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
import java.util.Set;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @hibernate.class
|
||||
* table="CATS"
|
||||
*/
|
||||
public class Cat {
|
||||
private Long id; // identifier
|
||||
private Date birthdate;
|
||||
private Cat mate;
|
||||
private Set kittens
|
||||
private Color color;
|
||||
private char sex;
|
||||
private float weight;
|
||||
|
||||
/**
|
||||
* @hibernate.id
|
||||
* generator-class="native"
|
||||
* column="CAT_ID"
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
private void setId(Long id) {
|
||||
this.id=id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hibernate.many-to-one
|
||||
* column="MATE_ID"
|
||||
*/
|
||||
public Cat getMate() {
|
||||
return mate;
|
||||
}
|
||||
void setMate(Cat mate) {
|
||||
this.mate = mate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hibernate.property
|
||||
* column="BIRTH_DATE"
|
||||
*/
|
||||
public Date getBirthdate() {
|
||||
return birthdate;
|
||||
}
|
||||
void setBirthdate(Date date) {
|
||||
birthdate = date;
|
||||
}
|
||||
/**
|
||||
* @hibernate.property
|
||||
* column="WEIGHT"
|
||||
*/
|
||||
public float getWeight() {
|
||||
return weight;
|
||||
}
|
||||
void setWeight(float weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hibernate.property
|
||||
* column="COLOR"
|
||||
* not-null="true"
|
||||
*/
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
void setColor(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
/**
|
||||
* @hibernate.set
|
||||
* lazy="true"
|
||||
* order-by="BIRTH_DATE"
|
||||
* @hibernate.collection-key
|
||||
* column="PARENT_ID"
|
||||
* @hibernate.collection-one-to-many
|
||||
*/
|
||||
public Set getKittens() {
|
||||
return kittens;
|
||||
}
|
||||
void setKittens(Set kittens) {
|
||||
this.kittens = kittens;
|
||||
}
|
||||
// addKitten not needed by Hibernate
|
||||
public void addKitten(Cat kitten) {
|
||||
kittens.add(kitten);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hibernate.property
|
||||
* column="SEX"
|
||||
* not-null="true"
|
||||
* update="false"
|
||||
*/
|
||||
public char getSex() {
|
||||
return sex;
|
||||
}
|
||||
void setSex(char sex) {
|
||||
this.sex=sex;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
See the Hibernate web site for more examples of XDoclet and Hibernate.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<chapter id="collections">
|
||||
<title>Collection Mapping</title>
|
||||
|
||||
<sect1 id="collections-persistent">
|
||||
<sect1 id="collections-persistent" revision="1">
|
||||
<title>Persistent Collections</title>
|
||||
|
||||
<para>
|
||||
|
@ -74,9 +74,14 @@ kittens = cat.getKittens(); //Okay, kittens collection is a Set
|
|||
Collection instances are distinguished in the database by a foreign key to
|
||||
the owning entity. This foreign key is referred to as the
|
||||
<emphasis>collection key </emphasis>. The collection key is mapped by
|
||||
the <literal><key></literal> element.
|
||||
the <literal><key></literal> element. If you have a foreign-key constraint
|
||||
set in the database, and have chosen the <literal>ON DELETE CASCADE</literal>
|
||||
option, always use the <literal>on-delete</literal> attribute on your
|
||||
<literal><key></literal> mappings:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<key column="CHILD_ID" on-delete="cascade"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Collections may contain almost any other Hibernate type, including all basic types,
|
||||
custom types, entity types and components. This is an important definition: An object
|
||||
|
|
|
@ -368,7 +368,7 @@ hibernate.dialect = \
|
|||
are also not available in the <literal>hibernate.cfg.xml</literal> file, discusse later.
|
||||
</para>
|
||||
|
||||
<table frame="topbot" id="configuration-optional-properties" revision="4">
|
||||
<table frame="topbot" id="configuration-optional-properties" revision="5">
|
||||
<title>Hibernate Configuration Properties</title>
|
||||
<tgroup cols="2">
|
||||
<colspec colname="c1" colwidth="1*"/>
|
||||
|
@ -731,7 +731,19 @@ hibernate.dialect = \
|
|||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
<literal>hibernate.use_sql_comments</literal>
|
||||
</entry>
|
||||
<entry>
|
||||
If turned on, Hibernate will generate comments inside the SQL, for
|
||||
easier debugging, defaults to <literal>false</literal>.
|
||||
<para>
|
||||
<emphasis role="strong">eg.</emphasis>
|
||||
<literal>true</literal> | <literal>false</literal>
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<chapter id="inheritance">
|
||||
<title>Inheritance Mapping</title>
|
||||
|
||||
<sect1 id="inheritance-strategies" revision="1">
|
||||
<sect1 id="inheritance-strategies" revision="2">
|
||||
<title>The Three Strategies</title>
|
||||
|
||||
<para>
|
||||
|
@ -32,7 +32,8 @@
|
|||
apply as apply to table-per-concrete class mappings. Hibernate does
|
||||
not support mixing <literal><subclass></literal> mappings and
|
||||
<literal><joined-subclass></literal> mappings inside the same
|
||||
<literal><class></literal> element.
|
||||
<literal><class></literal> element. However, it is possible to
|
||||
use a <literal><join></literal> element to map this.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -105,6 +106,14 @@
|
|||
correct from a relational point of view.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
TODO: document usage of join for discriminators in table-per-subclass
|
||||
</para>
|
||||
|
||||
<para>
|
||||
TODO: document usage of join for mixing inheritance mapping strategies
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For either of these two mapping strategies, a polymorphic
|
||||
association to <literal>Payment</literal> is mapped using
|
||||
|
@ -224,11 +233,19 @@
|
|||
not instances of <literal>NonelectronicTransaction</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
TODO: Document union-subclass for polymorphic-table-per-concrete-class mappings
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="inheritance-limitations">
|
||||
<title>Limitations</title>
|
||||
|
||||
<para>
|
||||
TODO: This section needs to be rewritten, Hibernate3 has almost no limitations on inheritance mappings
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate assumes that an association maps to exactly one foreign key column.
|
||||
Multiple associations per foreign key are tolerated (you might need to specify
|
||||
|
|
|
@ -1118,6 +1118,124 @@ finally {
|
|||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="manipulatingdata-filters">
|
||||
<title>Parameterized application views with filters</title>
|
||||
|
||||
<para>
|
||||
Hibernate3 adds the ability to pre-define filter criteria and attach those filters at both
|
||||
a class and a collection level. A filter criteria is the ability to define a restriction clause
|
||||
very similiar to the existing "where" attribute available on the class and various collection
|
||||
elements. Except these filter conditions can be parameterized. The application can then make
|
||||
the decision at runtime whether given filters should be enabled and what their parameter
|
||||
values should be. Filters can be used like database views, but parameterized inside the
|
||||
application.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In order to use filters, they must first be defined and then attached to the appropriate
|
||||
mapping elements. To define a filter, use the <literal><filter-def/></literal> element
|
||||
within a <literal><hibernate-mapping/></literal> element:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<filter-def name="myFilter">
|
||||
<filter-param name="myFilterParam" type="string"/>
|
||||
</filter-def>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Then, this filter can be attached to a class:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="myClass" ...>
|
||||
...
|
||||
<filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
or, to a collection:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set ...>
|
||||
<filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
or, even to both (or multiples of each) at the same time.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The methods on <literal>Session</literal> are: <literal>enableFilter(String filterName)</literal>,
|
||||
<literal>getEnabledFilter(String filterName)</literal>, and <literal>disableFilter(String filterName)</literal>.
|
||||
By default, filters are <emphasis>not</emphasis> enabled for a given session; they must be explcitly
|
||||
enabled through use of the <literal>Session.enabledFilter()</literal> method, which returns an
|
||||
instance of the <literal>Filter</literal> interface. Using the simple filter defined above, this
|
||||
would look like:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");]]></programlisting>
|
||||
|
||||
<para>
|
||||
Note that methods on the org.hibernate.Filter interface do allow the method-chaining common to much of Hibernate.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A full example, using temporal data with an effective record date pattern:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<filter-def name="effectiveDate">
|
||||
<filter-param name="asOfDate" type="date"/>
|
||||
</filter-def>
|
||||
|
||||
<class name="Employee" ...>
|
||||
...
|
||||
<many-to-one name="department" column="dept_id" class="Department"/>
|
||||
<property name="effectiveStartDate" type="date" column="eff_start_dt"/>
|
||||
<property name="effectiveEndDate" type="date" column="eff_end_dt"/>
|
||||
...
|
||||
<!--
|
||||
Note that this assumes non-terminal records have an eff_end_dt set to
|
||||
a max db date for simplicity-sake
|
||||
-->
|
||||
<filter name="effectiveDate"
|
||||
condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
|
||||
</class>
|
||||
|
||||
<class name="Department" ...>
|
||||
...
|
||||
<set name="employees" lazy="true">
|
||||
<key column="dept_id"/>
|
||||
<one-to-many class="Employee"/>
|
||||
<filter name="effectiveDate"
|
||||
condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
|
||||
</set>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Then, in order to ensure that you always get back currently effective records, simply
|
||||
enable the filter on the session prior to retrieving employee data:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = ...;
|
||||
session.enabledFilter("effectiveDate").setParameter("asOfDate", new Date());
|
||||
List results = session.createQuery("from Employee as e where e.salary > :targetSalary")
|
||||
.setLong("targetSalary", new Long(1000000))
|
||||
.list();
|
||||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
In the HQL above, even though we only explicitly mentioned a salary constraint on the results,
|
||||
because of the enabled filter the query will return only currently active employees who have
|
||||
a salary greater than a million dollars.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note: if you plan on using filters with outer joining (either through HQL or load fetching) be
|
||||
careful of the direction of the condition expression. Its safest to set this up for left
|
||||
outer joining; in general, place the parameter first followed by the column name(s) after
|
||||
the operator.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="manipulatingdata-interceptors" revision="1">
|
||||
<title>Interceptors</title>
|
||||
<para>
|
||||
|
@ -1225,7 +1343,98 @@ public class AuditInterceptor implements Interceptor, Serializable {
|
|||
<programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="manipulatingdata-events">
|
||||
<title>Event system</title>
|
||||
|
||||
<para>
|
||||
If you have to react to particular events in your persistence layer, you may
|
||||
also use the Hibernate3 <emphasis>event</emphasis> architecture. The event
|
||||
system can be used in addition or as a replacement for interceptors.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Essentially all of the methods of the <literal>Session</literal> interface correlate
|
||||
to an event. You have a <literal>LoadEvent</literal>, a <literal>FlushEvent</literal>, etc
|
||||
(consult the XML configuration-file DTD or the <literal>org.hibernate.event</literal>
|
||||
package for the full list of defined event types). When a request is made of one of
|
||||
these methods, the Hibernate <literal>Session</literal> generates an appropriate
|
||||
event and passes it to the configured event listener for that type. Out-of-the-box,
|
||||
these listeners implement the same processing in which those methods always resulted.
|
||||
However, you are free to implement a customization of one of the listener interfaces
|
||||
(i.e., the <literal>LoadEvent</literal> is processed by the registered implemenation
|
||||
of the <literal>LoadEventListener</literal> interface), in which case their
|
||||
implementation would be responsible for processing any <literal>load()</literal> requests
|
||||
made of the <literal>Session</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The listeners should be considered effectively singletons; meaning, they are shared between
|
||||
requests, and thus should not save any state as instance variables. The event objects
|
||||
themselves, however, do hold a lot of the context needed for processing as they are unique
|
||||
to each request. Custom event listeners may also make use of the event's context for storage
|
||||
of any needed processing variables. The context is a simple map, but the default listeners
|
||||
don't use the context map at all, so don't worry about over-writing internally required
|
||||
context variables.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A custom listener should implement the appropriate interface for the event it wants to
|
||||
process and/or extend one of the convenience base classes (or even the default event
|
||||
listeners used by Hibernate out-of-the-box as these are declared non-final for this
|
||||
purpose). Custom listeners can either be registered programatically through the
|
||||
<literal>Configuration</literal> object, or specified in the Hibernate configuration
|
||||
XML (declarative configuration through the properties file is not supported). Here's an
|
||||
example of a custom load event listener:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public class MyLoadListener extends DefaultLoadEventListener {
|
||||
// this is the single method defined by the LoadEventListener interface
|
||||
public Object onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
|
||||
throws HibernateException {
|
||||
if ( !MySecurity.isAuthorized( event.getEntityName(), event.getEntityId() ) ) {
|
||||
throw MySecurityException("Unauthorized access");
|
||||
}
|
||||
return super.onLoad(event, loadType);
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
You also need a configuration entry telling Hibernate to use the listener instead
|
||||
of the default listener:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-configuration>
|
||||
<session-factory>
|
||||
...
|
||||
<listener type="load" class="MyLoadListener"/>
|
||||
</session-factory>
|
||||
</hibernate-configuration>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Instead, you may register it programatically:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Configuration cfg = new Configuration();
|
||||
cfg.getSessionEventListenerConfig().setLoadEventListener( new MyLoadListener() );]]></programlisting>
|
||||
|
||||
<para>
|
||||
Listeners registered declaratively cannot share instances. If the same class name is
|
||||
used in multiple <literal><listener/></literal> elements, each reference will
|
||||
result in a seperate instance of that class. If you need the capability to share
|
||||
listener instances between listener types you must use the programatic registration
|
||||
approach.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Why implement an interface and define the specific type during configuration? Well, a
|
||||
listener implementation could implement multiple event listener interfaces. Having the
|
||||
type additionally defined during registration makes it easier to turn custom listeners on
|
||||
or off during configuration.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="manipulatingdata-metadata">
|
||||
<title>Metadata API</title>
|
||||
<para>
|
||||
|
|
|
@ -408,6 +408,62 @@ ICat fritz = (ICat) iter.next();]]></programlisting>
|
|||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="performance-lazyproperties">
|
||||
<title>Using lazy property fetching</title>
|
||||
|
||||
<para>
|
||||
Hibernate3 supports the lazy fetching of individual properties. This optimization technique
|
||||
is also known as <emphasis>fetch groups</emphasis>. Please note that this is mostly a
|
||||
marketing feature, as in practice, optimizing row reads is much more important than
|
||||
optimization of column reads. However, only loading some properties of a class might
|
||||
be useful in extreme cases, when legacy tables have hundreds of columns and the data model
|
||||
can not be improved.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To enable lazy property loading, set the <literal>lazy</literal> attribute on your
|
||||
particular property mappings:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Document">
|
||||
<id name="id">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="name" not-null="true" length="50"/>
|
||||
<property name="summary" not-null="true" length="200" lazy="true"/>
|
||||
<property name="text" not-null="true" length="2000" lazy="true"/>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Lazy property loading requires buildtime bytecode instrumentation! If your persistent
|
||||
classes are not enhanced, Hibernate will silently ignore lazy property settings and
|
||||
fall back to immediate fetching.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For bytecode instrumentation, use the following Ant task:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<target name="instrument" depends="compile">
|
||||
<taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
|
||||
<classpath path="${jar.path}"/>
|
||||
<classpath path="${classes.dir}"/>
|
||||
<classpath refid="lib.class.path"/>
|
||||
</taskdef>
|
||||
|
||||
<instrument verbose="true">
|
||||
<fileset dir="${testclasses.dir}/org/hibernate/auction/model">
|
||||
<include name="*.class"/>
|
||||
</fileset>
|
||||
</instrument>
|
||||
</target>]]></programlisting>
|
||||
|
||||
<para>
|
||||
TODO: Document issues with lazy property loading
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="performance-cache" revision="1">
|
||||
<title>The Second Level Cache</title>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<chapter id="persistent-classes">
|
||||
<chapter id="persistent-classes" revision="1">
|
||||
<title>Persistent Classes</title>
|
||||
|
||||
<para>
|
||||
|
@ -10,7 +10,9 @@
|
|||
|
||||
<para>
|
||||
Hibernate works best if these classes follow some simple rules, also known
|
||||
as the Plain Old Java Object (POJO) programming model.
|
||||
as the Plain Old Java Object (POJO) programming model. However, Hibernate3
|
||||
also allows you to express a domain model as nested dynamic <literal>Map</literal>s,
|
||||
if required.
|
||||
</para>
|
||||
|
||||
<sect1 id="persistent-classes-pojo">
|
||||
|
@ -97,7 +99,7 @@ public class Cat {
|
|||
</para>
|
||||
|
||||
|
||||
<sect2 id="persistent-classes-pojo-accessors">
|
||||
<sect2 id="persistent-classes-pojo-accessors" revision="1">
|
||||
<title>Declare accessors and mutators for persistent fields</title>
|
||||
|
||||
<para>
|
||||
|
@ -106,7 +108,8 @@ public class Cat {
|
|||
it is far better to decouple this implementation detail from the persistence
|
||||
mechanism. Hibernate persists JavaBeans style properties, and recognizes method
|
||||
names of the form <literal>getFoo</literal>, <literal>isFoo</literal> and
|
||||
<literal>setFoo</literal>.
|
||||
<literal>setFoo</literal>. You may however switch to direct field access for
|
||||
particular properties, if needed.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -116,13 +119,15 @@ public class Cat {
|
|||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="persistent-classes-pojo-constructor">
|
||||
<title>Implement a default constructor</title>
|
||||
<sect2 id="persistent-classes-pojo-constructor" revision="1">
|
||||
<title>Implement a no-argument constructor</title>
|
||||
|
||||
<para>
|
||||
<literal>Cat</literal> has an implicit default (no-argument) constructor. All
|
||||
<literal>Cat</literal> has a no-argument constructor. All
|
||||
persistent classes must have a default constructor (which may be non-public) so
|
||||
Hibernate can instantiate them using <literal>Constructor.newInstance()</literal>.
|
||||
We recommend to give the constructor at least <emphasis>package</emphasis> visibility
|
||||
for runtime proxy generation in Hibernate.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
|
@ -135,7 +140,7 @@ public class Cat {
|
|||
anything, and its type might have been any primitive type, any primitive "wrapper"
|
||||
type, <literal>java.lang.String</literal> or <literal>java.util.Date</literal>. (If
|
||||
your legacy database table has composite keys, you can even use a user-defined class
|
||||
with properties of these types - see the section on composite identifiers below.)
|
||||
with properties of these types - see the section on composite identifiers later.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -277,234 +282,55 @@ public class DomesticCat extends Cat {
|
|||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="persistent-classes-lifecycle">
|
||||
<title>Lifecycle Callbacks</title>
|
||||
<sect1 id="persistent-classes-dynamic">
|
||||
<title>Dynamic models</title>
|
||||
|
||||
<para>
|
||||
Optionally, a persistent class might implement the interface
|
||||
<literal>Lifecycle</literal> which provides some callbacks that allow
|
||||
the persistent object to perform necessary initialization/cleanup after
|
||||
save or load and before deletion or update.
|
||||
Hibernate also supports dynamic domain models, using <literal>Map</literal>s of
|
||||
<literal>Map</literal>s. With this approach, you don't write persistent classes,
|
||||
a Hibernate mapping file for each "entity" is sufficient:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
<dynamic-class entity-name="TestMap">
|
||||
<id name="id" type="long" column="ID">
|
||||
<generator class="sequence"/>
|
||||
</id>
|
||||
<property name="name" column="NAME" type="string"/>
|
||||
<property name="address" column="ADDRESS" type="string"/>
|
||||
<many-to-one name="parent" column="PARENT_ID" class="TestMap"/>
|
||||
<bag name="children" inverse="true" lazy="false">
|
||||
<key column="PARENT_ID"/>
|
||||
<one-to-many class="TestMap"/>
|
||||
</bag>
|
||||
</dynamic-class>
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<!-- TODO: add xref to interceptor -->
|
||||
The Hibernate <literal>Interceptor</literal> offers a less intrusive
|
||||
alternative, however.
|
||||
At runtime, you only use <literal>Map</literal>s and use the Hibernate entity
|
||||
name to refer to a particular type.
|
||||
</para>
|
||||
|
||||
<programlistingco>
|
||||
<areaspec>
|
||||
<area id="lifecycle1" coords="2 70"/>
|
||||
<area id="lifecycle2" coords="3 70" />
|
||||
<area id="lifecycle3" coords="4 70"/>
|
||||
<area id="lifecycle4" coords="5 70" />
|
||||
</areaspec>
|
||||
<programlisting><![CDATA[public interface Lifecycle {
|
||||
public boolean onSave(Session s) throws CallbackException;
|
||||
public boolean onUpdate(Session s) throws CallbackException;
|
||||
public boolean onDelete(Session s) throws CallbackException;
|
||||
public void onLoad(Session s, Serializable id);
|
||||
}]]></programlisting>
|
||||
<calloutlist>
|
||||
<callout arearefs="lifecycle1">
|
||||
<para>
|
||||
<literal>onSave</literal> - called just before the object is saved or
|
||||
inserted
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="lifecycle2">
|
||||
<para>
|
||||
<literal>onUpdate</literal> - called just before an object is updated
|
||||
(when the object is passed to <literal>Session.update()</literal>)
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="lifecycle3">
|
||||
<para>
|
||||
<literal>onDelete</literal> - called just before an object is deleted
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="lifecycle4">
|
||||
<para>
|
||||
<literal>onLoad</literal> - called just after an object is loaded
|
||||
</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
</programlistingco>
|
||||
|
||||
<programlisting><![CDATA[Session s = openSession();
|
||||
Map parent = new HashMap();
|
||||
parent.put("type", "TestMap");
|
||||
parent.put("name", "foo");
|
||||
parent.put("address", "bar");
|
||||
|
||||
Map child = new HashMap();
|
||||
child.put("type", "TestMap");
|
||||
child.put("name", "fooTwo");
|
||||
child.put("address", "barTwo");
|
||||
child.put("parent", parent);
|
||||
|
||||
s.save(parent);
|
||||
s.save(child);
|
||||
]]></programlisting>
|
||||
|
||||
<!-- TODO: Document user-extension framework in the property and proxy package -->
|
||||
<para>
|
||||
<literal>onSave()</literal>, <literal>onDelete()</literal> and
|
||||
<literal>onUpdate()</literal> may be used to cascade saves and
|
||||
deletions of dependent objects. This is an alternative to declaring cascaded
|
||||
operations in the mapping file. <literal>onLoad()</literal> may
|
||||
be used to initialize transient properties of the object from its persistent
|
||||
state. It may not be used to load dependent objects since the
|
||||
<literal>Session</literal> interface may not be invoked from
|
||||
inside this method. A further intended usage of <literal>onLoad()</literal>,
|
||||
<literal>onSave()</literal> and <literal>onUpdate()</literal> is to store a
|
||||
reference to the current <literal>Session</literal> for later use.
|
||||
TODO: Document user-extension framework in the property and proxy package
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note that <literal>onUpdate()</literal> is not called every time the object's
|
||||
persistent state is updated. It is called only when a transient object is passed
|
||||
to <literal>Session.update()</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If <literal>onSave()</literal>, <literal>onUpdate()</literal> or
|
||||
<literal>onDelete()</literal> return <literal>true</literal>, the operation is
|
||||
silently vetoed. If a <literal>CallbackException</literal> is thrown, the operation
|
||||
is vetoed and the exception is passed back to the application.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note that <literal>onSave()</literal> is called after an identifier is assigned to
|
||||
the object, except when native key generation is used.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="persistent-classes-validatable">
|
||||
<title>Validatable callback</title>
|
||||
|
||||
<para>
|
||||
If the persistent class needs to check invariants before its state is
|
||||
persisted, it may implement the following interface:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public interface Validatable {
|
||||
public void validate() throws ValidationFailure;
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
The object should throw a <literal>ValidationFailure</literal> if an invariant
|
||||
was violated. An instance of <literal>Validatable</literal> should not change
|
||||
its state from inside <literal>validate()</literal>.
|
||||
</para>
|
||||
<para>
|
||||
Unlike the callback methods of the <literal>Lifecycle</literal> interface,
|
||||
<literal>validate()</literal> might be called at unpredictable times. The
|
||||
application should not rely upon calls to <literal>validate()</literal> for
|
||||
business functionality.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="persistent-classes-xdoclet">
|
||||
<title>Using XDOclet markup</title>
|
||||
|
||||
<para>
|
||||
In the next chapter we will show how Hibernate mappings may be expressed using
|
||||
a simple, readable XML format. Many Hibernate users prefer to embed mapping
|
||||
information directly in sourcecode using XDoclet <literal>@hibernate.tags</literal>.
|
||||
We will not cover this approach in this document, since strictly it is considered
|
||||
part of XDoclet. However, we include the following example of the <literal>Cat</literal>
|
||||
class with XDoclet mappings.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
import java.util.Set;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @hibernate.class
|
||||
* table="CATS"
|
||||
*/
|
||||
public class Cat {
|
||||
private Long id; // identifier
|
||||
private Date birthdate;
|
||||
private Cat mate;
|
||||
private Set kittens
|
||||
private Color color;
|
||||
private char sex;
|
||||
private float weight;
|
||||
|
||||
/**
|
||||
* @hibernate.id
|
||||
* generator-class="native"
|
||||
* column="CAT_ID"
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
private void setId(Long id) {
|
||||
this.id=id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hibernate.many-to-one
|
||||
* column="MATE_ID"
|
||||
*/
|
||||
public Cat getMate() {
|
||||
return mate;
|
||||
}
|
||||
void setMate(Cat mate) {
|
||||
this.mate = mate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hibernate.property
|
||||
* column="BIRTH_DATE"
|
||||
*/
|
||||
public Date getBirthdate() {
|
||||
return birthdate;
|
||||
}
|
||||
void setBirthdate(Date date) {
|
||||
birthdate = date;
|
||||
}
|
||||
/**
|
||||
* @hibernate.property
|
||||
* column="WEIGHT"
|
||||
*/
|
||||
public float getWeight() {
|
||||
return weight;
|
||||
}
|
||||
void setWeight(float weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hibernate.property
|
||||
* column="COLOR"
|
||||
* not-null="true"
|
||||
*/
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
void setColor(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
/**
|
||||
* @hibernate.set
|
||||
* lazy="true"
|
||||
* order-by="BIRTH_DATE"
|
||||
* @hibernate.collection-key
|
||||
* column="PARENT_ID"
|
||||
* @hibernate.collection-one-to-many
|
||||
*/
|
||||
public Set getKittens() {
|
||||
return kittens;
|
||||
}
|
||||
void setKittens(Set kittens) {
|
||||
this.kittens = kittens;
|
||||
}
|
||||
// addKitten not needed by Hibernate
|
||||
public void addKitten(Cat kitten) {
|
||||
kittens.add(kitten);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hibernate.property
|
||||
* column="SEX"
|
||||
* not-null="true"
|
||||
* update="false"
|
||||
*/
|
||||
public char getSex() {
|
||||
return sex;
|
||||
}
|
||||
void setSex(char sex) {
|
||||
this.sex=sex;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<chapter id="querysql">
|
||||
<title>Native SQL Queries</title>
|
||||
<chapter id="querysql" revision="1">
|
||||
<title>Native SQL</title>
|
||||
|
||||
<para>
|
||||
You may also express queries in the native SQL dialect of your database. This is useful if you
|
||||
|
@ -8,6 +8,11 @@
|
|||
Hibernate.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate3 also supports native SQL statements for all create, update, delete, and load
|
||||
operations.
|
||||
</para>
|
||||
|
||||
<sect1 id="querysql-creating">
|
||||
<title>Creating a SQL based <literal>Query</literal></title>
|
||||
|
||||
|
@ -101,4 +106,98 @@ List loggedCats = sess.createSQLQuery(sql, "cat", Cat.class)
|
|||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querysql-cud">
|
||||
<title>Custom SQL for CUD</title>
|
||||
|
||||
<para>
|
||||
Hibernate3 can use custom SQL statements for create, update, and delete operations.
|
||||
The class and collection persisters in Hibernate already contain a set of configuration
|
||||
time generated strings (insertsql, deletesql, updatesql etc.). The mapping tags
|
||||
<literal><sql-insert></literal>, <literal><sql-delete></literal>, and
|
||||
<literal><sql-update></literal> override these strings:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true"/>
|
||||
<sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
|
||||
<sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
|
||||
<sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
The SQL is directly execute in your database, so you are free to use any dialect
|
||||
you like.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Stored procedures are support if the <literal>callable</literal> attribute is set:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true"/>
|
||||
<sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
|
||||
<sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
|
||||
<sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
The stored procedures are in most cases (read: better do it than not) required to
|
||||
return the number of rows inserted/updated/deleted, as Hibernate has some runtime
|
||||
checks for the success of the statement. Hibernate always registers the first statement
|
||||
parameter as a numeric output parameter for the CUD operations:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
|
||||
RETURN NUMBER IS
|
||||
BEGIN
|
||||
|
||||
update PERSON
|
||||
set
|
||||
NAME = uname,
|
||||
where
|
||||
ID = uid;
|
||||
|
||||
return SQL%ROWCOUNT;
|
||||
|
||||
END updatePerson;]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querysql-load">
|
||||
<title>Custom SQL for loading</title>
|
||||
|
||||
<para>
|
||||
You may also declare your own SQL (or HQL) queries for entity loading:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="person">
|
||||
<return alias="p" class="Person" lock-mode="upgrade"/>
|
||||
SELECT NAME AS {p.name}, ID AS {p.id} FROM PERSON WHERE ID=? FOR UPDATE
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<para>
|
||||
This is just a named query declaration, as discussed earlier. You may reference this
|
||||
named query in a class mapping:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true"/>
|
||||
<loader query-ref="person"/>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
TODO: Document synchronized mapping element in named queries
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
|
@ -868,7 +868,7 @@ public class Person implements Serializable, IAuditable {
|
|||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="toolsetguide-s3">
|
||||
<sect1 id="toolsetguide-s3" revision="1">
|
||||
<title>Mapping File Generation</title>
|
||||
|
||||
<para>
|
||||
|
@ -955,8 +955,7 @@ public class Person implements Serializable, IAuditable {
|
|||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
For <literal>hibernate.type.Type</literal> custom types and <literal>PersistentEnum</literal>
|
||||
a simple column is used as well.
|
||||
For <literal>hibernate.type.Type</literal> custom types a simple column is used as well.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
|
|
Loading…
Reference in New Issue