Author: epbernard
Date: 2007-02-06 00:51:21 -0500 (Tue, 06 Feb 2007)
New Revision: 11155
Added:
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/build.xml
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/checkconstraints.xml
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/defineconstraints.xml
Removed:
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/entity.xml
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/lucene.xml
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/setup.xml
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/validator.xml
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/xml-overriding.xml
Modified:
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/master.xml
Log:
Standalone validator documentation
Added: branches/HAN_SPLIT/HibernateExt/validator/doc/reference/build.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/validator/doc/reference/build.xml
(rev 0)
+++ branches/HAN_SPLIT/HibernateExt/validator/doc/reference/build.xml 2007-02-06 05:51:21
UTC (rev 11155)
@@ -0,0 +1,17 @@
+<project name="Documentation" default="all.doc"
basedir=".">
+
+ <!-- Use the core Hibernate3 doc build system -->
+ <import file="../../../common/common-build.xml"/>
+ <import file="${hibernate-cvs.doc.reference}/build.xml"/>
+
+
+ <target name="all.doc" depends="clean">
+
+ <!-- TRANSLATOR: Duplicate this call for your language -->
+ <antcall target="lang.all">
+ <param name="docname"
value="hibernate_validator"/>
+ <param name="lang" value="en"/>
+ </antcall>
+ </target>
+
+</project>
Modified: branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/master.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/master.xml 2007-02-05
23:37:37 UTC (rev 11154)
+++ branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/master.xml 2007-02-06
05:51:21 UTC (rev 11155)
@@ -1,79 +1,69 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
-"../../../../../Hibernate3/doc/reference/support/docbook-dtd/docbookx.dtd" [
-<!ENTITY setup SYSTEM "modules/setup.xml">
-<!ENTITY entity SYSTEM "modules/entity.xml">
-<!ENTITY xml-overriding SYSTEM "modules/xml-overriding.xml">
-<!ENTITY validator SYSTEM "modules/validator.xml">
-<!ENTITY lucene SYSTEM "modules/lucene.xml">
-]>
+ "../../../../../Hibernate3/doc/reference/support/docbook-dtd/docbookx.dtd" [
+ <!ENTITY defineconstraints SYSTEM "modules/defineconstraints.xml">
+ <!ENTITY checkconstraints SYSTEM "modules/checkconstraints.xml">
+ ]>
<book lang="en">
- <bookinfo>
- <title>Hibernate Annotations</title>
+ <bookinfo>
+ <title>Hibernate Validator</title>
- <subtitle>Reference Guide</subtitle>
+ <subtitle>Reference Guide</subtitle>
- <releaseinfo>3.2.1.GA</releaseinfo>
+ <releaseinfo>3.2.2.GA</releaseinfo>
- <mediaobject>
- <imageobject>
- <imagedata fileref="images/hibernate_logo_a.png"
format="png" />
- </imageobject>
- </mediaobject>
- </bookinfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/hibernate_logo_a.png"
format="png"/>
+ </imageobject>
+ </mediaobject>
+ </bookinfo>
- <toc></toc>
+ <toc></toc>
- <preface id="preface" revision="1">
- <title>Preface</title>
+ <preface id="preface" revision="1">
+ <title>Preface</title>
+ <para>Annotations are a very convenient and elegant way to specify invariant
+ constraints for a domain model. You can, for example, express that a
+ property should never be null, that the account balance should be strictly
+ positive, etc. These domain model constraints are declared in the bean
+ itself by annotating its properties. A validator can then read them and
+ check for constraint violations. The validation mechanism can be executed in
+ different layers in your application without having to duplicate any of
+ these rules (presentation layer, data access layer). Following the DRY principle,
+ Hibernate Validator has been designed for that purpose.
+ </para>
- <para>Hibernate, like all other object/relational mapping tools, requires
- metadata that governs the transformation of data from one representation
- to the other (and vice versa). In Hibernate 2.x, mapping metadata is most
- of the time declared in XML text files. Another option is XDoclet,
- utilizing Javadoc source code annotations and a preprocessor at compile
- time. The same kind of annotation support is now available in the standard
- JDK, although more powerful and better supported by tools. IntelliJ IDEA,
- and Eclipse for example, support auto-completion and syntax highlighting
- of JDK 5.0 annotations. Annotations are compiled into the bytecode and
- read at runtime (in Hibernate's case on startup) using reflection, so no
- external XML files are needed.</para>
+ <para>Hibernate Validator works at two levels. First, it is able to check
+ in-memory instances of a class for constraint violations. Second, it can
+ apply the constraints to the Hibernate metamodel and incorporate them into
+ the generated database schema.
+ </para>
- <para>The EJB3 specification recognizes the interest and the success of
- the transparent object/relational mapping paradigm. The EJB3 specification
- standardizes the basic APIs and the metadata needed for any
- object/relational persistence mechanism. <emphasis>Hibernate
- EntityManager</emphasis> implements the programming interfaces and
- lifecycle rules as defined by the EJB3 persistence specification. Together
- with <emphasis>Hibernate Annotations</emphasis>, this wrapper implements
a
- complete (and standalone) EJB3 persistence solution on top of the mature
- Hibernate core. You may use a combination of all three together,
- annotations without EJB3 programming interfaces and lifecycle, or even
- pure native Hibernate, depending on the business and technical needs of
- your project. You can at all times fall back to Hibernate native APIs, or
- if required, even to native JDBC and SQL.</para>
+ <para>Each constraint annotation is associated to a validator implementation
+ responsible for checking the constraint on the entity instance. A validator
+ can also (optionally) apply the constraint to the Hibernate metamodel,
+ allowing Hibernate to generate DDL that expresses the constraint. With the
+ appropriate event listener, you can execute the checking operation on
+ inserts and updates done by Hibernate. Hibernate Validator is not limited to
+ use with Hibernate. You can easily use it anywhere in your
+ application.
+ </para>
- <para>This release is based on the final release of the EJB 3.0 / JPA
- specification (aka JSP-220) and support all the specification features
- (including the optional ones). Most of the Hibernate features and
- extensions are also available through Hibernate specific annotations
- compared to the specification are also available. While the Hibernate
- feature coverage is now very high, some are still missing. The eventual
- goal is to cover all of them. See the JIRA road map section for more
- informations.</para>
+ <para>When checking instances at runtime, Hibernate Validator returns
+ information about constraint violations in an array of
+ <classname>InvalidValue</classname>
+ s. Among other information, the
+ <classname>InvalidValue</classname>
+ contains an error description message
+ that can embed the parameter values bundle with the annotation (eg. length
+ limit), and message strings that may be externalized to a
+ <classname>ResourceBundle</classname>
+ .
+ </para>
+ </preface>
- <para>If you are moving from previous Hibernate Annotations versions,
- please have a look at <
uri>http://www.hibernate.org/371.html</uri> for a
- migration guide.</para>
- </preface>
+ &defineconstraints;
+ &checkconstraints;
- &setup;
-
- &entity;
-
- &xml-overriding;
-
- &validator;
-
- &lucene;
</book>
\ No newline at end of file
Copied:
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/checkconstraints.xml
(from rev 11154,
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/validator.xml)
===================================================================
---
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/checkconstraints.xml
(rev 0)
+++
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/checkconstraints.xml 2007-02-06
05:51:21 UTC (rev 11155)
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="validator-checkconstraints">
+ <title>Using the Validator framework</title>
+
+ <para>Hibernate Validator is intended to be used to implement multi-layered
+ data validation, where constraints are expressed in a single place (the
+ annotated domain model) and checked in various different layers of the
+ application.</para>
+
+ <para>This chapter will cover Hibernate Validator usage for different
+ layers</para>
+
+ <section id="validator-checkconstraints-db" revision="1">
+ <title>Database schema-level validation</title>
+
+ <para>Out of the box, Hibernate Annotations will translate the constraints
+ you have defined for your entities into mapping metadata. For example, if
+ a property of your entity is annotated <literal>@NotNull</literal>, its
+ columns will be declared as <literal>not null</literal> in the DDL
schema
+ generated by Hibernate.</para>
+
+ <para>Using hbm2ddl, domain model constraints will be expressed into the
+ database schema.</para>
+ </section>
+
+ <section id="validator-checkconstraints-orm">
+ <title>ORM integration</title>
+
+ <para>Hibernate Validator integrates with both Hibernate and all pure Java
+ Persistence providers</para>
+
+ <section id="validator-checkconstraints-orm-hibernateevent"
revision="1">
+ <title>Hibernate event-based validation</title>
+
+ <para>Hibernate Validator has two built-in Hibernate event listeners.
+ Whenever a <literal>PreInsertEvent</literal> or
+ <literal>PreUpdateEvent</literal> occurs, the listeners will verify
all
+ constraints of the entity instance and throw an exception if any
+ constraint is violated. Basically, objects will be checked before any
+ inserts and before any updates made by Hibernate. This includes changes
+ applied by cascade! This is the most convenient and the easiest way to
+ activate the validation process. On constraint violation, the event will
+ raise a runtime <classname>InvalidStateException</classname> which
+ contains an array of <literal>InvalidValue</literal>s describing each
+ failure.</para>
+
+ <programlisting><hibernate-configuration>
+ ...
+ <event type="pre-update">
+ <listener
+ class="org.hibernate.validator.event.ValidateEventListener"/>
+ </event>
+ <event type="pre-insert">
+ <listener
+ class="org.hibernate.validator.event.ValidateEventListener"/>
+ </event>
+</hibernate-configuration></programlisting>
+
+ <para><note>
+ <para>When using Hibernate Entity Manager, the Validation framework
+ is activated out of the box. If the beans are not annotated with
+ validation annotations, there is no performance cost.</para>
+ </note></para>
+ </section>
+
+ <section id="validator-checkconstraints-orm-jpaevent">
+ <title>Java Persistence event-based validation</title>
+
+ <para>Hibernate Validator is not tied to Hibernate for event based
+ validation: a Java Persistence entity listener is available. Whenever an
+ listened entity is persisted or updated, Hibernate Validator will verify
+ all constraints of the entity instance and throw an exception if any
+ constraint is violated. Basically, objects will be checked before any
+ inserts and before any updates made by the Java Persistence provider.
+ This includes changes applied by cascade! On constraint violation, the
+ event will raise a runtime
<classname>InvalidStateException</classname>
+ which contains an array of <literal>InvalidValue</literal>s describing
+ each failure.</para>
+
+ <para>Here is how to make a class validatable:</para>
+
+ <programlisting>@Entity
+@EntityListeners( JPAValidateListener.class )
+public class Submarine {
+ ...
+}
+}</programlisting>
+
+ <para><note>
+ <para>Compared to the Hibernate event, the Java Persistence listener
+ has two drawbacks. You need to define the entity listener on every
+ validatable entity. The DDL generated by your provider will not
+ reflect the constraints.</para>
+ </note></para>
+ </section>
+ </section>
+
+ <section>
+ <title>Application-level validation</title>
+
+ <para>Hibernate Validator can be applied anywhere in your application
+ code.</para>
+
+ <programlisting>ClassValidator personValidator = new ClassValidator(
Person.class );
+ClassValidator addressValidator = new ClassValidator( Address.class,
ResourceBundle.getBundle("messages", Locale.ENGLISH) );
+
+InvalidValue[] validationMessages =
addressValidator.getInvalidValues(address);</programlisting>
+
+ <para>The first two lines prepare the Hibernate Validator for class
+ checking. The first one relies upon the error messages embedded in
+ Hibernate Validator (see <xref
linkend="validator-defineconstraints-error" />),
+ the second one uses a resource bundle for these messages. It is considered
+ a good practice to execute these lines once and cache the validator
+ instances.</para>
+
+ <para>The third line actually validates the
<literal>Address</literal>
+ instance and returns an array of <literal>InvalidValue</literal>s. Your
+ application logic will then be able to react to the failure.</para>
+
+ <para>You can also check a particular property instead of the whole bean.
+ This might be useful for property per property user interaction</para>
+
+ <programlisting>ClassValidator addressValidator = new ClassValidator(
Address.class, ResourceBundle.getBundle("messages", Locale.ENGLISH) );
+
+//only get city property invalid values
+InvalidValue[] validationMessages = addressValidator.getInvalidValues(address,
"city");
+
+//only get potential city property invalid values
+InvalidValue[] validationMessages =
addressValidator.getPotentialInvalidValues("city",
"Paris")</programlisting>
+ </section>
+
+ <section>
+ <title>Presentation layer validation</title>
+
+ <para>When working with JSF and <productname>JBoss
Seam</productname>, one
+ can triggers the validation process at the presentation layer using Seam's
+ JSF tags <literal><s:validate></literal> and
+ <literal><s:validateAll/></literal>, letting the
constraints be
+ expressed on the model, and the violations presented in the view</para>
+
+ <programlisting><h:form>
+ <div>
+ <h:messages/>
+ </div>
+ <emphasis role="bold"><s:validateAll></emphasis>
+ <div>
+ Country:
+ <h:inputText value="#{location.country}"
required="true"/>
+ </div>
+ <div>
+ Zip code:
+ <h:inputText value="#{location.zip}"
required="true"/>
+ </div>
+ <div>
+ <h:commandButton/>
+ </div>
+ <emphasis
role="bold"></s:validateAll></emphasis>
+</h:form></programlisting>
+
+ <para>Going even further, and adding
<productname>Ajax4JSF</productname>
+ to the loop will bring client side validation with just a couple of
+ additional JSF tags, again without validation definition
+ duplication.</para>
+
+ <para>Check the <ulink
url="http://www.jboss.com/products/seam">JBoss Seam</ulink>
+ documentation for more information.</para>
+ </section>
+
+ <section>
+ <title>Validation informations</title>
+
+ <para>As a validation information carrier, hibernate provide an array of
+ <classname>InvalidValue</classname>. Each
<literal>InvalidValue</literal>
+ has a buch of methods describing the individual issues.</para>
+
+ <para><methodname>getBeanClass()</methodname> retrieves the failing
bean
+ type</para>
+
+ <para><methodname>getBean()</methodname>retrieves the failing
instance (if
+ any ie not when using
+ <methodname>getPotentianInvalidValues()</methodname>)</para>
+
+ <para><methodname>getValue()</methodname> retrieves the failing
+ value</para>
+
+ <para><methodname>getMessage()</methodname> retrieves the proper
+ internationalized error message</para>
+
+ <para><methodname>getRootBean()</methodname> retrieves the root
bean
+ instance generating the issue (useful in conjunction with
+ <literal>@Valid</literal>), is null if getPotentianInvalidValues() is
+ used.</para>
+
+ <para><literal>getPropertyPath()</literal> retrieves the dotted
path of
+ the failing property starting from the root bean</para>
+ </section>
+</chapter>
\ No newline at end of file
Copied:
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/defineconstraints.xml
(from rev 11154,
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/validator.xml)
===================================================================
---
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/defineconstraints.xml
(rev 0)
+++
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/defineconstraints.xml 2007-02-06
05:51:21 UTC (rev 11155)
@@ -0,0 +1,409 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="validator-defineconstraints">
+ <title>Defining constraints</title>
+
+ <section id="validator-defineconstraints-definition"
revision="1">
+ <title>What is a constraint?</title>
+
+ <para>A constraint is a rule that a given element (field, property or
+ bean) has to comply to. The rule semantic is expressed by an annotation. A
+ constraint usually has some attributes used to parameterize the
+ constraints limits. The constraint applies to the annotated
+ element.</para>
+ </section>
+
+ <section id="validator-defineconstraints-builtin"
revision="1">
+ <title>Built in constraints</title>
+
+ <para>Hibernate Validator comes with some built-in constraints, which
+ covers most basic data checks. As we'll see later, you're not limited to
+ them, you can literally in a minute write your own constraints.</para>
+
+ <table>
+ <title>Built-in constraints</title>
+
+ <tgroup cols="4">
+ <colspec align="center" />
+
+ <thead>
+ <row>
+ <entry>Annotation</entry>
+
+ <entry>Apply on</entry>
+
+ <entry>Runtime checking</entry>
+
+ <entry>Hibernate Metadata impact</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>@Length(min=, max=)</entry>
+
+ <entry>property (String)</entry>
+
+ <entry>check if the string length match the range</entry>
+
+ <entry>Column length will be set to max</entry>
+ </row>
+
+ <row>
+ <entry>@Max(value=)</entry>
+
+ <entry>property (numeric or string representation of a
+ numeric)</entry>
+
+ <entry>check if the value is less than or equals to max</entry>
+
+ <entry>Add a check constraint on the column</entry>
+ </row>
+
+ <row>
+ <entry>@Min(value=)</entry>
+
+ <entry>property (numeric or string representation of a
+ numeric)</entry>
+
+ <entry>check if the value is more than or equals to min</entry>
+
+ <entry>Add a check constraint on the column</entry>
+ </row>
+
+ <row>
+ <entry>@NotNull</entry>
+
+ <entry>property</entry>
+
+ <entry>check if the value is not null</entry>
+
+ <entry>Column(s) are not null</entry>
+ </row>
+
+ <row>
+ <entry>@NotEmpty</entry>
+
+ <entry>property</entry>
+
+ <entry>check if the string is not null nor empty. Check if the
+ connection is not null nor empty</entry>
+
+ <entry>Column(s) are not null (for String)</entry>
+ </row>
+
+ <row>
+ <entry>@Past</entry>
+
+ <entry>property (date or calendar)</entry>
+
+ <entry>check if the date is in the past</entry>
+
+ <entry>Add a check constraint on the column</entry>
+ </row>
+
+ <row>
+ <entry>@Future</entry>
+
+ <entry>property (date or calendar)</entry>
+
+ <entry>check if the date is in the future</entry>
+
+ <entry>none</entry>
+ </row>
+
+ <row>
+ <entry>@Pattern(regex="regexp", flag=)</entry>
+
+ <entry>property (string)</entry>
+
+ <entry>check if the property match the regular expression given a
+ match flag (see <classname>java.util.regex.Pattern </classname>
+ )</entry>
+
+ <entry>none</entry>
+ </row>
+
+ <row>
+ <entry>@Range(min=, max=)</entry>
+
+ <entry>property (numeric or string representation of a
+ numeric)</entry>
+
+ <entry>check if the value is between min and max
+ (included)</entry>
+
+ <entry>Add a check constraint on the column</entry>
+ </row>
+
+ <row>
+ <entry>@Size(min=, max=)</entry>
+
+ <entry>property (array, collection, map)</entry>
+
+ <entry>check if the element size is between min and max
+ (included)</entry>
+
+ <entry>none</entry>
+ </row>
+
+ <row>
+ <entry>@AssertFalse</entry>
+
+ <entry>property</entry>
+
+ <entry>check that the method evaluates to false (useful for
+ constraints expressed in code rather than annotations)</entry>
+
+ <entry>none</entry>
+ </row>
+
+ <row>
+ <entry>@AssertTrue</entry>
+
+ <entry>property</entry>
+
+ <entry>check that the method evaluates to true (useful for
+ constraints expressed in code rather than annotations)</entry>
+
+ <entry>none</entry>
+ </row>
+
+ <row>
+ <entry>@Valid</entry>
+
+ <entry>property (object)</entry>
+
+ <entry>perform validation recursively on the associated object. If
+ the object is a Collection or an array, the elements are validated
+ recursively. If the object is a Map, the value elements are
+ validated recursively.</entry>
+
+ <entry>none</entry>
+ </row>
+
+ <row>
+ <entry>@Email</entry>
+
+ <entry>property (String)</entry>
+
+ <entry>check whether the string is conform to the email address
+ specification</entry>
+
+ <entry>none</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+
+ <section id="validator-defineconstraints-error" xreflabel="Error
messages">
+ <title>Error messages</title>
+
+ <para>Hibernate Validator comes with a default set of error messages
+ translated in about ten languages (if yours is not part of it, please sent
+ us a patch). You can override those messages by creating a
+ <filename>ValidatorMessages.properties</filename> or (
+ <filename>ValidatorMessages_loc.properties</filename> ) and override the
+ needed keys. You can even add your own additional set of messages while
+ writing your validator annotations. If Hibernate Validator cannot resolve
+ a key from your resourceBundle nor from ValidatorMessage, it falls back to
+ the default built-in values.</para>
+
+ <para>Alternatively you can provide a
+ <classname>ResourceBundle</classname> while checking programmatically
the
+ validation rules on a bean or if you want a completly different
+ interpolation mechanism, you can provide an implementation of
+ <literal>org.hibernate.validator.MessageInterpolator</literal> (check
the
+ JavaDoc for more informations).</para>
+ </section>
+
+ <section>
+ <title>Writing your own constraints</title>
+
+ <para>Extending the set of built-in constraints is extremely easy. Any
+ constraint consists of two pieces: the constraint
+ <emphasis>descriptor</emphasis> (the annotation) and the constraint
+ <emphasis>validator</emphasis> (the implementation class). Here is a
+ simple user-defined descriptor:</para>
+
+ <programlisting>(a)ValidatorClass(CapitalizedValidator.class)
+@Target(METHOD)
+@Retention(RUNTIME)
+@Documented
+public @interface Capitalized {
+ CapitalizeType type() default Capitalize.FIRST;
+ String message() default "has incorrect capitalization"
+} </programlisting>
+
+ <para><literal>type</literal> is a parameter describing how the
property
+ should to be capitalized. This is a user parameter fully dependant on the
+ annotation business.</para>
+
+ <para><literal>message</literal> is the default string used to
describe
+ the constraint violation and is mandatory. You can hard code the string or
+ you can externalize part/all of it through the Java ResourceBundle
+ mechanism. Parameters values are going to be injected inside the message
+ when the <literal>{parameter}</literal> string is found (in our example
+ <literal>Capitalization is not {type}</literal> would generate
+ <literal>Capitalization is not FIRST</literal> ), externalizing the
whole
+ string in <filename>ValidatorMessages.properties</filename> is
considered
+ good practice. See <xref linkend="validator-defineconstraints-error"
/> .</para>
+
+ <programlisting>(a)ValidatorClass(CapitalizedValidator.class)
+@Target(METHOD)
+@Retention(RUNTIME)
+@Documented
+public @interface Capitalized {
+ CapitalizeType type() default Capitalize.FIRST;
+ String message() default "{validator.capitalized}";
+}
+
+
+#in ValidatorMessages.properties
+validator.capitalized = <literal>Capitalization is not {type}</literal>
+ </programlisting>
+
+ <para>As you can see the {} notation is recursive.</para>
+
+ <para>To link a descriptor to its validator implementation, we use the
+ <literal>@ValidatorClass</literal> meta-annotation. The validator class
+ parameter must name a class which implements
+ <literal>Validator<ConstraintAnnotation></literal>
.</para>
+
+ <para>We now have to implement the validator (ie. the rule checking
+ implementation). A validation implementation can check the value of the a
+ property (by implementing <literal>PropertyConstraint</literal> ) and/or
+ can modify the hibernate mapping metadata to express the constraint at the
+ database level (by implementing
+ <literal>PersistentClassConstraint</literal> )</para>
+
+ <programlisting>public class CapitalizedValidator
+ implements Validator<Capitalized>, PropertyConstraint {
+ private CapitalizeType type;
+
+ //part of the Validator<Annotation> contract,
+ //allows to get and use the annotation values
+ public void initialize(Capitalized parameters) {
+ type = parameters.type();
+ }
+
+ //part of the property constraint contract
+ public boolean isValid(Object value) {
+ if (value==null) return true;
+ if ( !(value instanceof String) ) return false;
+ String string = (String) value;
+ if (type == CapitalizeType.ALL) {
+ return string.equals( string.toUpperCase() );
+ }
+ else {
+ String first = string.substring(0,1);
+ return first.equals( first.toUpperCase();
+ }
+ }
+} </programlisting>
+
+ <para>The <literal>isValid()</literal> method should return false
if the
+ constraint has been violated. For more examples, refer to the built-in
+ validator implementations.</para>
+
+ <para>We only have seen property level validation, but you can write a
+ Bean level validation annotation. Instead of receiving the return instance
+ of a property, the bean itself will be passed to the validator. To
+ activate the validation checking, just annotated the bean itself instead.
+ A small sample can be found in the unit test suite.</para>
+ </section>
+
+ <section>
+ <title>Annotating your domain model</title>
+
+ <para>Since you are already familiar with annotations now, the syntax
+ should be very familiar</para>
+
+ <programlisting>public class Address {
+ private String line1;
+ private String line2;
+ private String zip;
+ private String state;
+ private String country;
+ private long id;
+
+ // a not null string of 20 characters maximum
+ @Length(max=20)
+ @NotNull
+ public String getCountry() {
+ return country;
+ }
+
+ // a non null string
+ @NotNull
+ public String getLine1() {
+ return line1;
+ }
+
+ //no constraint
+ public String getLine2() {
+ return line2;
+ }
+
+ // a not null string of 3 characters maximum
+ @Length(max=3) @NotNull
+ public String getState() {
+ return state;
+ }
+
+ // a not null numeric string of 5 characters maximum
+ // if the string is longer, the message will
+ //be searched in the resource bundle at key 'long'
+ @Length(max=5, message="{long}")
+ @Pattern(regex="[0-9]+")
+ @NotNull
+ public String getZip() {
+ return zip;
+ }
+
+ // should always be true
+ @AssertTrue
+ public boolean isValid() {
+ return true;
+ }
+
+ // a numeric between 1 and 2000
+ @Id @Min(1)
+ @Range(max=2000)
+ public long getId() {
+ return id;
+ }
+} </programlisting>
+
+ <para>While the example only shows public property validation, you can
+ also annotate fields of any kind of visibility</para>
+
+ <programlisting>@MyBeanConstraint(max=45
+public class Dog {
+ @AssertTrue private boolean isMale;
+ @NotNull protected String getName() { ... };
+ ...
+} </programlisting>
+
+ <para>You can also annotate interfaces. Hibernate Validator will check all
+ superclasses and interfaces extended or implemented by a given bean to
+ read the appropriate validator annotations.</para>
+
+ <programlisting>public interface Named {
+ @NotNull String getName();
+ ...
+}
+
+public class Dog implements Named {
+
+ @AssertTrue private boolean isMale;
+
+ public String getName() { ... };
+
+}
+ </programlisting>
+
+ <para>The name property will be checked for nullity when the Dog bean is
+ validated.</para>
+ </section>
+</chapter>
\ No newline at end of file
Property changes on:
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/defineconstraints.xml
___________________________________________________________________
Name: svn:keywords
+ Author Date Id Revision
Name: svn:eol-style
+ native
Deleted: branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/entity.xml
===================================================================
---
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/entity.xml 2007-02-05
23:37:37 UTC (rev 11154)
+++
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/entity.xml 2007-02-06
05:51:21 UTC (rev 11155)
@@ -1,3432 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<chapter id="entity">
- <title>Entity Beans</title>
-
- <sect1 id="entity-overview" revision="1">
- <title>Intro</title>
-
- <para>This section covers EJB 3.0 (aka JPA) entity annotations and
- Hibernate-specific extensions.</para>
- </sect1>
-
- <sect1 id="entity-mapping" revision="2">
- <title>Mapping with EJB3/JPA Annotations</title>
-
- <para>EJB3 entities are plain POJOs. Actually they represent the exact
- same concept as the Hibernate persistent entities. Their mappings are
- defined through JDK 5.0 annotations (an XML descriptor syntax for
- overriding is defined in the EJB3 specification). Annotations can be split
- in two categories, the logical mapping annotations (allowing you to
- describe the object model, the class associations, etc.) and the physical
- mapping annotations (describing the physical schema, tables, columns,
- indexes, etc). We will mix annotations from both categories in the
- following code examples.</para>
-
- <para>EJB3 annotations are in the
<literal>javax.persistence.*</literal>
- package. Most JDK 5 compliant IDE (like Eclipse, IntelliJ IDEA and
- Netbeans) can autocomplete annotation interfaces and attributes for you
- (even without a specific "EJB3" module, since EJB3 annotations are plain
- JDK 5 annotations).</para>
-
- <para>For more and runnable concrete examples read the JBoss EJB 3.0
- tutorial or review the Hibernate Annotations test suite. Most of the unit
- tests have been designed to represent a concrete example and be a
- inspiration source.</para>
-
- <sect2>
- <title>Declaring an entity bean</title>
-
- <para>Every bound persistent POJO class is an entity bean and is
- declared using the <literal>@Entity</literal> annotation (at the class
- level):</para>
-
- <programlisting>
-@Entity
-public class Flight implements Serializable {
- Long id;
-
- @Id
- public Long getId() { return id; }
-
- public void setId(Long id) { this.id = id; }
-}
- </programlisting>
-
- <para><literal>@Entity</literal> declares the class as an entity
bean
- (i.e. a persistent POJO class), <literal>@Id</literal> declares the
- identifier property of this entity bean. The other mapping declarations
- are implicit. This configuration by exception concept is central to the
- new EJB3 specification and a major improvement. The class Flight is
- mapped to the Flight table, using the column id as its primary key
- column.</para>
-
- <para>Depending on whether you annotate fields or methods, the access
- type used by Hibernate will be <literal>field</literal> or
- <literal>property</literal>. The EJB3 spec requires that you declare
- annotations on the element type that will be accessed, i.e. the getter
- method if you use <literal>property</literal> access, the field if you
- use <literal>field</literal> access. Mixing EJB3 annotations in both
- fields and methods should be avoided. Hibernate will guess the access
- type from the position of <literal>@Id</literal> or
- <literal>(a)EmbeddedId</literal>.</para>
-
- <sect3>
- <title>Defining the table</title>
-
- <para><literal>@Table</literal> is set at the class level; it
allows
- you to define the table, catalog, and schema names for your entity
- bean mapping. If no <literal>@Table</literal> is defined the default
- values are used: the unqualified class name of the entity.</para>
-
- <programlisting>
-@Entity
-@Table(name="tbl_sky")
-public class Sky implements Serializable {
-...
- </programlisting>
-
- <para>The <literal>@Table</literal> element also contains a
- <literal>schema</literal> and a
<literal>catalog</literal> attributes,
- if they need to be defined. You can also define unique constraints to
- the table using the <literal>@UniqueConstraint</literal> annotation
in
- conjunction with <literal>@Table</literal> (for a unique constraint
- bound to a single column, refer to
<literal>(a)Column</literal>).</para>
-
- <programlisting>@Table(name="tbl_sky",
- <emphasis role="bold">uniqueConstraints =
{@UniqueConstraint(columnNames={"month", "day"})}</emphasis>
-)</programlisting>
-
- <para>A unique constraint is applied to the tuple month, day. Note
- that the <literal>columnNames</literal> array refers to the logical
- column names.</para>
-
- <remark>The logical column name is defined by the Hibernate
- NamingStrategy implementation. The default EJB3 naming strategy use
- the physical column name as the logical column name. Note that this
- may be different than the property name (if the column name is
- explicit). Unless you override the NamingStrategy, you shouldn't worry
- about that.</remark>
- </sect3>
-
- <sect3>
- <title>Versioning for optimistic locking</title>
-
- <para>You can add optimistic locking capability to an entity bean
- using the <literal>@Version</literal> annotation:</para>
-
- <programlisting>
-@Entity
-public class Flight implements Serializable {
-...
- @Version
- @Column(name="OPTLOCK")
- public Integer getVersion() { ... }
-} </programlisting>
-
- <para>The version property will be mapped to the
- <literal>OPTLOCK</literal> column, and the entity manager will use
it
- to detect conflicting updates (preventing lost updates you might
- otherwise see with the last-commit-wins strategy).</para>
-
- <para>The version column may be a numeric (the recommended solution)
- or a timestamp as per the EJB3 spec. Hibernate support any kind of
- type provided that you define and implement the appropriate
- <classname>UserVersionType</classname>.</para>
- </sect3>
- </sect2>
-
- <sect2>
- <title>Mapping simple properties</title>
-
- <sect3>
- <title>Declaring basic property mappings</title>
-
- <para>Every non static non transient property (field or method) of an
- entity bean is considered persistent, unless you annotate it as
- <literal>@Transient</literal>. Not having an annotation for your
- property is equivalent to the appropriate <literal>@Basic</literal>
- annotation. The <literal>@Basic</literal> annotation allows you to
- declare the fetching strategy for a property:</para>
-
- <programlisting>public transient int counter; //transient property
-
-private String firstname; //persistent property
-
-@Transient
-String getLengthInMeter() { ... } //transient property
-
-String getName() {... } // persistent property
-
-@Basic
-int getLength() { ... } // persistent property
-
-@Basic(fetch = FetchType.LAZY)
-String getDetailedComment() { ... } // persistent property
-
-(a)Temporal(TemporalType.TIME)
-java.util.Date getDepartureTime() { ... } // persistent property
-
-@Enumerated(STRING)
-Starred getNote() { ... } //enum persisted as String in database</programlisting>
-
- <para><literal>counter</literal>, a transient field, and
- <literal>lengthInMeter</literal>, a method annotated as
- <literal>@Transient</literal>, and will be ignored by the entity
- manager. <literal>name</literal>,
<literal>length</literal>, and
- <literal>firstname</literal> properties are mapped persistent and
- eagerly fetched (the default for simple properties). The
- <literal>detailedComment</literal> property value will be lazily
- fetched from the database once a lazy property of the entity is
- accessed for the first time. Usually you don't need to lazy simple
- properties (not to be confused with lazy association fetching).</para>
-
- <note>
- <para>To enable property level lazy fetching, your classes have to
- be instrumented: bytecode is added to the original one to enable
- such feature, please refer to the Hibernate reference documentation.
- If your classes are not instrumented, property level lazy loading is
- silently ignored.</para>
- </note>
-
- <para>The recommended alternative is to use the projection capability
- of EJB-QL or Criteria queries.</para>
-
- <para>EJB3 support property mapping of all basic types supported by
- Hibernate (all basic Java types , their respective wrappers and
- serializable classes). Hibernate Annotations support out of the box
- Enum type mapping either into a ordinal column (saving the enum
- ordinal) or a string based column (saving the enum string
- representation): the persistence representation, defaulted to ordinal,
- can be overriden through the <literal>@Enumerated</literal>
annotation
- as shown in the <literal>note</literal> property
example.</para>
-
- <para>In core Java APIs, the temporal precision is not defined. When
- dealing with temporal data you might want to describe the expected
- precision in database. Temporal data can have
<literal>DATE</literal>,
- <literal>TIME</literal>, or <literal>TIMESTAMP</literal>
precision (ie
- the actual date, only the time, or both). Use the
- <literal>@Temporal</literal> annotation to fine tune
that.</para>
-
- <para><literal>@Lob</literal> indicates that the property
should be
- persisted in a Blob or a Clob depending on the property type:
- <classname>java.sql.Clob</classname>,
- <classname>Character[]</classname>,
<classname>char[]</classname> and
- java.lang.<classname>String</classname> will be persisted in a Clob.
- <classname>java.sql.Blob</classname>,
<classname>Byte[]</classname>,
- <classname>byte[] </classname>and serializable type will be
persisted
- in a Blob.</para>
-
- <programlisting>
-@Lob
-public String getFullText() {
- return fullText;
-}
-
-@Lob
-public byte[] getFullCode() {
- return fullCode;
-}
- </programlisting>
-
- <para>If the property type implements
- <classname>java.io.Serializable</classname> and is not a basic type,
- and if the property is not annotated with <literal>@Lob</literal>,
- then the Hibernate <literal>serializable</literal> type is
- used.</para>
- </sect3>
-
- <sect3>
- <title>Declaring column attributes</title>
-
- <para>The column(s) used for a property mapping can be defined using
- the <literal>@Column</literal> annotation. Use it to override
default
- values (see the EJB3 specification for more information on the
- defaults). You can use this annotation at the property level for
- properties that are:</para>
-
- <itemizedlist>
- <listitem>
- <para>not annotated at all</para>
- </listitem>
-
- <listitem>
- <para>annotated with
<literal>@Basic</literal></para>
- </listitem>
-
- <listitem>
- <para>annotated with
<literal>@Version</literal></para>
- </listitem>
-
- <listitem>
- <para>annotated with <literal>@Lob</literal></para>
- </listitem>
-
- <listitem>
- <para>annotated with
<literal>@Temporal</literal></para>
- </listitem>
-
- <listitem>
- <para>annotated with
-
<literal>(a)org.hibernate.annotations.CollectionOfElements</literal>
- (for Hibernate only)</para>
- </listitem>
- </itemizedlist>
-
- <programlisting>
-@Entity
-public class Flight implements Serializable {
-...
-@Column(updatable = false, name = "flight_name", nullable = false, length=50)
-public String getName() { ... }
- </programlisting>
-
- <para>The <literal>name</literal> property is mapped to the
- <literal>flight_name</literal> column, which is not nullable, has a
- length of 50 and is not updatable (making the property
- immutable).</para>
-
- <para>This annotation can be applied to regular properties as well as
- <literal>@Id</literal> or <literal>@Version</literal>
- properties.</para>
-
- <programlistingco>
- <areaspec>
- <area coords="2 55" id="hm1" />
-
- <area coords="3 55" id="hm2" />
-
- <area coords="4 55" id="hm3" />
-
- <area coords="5 55" id="hm4" />
-
- <area coords="6 55" id="hm5" />
-
- <area coords="7 55" id="hm6" />
-
- <area coords="8 55" id="hm7" />
-
- <area coords="9 55" id="hm8" />
-
- <area coords="10 55" id="hm9" />
-
- <area coords="11 55" id="hm10" />
- </areaspec>
-
- <programlisting>@Column(
- name="columnName";
- boolean unique() default false;
- boolean nullable() default true;
- boolean insertable() default true;
- boolean updatable() default true;
- String columnDefinition() default "";
- String table() default "";
- int length() default 255;
- int precision() default 0; // decimal precision
- int scale() default 0; // decimal scale</programlisting>
-
- <calloutlist>
- <callout arearefs="hm1">
- <para><literal>name</literal> (optional): the column
name
- (default to the property name)</para>
- </callout>
-
- <callout arearefs="hm2">
- <para><literal>unique</literal> (optional): set a unique
- constraint on this column or not (default false)</para>
- </callout>
-
- <callout arearefs="hm3">
- <para><literal>nullable</literal> (optional): set the
column as
- nullable (default false).</para>
- </callout>
-
- <callout arearefs="hm4">
- <para><literal>insertable</literal> (optional): whether
or not
- the column will be part of the insert statement (default
- true)</para>
- </callout>
-
- <callout arearefs="hm5">
- <para><literal>updatable</literal> (optional): whether or
not
- the column will be part of the update statement (default
- true)</para>
- </callout>
-
- <callout arearefs="hm6">
- <para><literal>columnDefinition</literal> (optional):
override
- the sql DDL fragment for this particular column (non
- portable)</para>
- </callout>
-
- <callout arearefs="hm7">
- <para><literal>table</literal> (optional): define the
targeted
- table (default primary table)</para>
- </callout>
-
- <callout arearefs="hm8">
-
<para><literal><literal>length</literal></literal>
(optional):
- column length (default 255)</para>
- </callout>
-
- <callout arearefs="hm8">
-
<para><literal><literal>precision</literal></literal>
- (optional): column decimal precision (default 0)</para>
- </callout>
-
- <callout arearefs="hm10">
-
<para><literal><literal>scale</literal></literal>
(optional):
- column decimal scale if useful (default 0)</para>
- </callout>
- </calloutlist>
- </programlistingco>
- </sect3>
-
- <sect3>
- <title>Embedded objects (aka components)</title>
-
- <para>It is possible to declare an embedded component inside an entity
- and even override its column mapping. Component classes have to be
- annotated at the class level with the <literal>@Embeddable</literal>
- annotation. It is possible to override the column mapping of an
- embedded object for a particular entity using the
- <literal>@Embedded</literal> and
<literal>@AttributeOverride</literal>
- annotation in the associated property:</para>
-
- <programlisting>
-@Entity
-public class Person implements Serializable {
-
- // Persistent component using defaults
- Address homeAddress;
-
- @Embedded
- @AttributeOverrides( {
- @AttributeOverride(name="iso2", column =
@Column(name="bornIso2") ),
- @AttributeOverride(name="name", column =
@Column(name="bornCountryName") )
- } )
- Country bornIn;
- ...
-}
- </programlisting>
-
- <programlisting>
-@Embeddable
-public class Address implements Serializable {
- String city;
- Country nationality; //no overriding here
-}
- </programlisting>
-
- <programlisting>
-@Embeddable
-public class Country implements Serializable {
- private String iso2;
- @Column(name="countryName") private String name;
-
- public String getIso2() { return iso2; }
- public void setIso2(String iso2) { this.iso2 = iso2; }
-
-
- public String getName() { return name; }
- public void setName(String name) { this.name = name; }
- ...
-}
- </programlisting>
-
- <para>A embeddable object inherit the access type of its owning entity
- (note that you can override that using the Hibernate specific
- <literal>@AccessType</literal> annotations (see <xref
- linkend="entity-hibspec" />).</para>
-
- <para>The <literal>Person</literal> entity bean has two
component
- properties, <literal>homeAddress</literal> and
- <literal>bornIn</literal>. <literal>homeAddress</literal>
property has
- not been annotated, but Hibernate will guess that it is a persistent
- component by looking for the <literal>@Embeddable</literal>
annotation
- in the Address class. We also override the mapping of a column name
- (to <literal>bornCountryName</literal>) with the
- <literal>@Embedded</literal> and <literal>@AttributeOverride
- </literal>annotations for each mapped attribute of
- <literal>Country</literal>. As you can see, <literal>Country
- </literal>is also a nested component of
<literal>Address</literal>,
- again using auto-detection by Hibernate and EJB3 defaults. Overriding
- columns of embedded objects of embedded objects is currently not
- supported in the EJB3 spec, however, Hibernate Annotations supports it
- through dotted expressions.</para>
-
- <para><programlisting> @Embedded
- @AttributeOverrides( {
- @AttributeOverride(name="city", column =
@Column(name="fld_city") )
- @AttributeOverride(name="<emphasis
role="bold">nationality.iso2</emphasis>", column =
@Column(name="nat_Iso2") ),
- @AttributeOverride(name="<emphasis
role="bold">nationality.name</emphasis>", column =
@Column(name="nat_CountryName") )
- //nationality columns in homeAddress are overridden
- } )
- Address homeAddress;</programlisting>Hibernate Annotations supports one
- more feature that is not explicitly supported by the EJB3
- specification. You can annotate a embedded object with the
- <literal>@MappedSuperclass</literal> annotation to make the
superclass
- properties persistent (see <literal>@MappedSuperclass</literal> for
- more informations).</para>
-
- <para>While not supported by the EJB3 specification, Hibernate
- Annotations allows you to use association annotations in an embeddable
- object (ie <literal>@*ToOne</literal> nor
- <literal>@*ToMany</literal>). To override the association columns
you
- can use <literal>(a)AssociationOverride</literal>.</para>
-
- <para>If you want to have the same embeddable object type twice in the
- same entity, the column name defaulting will not work: at least one of
- the columns will have to be explicit. Hibernate goes beyond the EJB3
- spec and allows you to enhance the defaulting mechanism through the
- <classname>NamingStrategy</classname>.
- <classname>DefaultComponentSafeNamingStrategy</classname> is a small
- improvement over the default EJB3NamingStrategy that allows embedded
- objects to be defaulted even if used twice in the same entity.</para>
- </sect3>
-
- <sect3>
- <title>Non-annotated property defaults</title>
-
- <para>If a property is not annotated, the following rules
- apply:</para>
-
- <itemizedlist>
- <listitem>
- If the property is of a single type, it is mapped as @Basic
- </listitem>
-
- <listitem>
- Otherwise, if the type of the property is annotated as @Embeddable, it is
mapped as @Embedded
- </listitem>
-
- <listitem>
- Otherwise, if the type of the property is Serializable, it is mapped as
@Basic in a column holding the object in its serialized version
- </listitem>
-
- <listitem>
- Otherwise, if the type of the property is java.sql.Clob or java.sql.Blob, it
is mapped as @Lob with the appropriate LobType
- </listitem>
- </itemizedlist>
- </sect3>
- </sect2>
-
- <sect2 id="entity-mapping-identifier" label=""
- xreflabel="Mapping identifier properties">
- <title>Mapping identifier properties</title>
-
- <para>The <literal>@Id</literal> annotation lets you define
which
- property is the identifier of your entity bean. This property can be set
- by the application itself or be generated by Hibernate (preferred). You
- can define the identifier generation strategy thanks to the
- <literal>@GeneratedValue</literal> annotation:</para>
-
- <itemizedlist>
- <listitem>
- AUTO - either identity column, sequence or table depending on the underlying
DB
- </listitem>
-
- <listitem>
- TABLE - table holding the id
- </listitem>
-
- <listitem>
- IDENTITY - identity column
- </listitem>
-
- <listitem>
- SEQUENCE - sequence
- </listitem>
- </itemizedlist>
-
- <para>Hibernate provides more id generators than the basic EJB3 ones.
- Check <xref linkend="entity-hibspec" /> for more
informations.</para>
-
- <para>The following example shows a sequence generator using the
- SEQ_STORE configuration (see below)</para>
-
- <programlisting>
-@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE")
-public Integer getId() { ... }
- </programlisting>
-
- <para>The next example uses the identity generator:</para>
-
- <programlisting>
-@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
-public Long getId() { ... }
- </programlisting>
-
- <para>The <literal>AUTO</literal> generator is the preferred type
for
- portable applications (across several DB vendors). The identifier
- generation configuration can be shared for several
- <literal>@Id</literal> mappings with the generator attribute. There
are
- several configurations available through
- <literal>@SequenceGenerator</literal> and
- <literal>@TableGenerator</literal>. The scope of a generator can be
the
- application or the class. Class-defined generators are not visible
- outside the class and can override application level generators.
- Application level generators are defined at XML level (see <xref
- linkend="xml-overriding" />):</para>
-
- <programlisting><table-generator name="EMP_GEN"
- table="GENERATOR_TABLE"
- pk-column-name="key"
- value-column-name="hi"
- pk-column-value="EMP"
- allocation-size="20"/>
-
-//and the annotation equivalent
-
-(a)javax.persistence.TableGenerator(
- name="EMP_GEN",
- table="GENERATOR_TABLE",
- pkColumnName = "key",
- valueColumnName = "hi"
- pkColumnValue="EMP",
- allocationSize=20
-)
-
-<sequence-generator name="SEQ_GEN"
- sequence-name="my_sequence"
- allocation-size="20"/>
-
-//and the annotation equivalent
-
-(a)javax.persistence.SequenceGenerator(
- name="SEQ_GEN",
- sequenceName="my_sequence",
- allocationSize=20
-)
- </programlisting>
-
- <para>If JPA XML (like <filename>META-INF/orm.xml</filename>) is
used to
- define thegenerators, <literal>EMP_GEN</literal> and
- <literal>SEQ_GEN</literal> are application level generators.
- <literal>EMP_GEN</literal> defines a table based id generator using
the
- hilo algorithm with a <literal>max_lo</literal> of 20. The hi value is
- kept in a <literal>table</literal>
"<literal>GENERATOR_TABLE</literal>".
- The information is kept in a row where <literal>pkColumnName</literal>
- "key" is equals to <literal>pkColumnValue</literal>
- "<literal>EMP</literal>" and column
<literal>valueColumnName</literal>
- "<literal>hi</literal>" contains the the next high value
used.</para>
-
- <para><literal>SEQ_GEN</literal> defines a sequence generator
using a
- sequence named <literal>my_sequence</literal>. The allocation size
used
- for this sequence based hilo algorithm is 20. Note that this version of
- Hibernate Annotations does not handle <literal>initialValue</literal>
in
- the sequence generator. The default allocation size is 50, so if you
- want to use a sequence and pickup the value each time, you must set the
- allocation size to 1.</para>
-
- <note>
- <para>Package level definition is no longer supported by the EJB 3.0
- specification. However, you can use the
- <literal>@GenericGenerator</literal> at the package level (see
<xref
- linkend="entity-hibspec-identifier" />).</para>
- </note>
-
- <para>The next example shows the definition of a sequence generator in a
- class scope:</para>
-
- <programlisting>
-@Entity
-(a)javax.persistence.SequenceGenerator(
- name="SEQ_STORE",
- sequenceName="my_sequence"
-)
-public class Store implements Serializable {
- private Long id;
-
- @Id @GeneratedValue(strategy=GenerationType.SEQUENCE,
generator="SEQ_STORE")
- public Long getId() { return id; }
-}
- </programlisting>
-
- <para>This class will use a sequence named my_sequence and the SEQ_STORE
- generator is not visible in other classes. Note that you can check the
- Hibernate Annotations tests in the org.hibernate.test.metadata.id
- package for more examples.</para>
-
- <para>You can define a composite primary key through several
- syntaxes:</para>
-
- <itemizedlist>
- <listitem>
- annotate the component property as @Id and make the component class
@Embeddable
- </listitem>
-
- <listitem>
- annotate the component property as @EmbeddedId
- </listitem>
-
- <listitem>
- annotate the class as @IdClass and annotate each property of the entity
involved in the primary key with @Id
- </listitem>
- </itemizedlist>
-
- <para>While quite common to the EJB2 developer,
- <literal>@IdClass</literal> is likely new for Hibernate users. The
- composite primary key class corresponds to multiple fields or properties
- of the entity class, and the names of primary key fields or properties
- in the primary key class and those of the entity class must match and
- their types must be the same. Let's look at an example:</para>
-
- <programlisting>@Entity
-<emphasis role="bold">(a)IdClass(FootballerPk.class)</emphasis>
-public class Footballer {
- //part of the id key
- <emphasis role="bold">@Id</emphasis> public String
getFirstname() {
- return firstname;
- }
-
- public void setFirstname(String firstname) {
- this.firstname = firstname;
- }
-
- //part of the id key
- <emphasis role="bold">@Id</emphasis> public String
getLastname() {
- return lastname;
- }
-
- public void setLastname(String lastname) {
- this.lastname = lastname;
- }
-
- public String getClub() {
- return club;
- }
-
- public void setClub(String club) {
- this.club = club;
- }
-
- //appropriate equals() and hashCode() implementation
-}
-
-@Embeddable
-public class FootballerPk implements Serializable {
- //same name and type as in Footballer
- public String getFirstname() {
- return firstname;
- }
-
- public void setFirstname(String firstname) {
- this.firstname = firstname;
- }
-
- //same name and type as in Footballer
- public String getLastname() {
- return lastname;
- }
-
- public void setLastname(String lastname) {
- this.lastname = lastname;
- }
-
- //appropriate equals() and hashCode() implementation
-}
-</programlisting>
-
- <para>As you may have seen, <literal>@IdClass</literal> points to
the
- corresponding primary key class.</para>
-
- <para>While not supported by the EJB3 specification, Hibernate allows
- you to define associations inside a composite identifier. Simply use the
- regular annotations for that</para>
-
- <programlisting>@Entity
-@AssociationOverride( name="id.channel", joinColumns =
@JoinColumn(name="chan_id") )
-public class TvMagazin {
- @EmbeddedId public TvMagazinPk id;
- @Temporal(TemporalType.TIME) Date time;
-}
-
-@Embeddable
-public class TvMagazinPk implements Serializable {
- @ManyToOne
- public Channel channel;
- public String name;
- @ManyToOne
- public Presenter presenter;
-}
-</programlisting>
- </sect2>
-
- <sect2>
- <title>Mapping inheritance</title>
-
- <para>EJB3 supports the three types of inheritance:</para>
-
- <itemizedlist>
- <listitem>
- Table per Class Strategy: the <union-class> element in Hibernate
- </listitem>
-
- <listitem>
- Single Table per Class Hierarchy Strategy: the <subclass>
element in Hibernate
- </listitem>
-
- <listitem>
- Joined Subclass Strategy: the <joined-subclass> element in
Hibernate
- </listitem>
- </itemizedlist>
-
- <para>The chosen strategy is declared at the class level of the top
- level entity in the hierarchy using the
<literal>@Inheritance</literal>
- annotation.</para>
-
- <note>
- <para>Annotating interfaces is currently not supported.</para>
- </note>
-
- <sect3>
- <title>Table per class</title>
-
- <para>This strategy has many drawbacks (esp. with polymorphic queries
- and associations) explained in the EJB3 spec, the Hibernate reference
- documentation, Hibernate in Action, and many other places. Hibernate
- work around most of them implementing this strategy using <literal>SQL
- UNION</literal> queries. It is commonly used for the top level of an
- inheritance hierarchy:</para>
-
- <programlisting>
-@Entity
-@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
-public class Flight implements Serializable {
- </programlisting>
-
- <para>This strategy support one to many associations provided that
- they are bidirectional. This strategy does not support the
- <literal>IDENTITY</literal> generator strategy: the id has to be
- shared across several tables. Consequently, when using this strategy,
- you should not use <literal>AUTO </literal>nor
- <literal>IDENTITY</literal>.</para>
- </sect3>
-
- <sect3>
- <title>Single table per class hierarchy</title>
-
- <para>All properties of all super- and subclasses are mapped into the
- same table, instances are distinguished by a special discriminator
- column:</para>
-
- <programlisting>
-@Entity
-(a)Inheritance(strategy=InheritanceType.SINGLE_TABLE)
-@DiscriminatorColumn(
- name="planetype",
- discriminatorType=DiscriminatorType.STRING
-)
-@DiscriminatorValue("Plane")
-public class Plane { ... }
-
-@Entity
-@DiscriminatorValue("A320")
-public class A320 extends Plane { ... }
- </programlisting>
-
- <para><classname>Plane</classname> is the superclass, it
defines the
- inheritance strategy
<literal>InheritanceType.SINGLE_TABLE</literal>.
- It also defines the discriminator column through the
- <literal>@DiscriminatorColumn</literal> annotation, a discriminator
- column can also define the discriminator type. Finally, the
- <literal>@DiscriminatorValue</literal> annotation defines the value
- used to differentiate a class in the hierarchy. All of these
- attributes have sensible default values. The default name of the
- discriminator column is <literal>DTYPE</literal>. The default
- discriminator value is the entity name (as defined in
- <literal>(a)Entity.name</literal>) for DiscriminatorType.STRING.
- <classname>A320</classname> is a subclass; you only have to define
- discriminator value if you don't want to use the default value. The
- strategy and the discriminator type are implicit.</para>
-
- <para><literal>@Inheritance</literal> and
- <literal>@DiscriminatorColumn</literal> should only be defined at
the
- top of the entity hierarchy.</para>
- </sect3>
-
- <sect3>
- <title>Joined subclasses</title>
-
- <para>The<literal> @PrimaryKeyJoinColumn</literal> and
- <literal>@PrimaryKeyJoinColumns</literal> annotations define the
- primary key(s) of the joined subclass table:</para>
-
- <programlisting>
-@Entity
-(a)Inheritance(strategy=InheritanceType.JOINED)
-public class Boat implements Serializable { ... }
-
-@Entity
-public class Ferry extends Boat { ... }
-
-@Entity
-@PrimaryKeyJoinColumn(name="BOAT_ID")
-public class AmericaCupClass extends Boat { ... }
- </programlisting>
-
- <para>All of the above entities use the
<literal>JOINED</literal>
- strategy, the <literal>Ferry</literal> table is joined with the
- <literal>Boat</literal> table using the same primary key names. The
- <literal>AmericaCupClass</literal> table is joined with
- <literal>Boat</literal> using the join condition <code>Boat.id
=
- AmericaCupClass.BOAT_ID</code>.</para>
- </sect3>
-
- <sect3>
- <title>Inherit properties from superclasses</title>
-
- <para>This is sometimes useful to share common properties through a
- technical or a business superclass without including it as a regular
- mapped entity (ie no specific table for this entity). For that purpose
- you can map them as
<literal>(a)MappedSuperclass</literal>.</para>
-
- <programlisting>@MappedSuperclass
-public class BaseEntity {
- @Basic
- @Temporal(TemporalType.TIMESTAMP)
- public Date getLastUpdate() { ... }
- public String getLastUpdater() { ... }
- ...
-}
-
-@Entity class Order extends BaseEntity {
- @Id public Integer getId() { ... }
- ...
-}</programlisting>
-
- <para>In database, this hierarchy will be represented as an
- <literal>Order</literal> table having the
<literal>id</literal>,
- <literal>lastUpdate</literal> and
<literal>lastUpdater</literal>
- columns. The embedded superclass property mappings are copied into
- their entity subclasses. Remember that the embeddable superclass is
- not the root of the hierarchy though.</para>
-
- <note>
- <para>Properties from superclasses not mapped as
- <literal>@MappedSuperclass</literal> are ignored.</para>
- </note>
-
- <note>
- <para>The access type (field or methods), is inherited from the root
- entity, unless you use the Hibernate annotation
- <literal>@AccessType</literal></para>
- </note>
-
- <note>
- <para>The same notion can be applied to
- <literal>@Embeddable</literal> objects to persist properties from
- their superclasses. You also need to use
- <literal>@MappedSuperclass</literal> to do that (this should not
be
- considered as a standard EJB3 feature though)</para>
- </note>
-
- <note>
- <para>It is allowed to mark a class as
- <literal>@MappedSuperclass</literal> in the middle of the mapped
- inheritance hierarchy.</para>
- </note>
-
- <note>
- <para>Any class in the hierarchy non annotated with
- <literal>@MappedSuperclass</literal> nor
<literal>@Entity</literal>
- will be ignored.</para>
- </note>
-
- <para>You can override columns defined in entity superclasses at the
- root entity level using the <literal>@AttributeOverride</literal>
- annotation.</para>
-
- <programlisting>@MappedSuperclass
-public class FlyingObject implements Serializable {
-
- public int getAltitude() {
- return altitude;
- }
-
- @Transient
- public int getMetricAltitude() {
- return metricAltitude;
- }
-
- @ManyToOne
- public PropulsionType getPropulsion() {
- return metricAltitude;
- }
- ...
-}
-
-@Entity
-@AttributeOverride( name="altitude", column =
@Column(name="fld_altitude") )
-@AssociationOverride( name="propulsion", joinColumns =
@JoinColumn(name="fld_propulsion_fk") )
-public class Plane extends FlyingObject {
- ...
-}</programlisting>
-
- <para>The <literal>altitude</literal> property will be
persisted in an
- <literal>fld_altitude</literal> column of table
- <literal>Plane</literal> and the propulsion association will be
- materialized in a <literal>fld_propulsion_fk</literal> foreign key
- column.</para>
-
- <para>You can define <literal>@AttributeOverride</literal>(s)
and
- <literal>@AssociationOverride</literal>(s) on
- <literal>@Entity</literal> classes,
- <literal>@MappedSuperclass</literal> classes and properties pointing
- to an <literal>@Embeddable</literal> object.</para>
- </sect3>
- </sect2>
-
- <sect2 id="entity-mapping-association">
- <title>Mapping entity bean associations/relationships</title>
-
- <sect3>
- <title>One-to-one</title>
-
- <para>You can associate entity beans through a one-to-one relationship
- using <literal>@OneToOne</literal>. There are three cases for
- one-to-one associations: either the associated entities share the same
- primary keys values, a foreign key is held by one of the entities
- (note that this FK column in the database should be constrained unique
- to simulate one-to-one multiplicity), or a association table is used
- to store the link between the 2 entities (a unique constraint has to
- be defined on each fk to ensure the one to one multiplicity)</para>
-
- <para>First, we map a real one-to-one association using shared primary
- keys:</para>
-
- <programlisting>
-@Entity
-public class Body {
- @Id
- public Long getId() { return id; }
-
- @OneToOne(cascade = CascadeType.ALL)
- @PrimaryKeyJoinColumn
- public Heart getHeart() {
- return heart;
- }
- ...
-}
- </programlisting>
-
- <programlisting>
-@Entity
-public class Heart {
- @Id
- public Long getId() { ...}
-}
- </programlisting>
-
- <para>The one to one is marked as true by using the
- <literal>@PrimaryKeyJoinColumn</literal> annotation.</para>
-
- <para>In the following example, the associated entities are linked
- through a foreign key column:</para>
-
- <programlisting>
-@Entity
-public class Customer implements Serializable {
- @OneToOne(cascade = CascadeType.ALL)
- <emphasis
role="bold">@JoinColumn(name="passport_fk")</emphasis>
- public Passport getPassport() {
- ...
- }
-
-@Entity
-public class Passport implements Serializable {
- @OneToOne(<emphasis role="bold">mappedBy =
"passport"</emphasis>)
- public Customer getOwner() {
- ...
-}
- </programlisting>
-
- <para>A <classname>Customer</classname> is linked to a
- <classname>Passport</classname>, with a foreign key column named
- <literal>passport_fk</literal> in the
<literal>Customer</literal>
- table. The join column is declared with the
- <literal>@JoinColumn</literal> annotation which looks like the
- <literal>@Column</literal> annotation. It has one more parameters
- named <literal>referencedColumnName</literal>. This parameter
declares
- the column in the targeted entity that will be used to the join. Note
- that when using
-
<literal><literal>referencedColumnName</literal></literal> to a
non
- primary key column, the associated class has to be
- <classname>Serializable</classname>. Also note that the
-
<literal><literal>referencedColumnName</literal></literal> to a
non
- primary key column has to be mapped to a property having a single
- column (other cases might not work).</para>
-
- <para>The association may be bidirectional. In a bidirectional
- relationship, one of the sides (and only one) has to be the owner: the
- owner is responsible for the association column(s) update. To declare
- a side as <emphasis>not</emphasis> responsible for the relationship,
- the attribute <literal>mappedBy</literal> is used.
- <literal>mappedBy</literal> refers to the property name of the
- association on the owner side. In our case, this is
- <literal>passport</literal>. As you can see, you don't have to
(must
- not) declare the join column since it has already been declared on the
- owners side.</para>
-
- <para>If no <literal>@JoinColumn</literal> is declared on the
owner
- side, the defaults apply. A join column(s) will be created in the
- owner table and its name will be the concatenation of the name of the
- relationship in the owner side, <keycap>_</keycap> (underscore), and
- the name of the primary key column(s) in the owned side. In this
- example <literal>passport_id</literal> because the property name is
- <literal>passport</literal> and the column id of
<literal>Passport
- </literal>is <literal>id</literal>.</para>
-
- <para>The third possibility (using an association table) is very
- exotic.</para>
-
- <programlisting>
-@Entity
-public class Customer implements Serializable {
- @OneToOne(cascade = CascadeType.ALL)
- <emphasis role="bold">@JoinTable(name =
"CustomerPassports"
- joinColumns = @JoinColumn(name="customer_fk"),
- inverseJoinColumns = @JoinColumns(name="passport_fk")</emphasis>
- )
- public Passport getPassport() {
- ...
- }
-
-@Entity
-public class Passport implements Serializable {
- @OneToOne(<emphasis role="bold">mappedBy =
"passport"</emphasis>)
- public Customer getOwner() {
- ...
-}
- </programlisting>
-
- <para>A <classname>Customer</classname> is linked to a
- <classname>Passport</classname> through a association table named
- <literal>CustomerPassports</literal> ; this association table has a
- foreign key column named <literal>passport_fk</literal> pointing to
- the <literal>Passport</literal> table (materialized by the
- <literal>inverseJoinColumn</literal>, and a foreign key column named
- <literal>customer_fk</literal> pointing to the
- <literal>Customer</literal> table materialized by the
- <literal>joinColumns</literal> attribute.</para>
-
- <para>You must declare the join table name and the join columns
- explicitly in such a mapping.</para>
- </sect3>
-
- <sect3>
- <title>Many-to-one</title>
-
- <para>Many-to-one associations are declared at the property level with
- the annotation <literal>@ManyToOne</literal>:</para>
-
- <programlisting>
-@Entity()
-public class Flight implements Serializable {
- <emphasis role="bold">@ManyToOne</emphasis>( cascade =
{CascadeType.PERSIST, CascadeType.MERGE} )
- @JoinColumn(name="COMP_ID")
- public Company getCompany() {
- return company;
- }
- ...
-}
- </programlisting>
-
- <para>The <literal>@JoinColumn</literal> attribute is optional,
the
- default value(s) is like in one to one, the concatenation of the name
- of the relationship in the owner side, <keycap>_</keycap>
- (underscore), and the name of the primary key column in the owned
- side. In this example <literal>company_id</literal> because the
- property name is <literal>company</literal> and the column id of
- Company is <literal>id</literal>.</para>
-
- <para><literal>@ManyToOne</literal> has a parameter named
- <literal>targetEntity</literal> which describes the target entity
- name. You usually don't need this parameter since the default value
- (the type of the property that stores the association) is good in
- almost all cases. However this is useful when you want to use
- interfaces as the return type instead of the regular entity.</para>
-
- <programlisting>
-@Entity()
-public class Flight implements Serializable {
- @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, <emphasis
- role="bold">targetEntity=CompanyImpl.class</emphasis> )
- @JoinColumn(name="COMP_ID")
- public Company getCompany() {
- return company;
- }
- ...
-}
-
-public interface Company {
- ...
- </programlisting>
-
- <para>You can alse map a many to one association through an
- association table. This association table described by the
- <literal>@JoinTable</literal> annotation will contains a foreign key
- referencing back the entity table (through
- <literal>(a)JoinTable.joinColumns</literal>) and a a foreign key
- referencing the target entity table (through
- <literal>(a)JoinTable.inverseJoinColumns</literal>).</para>
-
- <programlisting>
-@Entity()
-public class Flight implements Serializable {
- @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
- <emphasis role="bold">@JoinTable(name="Flight_Company",
- joinColumns = @JoinColumn(name="FLIGHT_ID"),
- inverseJoinColumns = @JoinColumns(name="COMP_ID")
- )</emphasis>
- public Company getCompany() {
- return company;
- }
- ...
-}
- </programlisting>
- </sect3>
-
- <sect3 id="entity-mapping-association-collections"
revision="1">
- <title>Collections</title>
-
- <sect4 id="entity-mapping-association-collections-overview"
- revision="1">
- <title>Overview</title>
-
- <para>You can map <classname>Collection</classname>,
- <literal>List</literal> (ie ordered lists, not indexed lists),
- <literal>Map</literal> and <classname>Set</classname>.
The EJB3
- specification describes how to map an ordered list (ie a list
- ordered at load time) using
- <literal>(a)javax.persistence.OrderBy</literal> annotation: this
- annotation takes into parameter a list of comma separated (target
- entity) properties to order the collection by (eg <code>firstname
- asc, age desc</code>), if the string is empty, the collection will
- be ordered by id. For true indexed
- collections, please refer to the <xref linkend="entity-hibspec"
/>.
- EJB3 allows you to map Maps using as a key one of the target entity
- property using
<literal>@MapKey(name="myProperty")</literal>
- (myProperty is a property name in the target entity). When using
- <literal>@MapKey</literal> (without property name), the target
- entity primary key is used. The map key uses the same column as the
- property pointed out: there is no additional column defined to hold
- the map key, and it does make sense since the map key actually
- represent a target property. Be aware that once loaded, the key is
- no longer kept in sync with the property, in other words, if you
- change the property value, the key will not change automatically in
- your Java model (for true map support please refers to <xref
- linkend="entity-hibspec" />). Many people confuse
- <literal><map></literal> capabilities and
- <literal>@MapKey</literal> ones. These are two different features.
- <literal>@MapKey</literal> still has some limitations, please
check
- the forum or the JIRA tracking system for more informations.</para>
-
- <para>Hibernate has several notions of collections.</para>
-
- <para></para>
-
- <table>
- <title>Collections semantics</title>
-
- <tgroup cols="3">
- <colspec colname="c1" />
-
- <colspec colname="c2" />
-
- <colspec colname="c3" colnum="2" />
-
- <thead>
- <row>
- <entry>Semantic</entry>
-
- <entry>java representation</entry>
-
- <entry>annotations</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>Bag semantic</entry>
-
- <entry>java.util.List, java.util.Collection</entry>
-
- <entry>(a)org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany</entry>
- </row>
-
- <row>
- <entry>Bag semantic with primary key (withtout the
- limitations of Bag semantic)</entry>
-
- <entry>java.util.List, java.util.Collection</entry>
-
- <entry>((a)org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany) and @CollectionId</entry>
- </row>
-
- <row>
- <entry>List semantic</entry>
-
- <entry>java.util.List</entry>
-
- <entry>((a)org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany) and
- @org.hibernate.annotations.IndexColumn</entry>
- </row>
-
- <row>
- <entry>Set semantic</entry>
-
- <entry>java.util.Set</entry>
-
- <entry>(a)org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany</entry>
- </row>
-
- <row>
- <entry>Map semantic</entry>
-
- <entry>java.util.Map</entry>
-
- <entry>((a)org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany) and (nothing or
- @org.hibernate.annotations.MapKey/MapKeyManyToMany for true
- map support, OR @javax.persistence.MapKey</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <remark>So specifically, java.util.List collections without
- @org.hibernate.annotations.IndexColumn are going to be considered as
- bags.</remark>
-
- <para>Collection of primitive, core type or embedded objects is not
- supported by the EJB3 specification. Hibernate Annotations allows
- them however (see <xref linkend="entity-hibspec"
/>).</para>
-
- <programlisting>@Entity public class City {
- @OneToMany(mappedBy="city")
- <emphasis
role="bold">@OrderBy("streetName")</emphasis>
- public List<Street> getStreets() {
- return streets;
- }
-...
-}
-
-@Entity public class Street {
- <emphasis role="bold">public String getStreetName()</emphasis>
{
- return streetName;
- }
-
- @ManyToOne
- public City getCity() {
- return city;
- }
- ...
-}
-
-
-@Entity
-public class Software {
- @OneToMany(mappedBy="software")
- <emphasis
role="bold">@MapKey(name="codeName")</emphasis>
- public Map<String, Version> getVersions() {
- return versions;
- }
-...
-}
-
-@Entity
-@Table(name="tbl_version")
-public class Version {
- <emphasis role="bold">public String getCodeName()</emphasis>
{...}
-
- @ManyToOne
- public Software getSoftware() { ... }
-...
-}</programlisting>
-
- <para>So <literal>City</literal> has a collection of
- <literal>Street</literal>s that are ordered by
- <literal>streetName</literal> (of
<literal>Street</literal>) when
- the collection is loaded. <literal>Software</literal> has a map of
- <literal>Version</literal>s which key is the
- <literal>Version</literal>
<literal>codeName</literal>.</para>
-
- <para>Unless the collection is a generic, you will have to define
- <literal>targetEntity</literal>. This is a annotation attribute
that
- take the target entity class as a value.</para>
- </sect4>
-
- <sect4 id="entity-mapping-association-collection-onetomany"
- revision="2">
- <title>One-to-many</title>
-
- <para>One-to-many associations are declared at the property level
- with the annotation <literal>@OneToMany</literal>. One to many
- associations may be bidirectional.</para>
-
- <sect5>
- <title>Bidirectional</title>
-
- <para>Since many to one are (almost) always the owner side of a
- bidirectional relationship in the EJB3 spec, the one to many
- association is annotated by <literal>@OneToMany( mappedBy=...
- )</literal></para>
-
- <programlisting>@Entity
-public class Troop {
- @OneToMany(mappedBy="troop")
- public Set<Soldier> getSoldiers() {
- ...
-}
-
-@Entity
-public class Soldier {
- @ManyToOne
- @JoinColumn(name="troop_fk")
- public Troop getTroop() {
- ...
-} </programlisting>
-
- <para><classname>Troop</classname> has a bidirectional one
to many
- relationship with <literal>Soldier</literal> through the
- <literal>troop</literal> property. You don't have to (must
not)
- define any physical mapping in the <literal>mappedBy</literal>
- side.</para>
-
- <para>To map a bidirectional one to many, with the one-to-many
- side as the owning side, you have to remove the
- <literal>mappedBy</literal> element and set the many to one
- <literal>@JoinColumn</literal> as insertable and updatable to
- false. This solution is obviously not optimized and will produce
- some additional UPDATE statements.</para>
-
- <programlisting>@Entity
-public class Troop {
- @OneToMany
- @JoinColumn(name="troop_fk") //we need to duplicate the physical
information
- public Set<Soldier> getSoldiers() {
- ...
-}
-
-@Entity
-public class Soldier {
- @ManyToOne
- @JoinColumn(name="troop_fk", insertable=false, updatable=false)
- public Troop getTroop() {
- ...
-}</programlisting>
- </sect5>
-
- <sect5>
- <title>Unidirectional</title>
-
- <para>A unidirectional one to many using a foreign key column in
- the owned entity is not that common and not really recommended. We
- strongly advise you to use a join table for this kind of
- association (as explained in the next section). This kind of
- association is described through a
- <literal>@JoinColumn</literal></para>
-
- <programlisting>
-@Entity
-public class Customer implements Serializable {
- @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
- @JoinColumn(name="CUST_ID")
- public Set<Ticket> getTickets() {
- ...
-}
-
-@Entity
-public class Ticket implements Serializable {
- ... //no bidir
-}
- </programlisting>
-
- <para><literal>Customer</literal> describes a
unidirectional
- relationship with <literal>Ticket</literal> using the join
column
- <literal>CUST_ID</literal>.</para>
- </sect5>
-
- <sect5>
- <title>Unidirectional with join table</title>
-
- <para>A unidirectional one to many with join table is much
- preferred. This association is described through an
- <literal>(a)JoinTable</literal>.</para>
-
- <programlisting>
-@Entity
-public class Trainer {
- @OneToMany
- @JoinTable(
- name="TrainedMonkeys",
- joinColumns = { @JoinColumn( name="trainer_id") },
- inverseJoinColumns = @JoinColumn( name="monkey_id")
- )
- public Set<Monkey> getTrainedMonkeys() {
- ...
-}
-
-@Entity
-public class Monkey {
- ... //no bidir
-}
- </programlisting>
-
- <para><literal>Trainer</literal> describes a
unidirectional
- relationship with <classname>Monkey</classname> using the join
- table <classname>TrainedMonkeys</classname>, with a foreign key
- <literal>trainer_id</literal> to
<literal>Trainer</literal>
- (<literal>joinColumns</literal>) and a foreign key
- <literal>monkey_id</literal> to
<literal>Monkey</literal>
- (<literal>inversejoinColumns</literal>).</para>
- </sect5>
-
- <sect5
id="entity-mapping-association-collection-manytomany-default"
- revision="1">
- <title>Defaults</title>
-
- <para>Without describing any physical mapping, a unidirectional
- one to many with join table is used. The table name is the
- concatenation of the owner table name, <keycap>_</keycap>, and
the
- other side table name. The foreign key name(s) referencing the
- owner table is the concatenation of the owner table,
- <keycap>_</keycap>, and the owner primary key column(s) name.
The
- foreign key name(s) referencing the other side is the
- concatenation of the owner property name, <keycap>_</keycap>,
and
- the other side primary key column(s) name. A unique constraint is
- added to the foreign key referencing the other side table to
- reflect the one to many.</para>
-
- <programlisting>
-@Entity
-public class Trainer {
- @OneToMany
- public Set<Tiger> getTrainedTigers() {
- ...
-}
-
-@Entity
-public class Tiger {
- ... //no bidir
-}
- </programlisting>
-
- <para><classname>Trainer</classname> describes a
unidirectional
- relationship with <classname>Tiger</classname> using the join
- table <literal>Trainer_Tiger</literal>, with a foreign key
- <literal>trainer_id</literal> to
<literal>Trainer</literal> (table
- name, <keycap>_</keycap>, trainer id) and a foreign key
- <literal>trainedTigers_id</literal> to
<literal>Monkey</literal>
- (property name, <keycap>_</keycap>, Tiger primary
column).</para>
- </sect5>
- </sect4>
-
- <sect4 id="eentity-mapping-association-collection-manytomany"
- revision="">
- <title>Many-to-many</title>
-
- <sect5>
- <title>Definition</title>
-
- <para>A many-to-many association is defined logically using the
- <literal>@ManyToMany</literal> annotation. You also have to
- describe the association table and the join conditions using the
- <literal>@JoinTable</literal> annotation. If the association is
- bidirectional, one side has to be the owner and one side has to be
- the inverse end (ie. it will be ignored when updating the
- relationship values in the association table):</para>
-
- <programlisting>
-@Entity
-public class Employer implements Serializable {
- @ManyToMany(
- targetEntity=org.hibernate.test.metadata.manytomany.Employee.class,
- cascade={CascadeType.PERSIST, CascadeType.MERGE}
- )
- @JoinTable(
- name="EMPLOYER_EMPLOYEE",
- joinColumns={@JoinColumn(name="EMPER_ID")},
- inverseJoinColumns={@JoinColumn(name="EMPEE_ID")}
- )
- public Collection getEmployees() {
- return employees;
- }
- ...
-}
- </programlisting>
-
- <programlisting>
-@Entity
-public class Employee implements Serializable {
- @ManyToMany(
- cascade={CascadeType.PERSIST, CascadeType.MERGE},
- mappedBy="employees"
- targetEntity=Employer.class
- )
- public Collection getEmployers() {
- return employers;
- }
-}
- </programlisting>
-
- <para>We've already shown the many declarations and the detailed
- attributes for associations. We'll go deeper in the
- <literal>@JoinTable</literal> description, it defines a
- <literal>name</literal>, an array of join columns (an array in
- annotation is defined using { A, B, C }), and an array of inverse
- join columns. The latter ones are the columns of the association
- table which refer to the <classname>Employee</classname> primary
- key (the "other side").</para>
-
- <para>As seen previously, the other side don't have to (must not)
- describe the physical mapping: a simple
- <literal>mappedBy</literal> argument containing the owner side
- property name bind the two.</para>
- </sect5>
-
- <sect5>
- <title>Default values</title>
-
- <para>As any other annotations, most values are guessed in a many
- to many relationship. Without describing any physical mapping in a
- unidirectional many to many the following rules applied. The table
- name is the concatenation of the owner table name,
- <keycap>_</keycap> and the other side table name. The foreign
key
- name(s) referencing the owner table is the concatenation of the
- owner table name, <keycap>_</keycap> and the owner primary key
- column(s). The foreign key name(s) referencing the other side is
- the concatenation of the owner property name,
<keycap>_</keycap>,
- and the other side primary key column(s). These are the same rules
- used for a unidirectional one to many relationship.</para>
-
- <programlisting>
-@Entity
-public class Store {
- @ManyToMany(cascade = CascadeType.PERSIST)
- public Set<City> getImplantedIn() {
- ...
- }
-}
-
-@Entity
-public class City {
- ... //no bidirectional relationship
-}
- </programlisting>
-
- <para>A <literal>Store_City</literal> is used as the join
table.
- The <literal>Store_id</literal> column is a foreign key to the
- <literal>Store</literal> table. The
- <literal>implantedIn_id</literal> column is a foreign key to the
- <literal>City</literal> table.</para>
-
- <para>Without describing any physical mapping in a bidirectional
- many to many the following rules applied. The table name is the
- concatenation of the owner table name, <keycap>_</keycap> and
the
- other side table name. The foreign key name(s) referencing the
- owner table is the concatenation of the other side property name,
- <keycap>_</keycap>, and the owner primary key column(s). The
- foreign key name(s) referencing the other side is the
- concatenation of the owner property name, <keycap>_</keycap>,
and
- the other side primary key column(s). These are the same rules
- used for a unidirectional one to many relationship.</para>
-
- <programlisting>
-@Entity
-public class Store {
- @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
- public Set<Customer> getCustomers() {
- ...
- }
-}
-
-@Entity
-public class Customer {
- @ManyToMany(mappedBy="customers")
- public Set<Store> getStores() {
- ...
- }
-}
- </programlisting>
-
- <para>A <literal>Store_Customer</literal> is used as the
join
- table. The <literal>stores_id</literal> column is a foreign key
to
- the <literal>Store</literal> table. The
- <literal>customers_id</literal> column is a foreign key to the
- <literal>Customer</literal> table.</para>
- </sect5>
- </sect4>
- </sect3>
-
- <sect3>
- <title>Transitive persistence with cascading</title>
-
- <para>You probably have noticed the <literal>cascade</literal>
- attribute taking an array of <classname>CascadeType</classname> as a
- value. The cascade concept in EJB3 is very is similar to the
- transitive persistence and cascading of operations in Hibernate, but
- with slightly different semantics and cascading types:</para>
-
- <itemizedlist>
- <listitem>
- CascadeType.PERSIST: cascades the persist (create) operation to associated
entities persist() is called or if the entity is managed
- </listitem>
-
- <listitem>
- CascadeType.MERGE: cascades the merge operation to associated entities if
merge() is called or if the entity is managed
- </listitem>
-
- <listitem>
- CascadeType.REMOVE: cascades the remove operation to associated entities if
delete() is called
- </listitem>
-
- <listitem>
- CascadeType.REFRESH: cascades the refresh operation to associated entities
if refresh() is called
- </listitem>
-
- <listitem>
- CascadeType.ALL: all of the above
- </listitem>
- </itemizedlist>
-
- <para>Please refer to the chapter 6.3 of the EJB3 specification for
- more information on cascading and create/merge semantics.</para>
- </sect3>
-
- <sect3 id="entity-mapping-association-fetching"
revision="1">
- <title>Association fetching</title>
-
- <para>You have the ability to either eagerly or lazily fetch
- associated entities. The <literal>fetch</literal> parameter can be
set
- to <literal>FetchType.LAZY</literal> or
- <literal>FetchType.EAGER</literal>.
<literal>EAGER</literal> will try
- to use an outer join select to retrieve the associated object, while
- <literal>LAZY</literal> will only trigger a select when the
associated
- object is accessed for the first time. <literal>@OneToMany</literal>
- and <literal>@ManyToMany</literal> associations are defaulted to
- <literal>LAZY</literal> and <literal>@OneToOne</literal>
and
- <literal>@ManyToOne</literal> are defaulted to
- <literal>EAGER</literal>. For more information about static
fetching,
- check <xref linkend="entity-hibspec-singleassoc-fetching"
/>.</para>
-
- <para>The recommanded approach is to use
<literal>LAZY</literal> onn
- all static fetching definitions and override this choice dynamically
- through JPA-QL. JPA-QL has a <literal>fetch</literal> keyword that
- allows you to override laziness when doing a particular query. This is
- very useful to improve performance and is decided on a use case to use
- case basis.</para>
- </sect3>
- </sect2>
-
- <sect2>
- <title>Mapping composite primary and foreign keys</title>
-
- <para>Composite primary keys use a embedded class as the primary key
- representation, so you'd use the <literal>@Id</literal> and
- <literal>@Embeddable</literal> annotations. Alternatively, you can use
- the <literal>@EmbeddedId</literal> annotation. Note that the dependent
- class has to be serializable and implements
-
<methodname>equals()</methodname>/<methodname>hashCode()</methodname>.
- You can also use <literal>@IdClass</literal> as described in <xref
- linkend="entity-mapping-identifier" />.</para>
-
- <programlisting>
-@Entity
-public class RegionalArticle implements Serializable {
-
- @Id
- public RegionalArticlePk getPk() { ... }
-}
-
-@Embeddable
-public class RegionalArticlePk implements Serializable { ... }
- </programlisting>
-
- <para>or alternatively</para>
-
- <programlisting>
-@Entity
-public class RegionalArticle implements Serializable {
-
- @EmbeddedId
- public RegionalArticlePk getPk() { ... }
-}
-
-public class RegionalArticlePk implements Serializable { ... }
- </programlisting>
-
- <para><literal>@Embeddable</literal> inherit the access type of
its
- owning entity unless the Hibernate specific annotation
- <literal>@AccessType</literal> is used. Composite foreign keys (if not
- using the default sensitive values) are defined on associations using
- the <literal>@JoinColumns</literal> element, which is basically an
array
- of <literal>@JoinColumn</literal>. It is considered a good practice to
- express <literal>referencedColumnNames</literal> explicitly.
Otherwise,
- Hibernate will suppose that you use the same order of columns as in the
- primary key declaration.</para>
-
- <programlisting>
-@Entity
-public class Parent implements Serializable {
- @Id
- public ParentPk id;
- public int age;
-
- @OneToMany(cascade=CascadeType.ALL)
- @JoinColumns ({
- @JoinColumn(name="parentCivility", referencedColumnName =
"isMale"),
- @JoinColumn(name="parentLastName", referencedColumnName =
"lastName"),
- @JoinColumn(name="parentFirstName", referencedColumnName =
"firstName")
- })
- public Set<Child> children; //unidirectional
- ...
-}
- </programlisting>
-
- <programlisting>
-@Entity
-public class Child implements Serializable {
- @Id @GeneratedValue
- public Integer id;
-
- @ManyToOne
- @JoinColumns ({
- @JoinColumn(name="parentCivility", referencedColumnName =
"isMale"),
- @JoinColumn(name="parentLastName", referencedColumnName =
"lastName"),
- @JoinColumn(name="parentFirstName", referencedColumnName =
"firstName")
- })
- public Parent parent; //unidirectional
-}
- </programlisting>
-
- <programlisting>
-@Embeddable
-public class ParentPk implements Serializable {
- String firstName;
- String lastName;
- ...
-}
- </programlisting>
-
- <para>Note the explicit usage of the
- <literal>referencedColumnName</literal>.</para>
- </sect2>
-
- <sect2>
- <title>Mapping secondary tables</title>
-
- <para>You can map a single entity bean to several tables using the
- <literal>@SecondaryTable</literal> or
- <literal>@SecondaryTables</literal> class level annotations. To
express
- that a column is in a particular table, use the
<literal>table</literal>
- parameter of <literal>@Column</literal> or
- <literal>(a)JoinColumn</literal>.</para>
-
- <programlisting>
-@Entity
-@Table(name="MainCat")
-<emphasis role="bold">@SecondaryTables({
- @SecondaryTable(name="Cat1", pkJoinColumns={
- @PrimaryKeyJoinColumn(name="cat_id",
referencedColumnName="id")
- ),
- @SecondaryTable(name="Cat2",
uniqueConstraints={@UniqueConstraint(columnNames={"storyPart2"})})
-})</emphasis>
-public class Cat implements Serializable {
-
- private Integer id;
- private String name;
- private String storyPart1;
- private String storyPart2;
-
- @Id @GeneratedValue
- public Integer getId() {
- return id;
- }
-
- public String getName() {
- return name;
- }
-
- <emphasis
role="bold">@Column(table="Cat1")</emphasis>
- public String getStoryPart1() {
- return storyPart1;
- }
-
- <emphasis
role="bold">@Column(table="Cat2")</emphasis>
- public String getStoryPart2() {
- return storyPart2;
- }
-</programlisting>
-
- <para>In this example, <literal>name</literal> will be in
- <literal>MainCat</literal>. <literal>storyPart1</literal>
will be in
- <literal>Cat1</literal> and <literal>storyPart2</literal>
will be in
- <literal>Cat2</literal>. <literal>Cat1</literal> will be
joined to
- <literal>MainCat</literal> using the
<literal>cat_id</literal> as a
- foreign key, and <literal>Cat2</literal> using
<literal>id</literal> (ie
- the same column name, the <literal>MainCat</literal> id column has).
- Plus a unique constraint on <literal>storyPart2</literal> has been
- set.</para>
-
- <para>Check out the JBoss EJB 3 tutorial or the Hibernate Annotations
- unit test suite for more examples.</para>
- </sect2>
- </sect1>
-
- <sect1 id="entity-mapping-query">
- <title>Mapping Queries</title>
-
- <sect2 id="entity-mapping-query-hql" label="Mapping JPAQL/HQL
queries"
- revision="1">
- <title>Mapping JPAQL/HQL queries</title>
-
- <para>You can map EJBQL/HQL queries using annotations.
- <literal>@NamedQuery</literal> and
<literal>@NamedQueries</literal> can
- be defined at the class level or in a JPA XML file. However their
- definitions are global to the session factory/entity manager factory
- scope. A named query is defined by its name and the actual query
- string.</para>
-
- <programlisting><entity-mappings>
- <named-query name="plane.getAll">
- <query>select p from Plane p</query>
- </named-query>
- ...
-</entity-mappings>
-...
-
-@Entity
-(a)NamedQuery(name="night.moreRecentThan", query="select n from Night n
where n.date >= :date")
-public class Night {
- ...
-}
-
-public class MyDao {
- doStuff() {
- Query q = s.getNamedQuery("night.moreRecentThan");
- q.setDate( "date", aMonthAgo );
- List results = q.list();
- ...
- }
- ...
-}
- </programlisting>
-
- <para>You can also provide some hints to a query through an array of
- <literal>QueryHint</literal> through a
<literal>hints</literal>
- attribute.</para>
-
- <para>The availabe Hibernate hints are</para>
-
- <para></para>
-
- <table>
- <title>Query hints</title>
-
- <tgroup cols="2">
- <thead>
- <colspec colname="c1" />
-
- <colspec colname="c2" colnum="2" />
-
- <row>
- <entry>hint</entry>
-
- <entry colname="c2">description</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>org.hibernate.cacheable</entry>
-
- <entry>Whether the query should interact with the second level
- cache (defualt to false)</entry>
- </row>
-
- <row>
- <entry>org.hibernate.cacheRegion</entry>
-
- <entry>Cache region name (default used otherwise)</entry>
- </row>
-
- <row>
- <entry>org.hibernate.timeout</entry>
-
- <entry>Query timeout</entry>
- </row>
-
- <row>
- <entry>org.hibernate.fetchSize</entry>
-
- <entry>resultset fetch size</entry>
- </row>
-
- <row>
- <entry>org.hibernate.flushMode</entry>
-
- <entry>Flush mode used for this query</entry>
- </row>
-
- <row>
- <entry>org.hibernate.cacheMode</entry>
-
- <entry>Cache mode used for this query</entry>
- </row>
-
- <row>
- <entry>org.hibernate.readOnly</entry>
-
- <entry>Entities loaded by this query should be in read only mode
- or not (default to false)</entry>
- </row>
-
- <row>
- <entry>org.hibernate.comment</entry>
-
- <entry>Query comment added to the generated SQL</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect2>
-
- <sect2 id="entity-mapping-query-native" revision="2">
- <title>Mapping native queries</title>
-
- <para>You can also map a native query (ie a plain SQL query). To achieve
- that, you need to describe the SQL resultset structure using
- <literal>@SqlResultSetMapping</literal> (or
- <literal>@SqlResultSetMappings</literal> if you plan to define several
- resulset mappings). Like <literal>@NamedQuery</literal>, a
- <literal>@SqlResultSetMapping</literal> can be defined at class level
or
- in a JPA XML file. However its scope is global to the
- application.</para>
-
- <para>As we will see, a <literal>resultSetMapping</literal>
parameter is
- defined in <literal>@NamedNativeQuery</literal>, it represents the
name
- of a defined <literal>@SqlResultSetMapping</literal>. The resultset
- mapping declares the entities retrieved by this native query. Each field
- of the entity is bound to an SQL alias (or column name). All fields of
- the entity including the ones of subclasses and the foreign key columns
- of related entities have to be present in the SQL query. Field
- definitions are optional provided that they map to the same column name
- as the one declared on the class property.</para>
-
-
<para><programlisting>@NamedNativeQuery(name="night&area",
query="select night.id nid, night.night_duration, "
- + " night.night_date, area.id aid, night.area_id, area.name "
- + "from Night night, Area area where night.area_id = area.id",
<emphasis
-
role="bold">resultSetMapping="joinMapping"</emphasis>)
-@SqlResultSetMapping(name="joinMapping", entities={
- @EntityResult(entityClass=org.hibernate.test.annotations.query.Night.class, fields =
{
- @FieldResult(name="id", column="nid"),
- @FieldResult(name="duration", column="night_duration"),
- @FieldResult(name="date", column="night_date"),
- @FieldResult(name="area", column="area_id"),
- discriminatorColumn="disc"
- }),
- @EntityResult(entityClass=org.hibernate.test.annotations.query.Area.class, fields =
{
- @FieldResult(name="id", column="aid"),
- @FieldResult(name="name", column="name")
- })
- }
-)</programlisting></para>
-
- <para>In the above example, the
<literal>night&area</literal> named
- query use the <literal>joinMapping</literal> result set mapping. This
- mapping returns 2 entities, <literal>Night</literal> and
- <literal>Area</literal>, each property is declared and associated to a
- column name, actually the column name retrieved by the query. Let's now
- see an implicit declaration of the property / column.</para>
-
- <programlisting>@Entity
-<emphasis role="bold">@SqlResultSetMapping(name="implicit",
entities=(a)EntityResult(entityClass=org.hibernate.test.annotations.query.SpaceShip.class))
-@NamedNativeQuery(name="implicitSample", query="select * from
SpaceShip", resultSetMapping="implicit")</emphasis>
-public class SpaceShip {
- private String name;
- private String model;
- private double speed;
-
- @Id
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- @Column(name="model_txt")
- public String getModel() {
- return model;
- }
-
- public void setModel(String model) {
- this.model = model;
- }
-
- public double getSpeed() {
- return speed;
- }
-
- public void setSpeed(double speed) {
- this.speed = speed;
- }
-}</programlisting>
-
- <para>In this example, we only describe the entity member of the result
- set mapping. The property / column mappings is done using the entity
- mapping values. In this case the <literal>model</literal> property is
- bound to the <literal>model_txt </literal>column. If the association
to
- a related entity involve a composite primary key, a
- <literal>@FieldResult</literal> element should be used for each
foreign
- key column. The <literal>@FieldResult</literal> name is composed of
the
- property name for the relationship, followed by a dot ("."), followed by
- the name or the field or property of the primary key.</para>
-
- <programlisting>@Entity
-@SqlResultSetMapping(name="compositekey",
-
entities=(a)EntityResult(entityClass=org.hibernate.test.annotations.query.SpaceShip.class,
- fields = {
- @FieldResult(name="name", column = "name"),
- @FieldResult(name="model", column = "model"),
- @FieldResult(name="speed", column = "speed"),
-<emphasis role="bold">
@FieldResult(name="captain.firstname", column = "firstn"),
- @FieldResult(name="captain.lastname", column =
"lastn"),</emphasis>
- @FieldResult(name="dimensions.length", column =
"length"),
- @FieldResult(name="dimensions.width", column =
"width")
- }),
- columns = { @ColumnResult(name = "surface"),
- @ColumnResult(name = "volume") } )
-
-@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;
- }
-}
-
-@Entity
-(a)IdClass(Identity.class)
-public class Captain implements Serializable {
- private String firstname;
- private String lastname;
-
- @Id
- public String getFirstname() {
- return firstname;
- }
-
- public void setFirstname(String firstname) {
- this.firstname = firstname;
- }
-
- @Id
- public String getLastname() {
- return lastname;
- }
-
- public void setLastname(String lastname) {
- this.lastname = lastname;
- }
-}
-</programlisting>
-
- <note>
- <para>If you look at the dimension property, you'll see that Hibernate
- supports the dotted notation for embedded objects (you can even have
- nested embedded objects). EJB3 implementations do not have to support
- this feature, we do :-)</para>
- </note>
-
- <para>If you retrieve a single entity and if you use the default
- mapping, you can use the <literal>resultClass</literal> attribute
- instead of <literal>resultSetMapping</literal>:</para>
-
- <programlisting><emphasis
role="bold">@NamedNativeQuery(name="implicitSample",
query="select * from SpaceShip",
- resultClass=SpaceShip.class)</emphasis>
-public class SpaceShip {</programlisting>
-
- <para>In some of your native queries, you'll have to return scalar
- values, for example when building report queries. You can map them in
- the <literal>@SqlResultsetMapping</literal> through
- <literal>@ColumnResult</literal>. You actually can even mix, entities
- and scalar returns in the same native query (this is probably not that
- common though).</para>
-
- <programlisting><emphasis
role="bold">@SqlResultSetMapping(name="scalar",
columns=@ColumnResult(name="dimension"))
-@NamedNativeQuery(name="scalar", query="select length*width as dimension
from SpaceShip",
resultSetMapping="scalar")</emphasis></programlisting>
-
- <para>An other query hint specific to native queries has been
- introduced: <literal>org.hibernate.callable</literal> which can be
true
- or false depending on whether the query is a stored procedure or
- not.</para>
- </sect2>
- </sect1>
-
- <sect1 id="entity-hibspec" xreflabel="Hibernate Annotation
Extensions">
- <title>Hibernate Annotation Extensions</title>
-
- <para>Hibernate 3.1 offers a variety of additional annotations that you
- can mix/match with your EJB 3 entities. They have been designed as a
- natural extension of EJB3 annotations.</para>
-
- <para>To empower the EJB3 capabilities, hibernate provides specific
- annotations that match hibernate features. The
- <classname>org.hibernate.annotations</classname> package contains all
- these annotations extensions.</para>
-
- <sect2 id="entity-hibspec-entity" revision="2">
- <title>Entity</title>
-
- <para>You can fine tune some of the actions done by Hibernate on
- entities beyond what the EJB3 spec offers.</para>
-
- <para><classname>(a)org.hibernate.annotations.Entity</classname>
adds
- additional metadata that may be needed beyond what is defined in the
- standard <literal>@Entity</literal> <itemizedlist>
- <listitem>
- mutable: whether this entity is mutable or not
- </listitem>
-
- <listitem>
- dynamicInsert: allow dynamic SQL for inserts
- </listitem>
-
- <listitem>
- dynamicUpdate: allow dynamic SQL for updates
- </listitem>
-
- <listitem>
- selectBeforeUpdate: Specifies that Hibernate should never perform an SQL
UPDATE unless it is certain that an object is actually modified.
- </listitem>
-
- <listitem>
- polymorphism: whether the entity polymorphism is of
PolymorphismType.IMPLICIT (default) or PolymorphismType.EXPLICIT
- </listitem>
-
- <listitem>
- persister: allow the overriding of the default persister implementation
- </listitem>
-
- <listitem>
- optimisticLock: optimistic locking strategy (OptimisticLockType.VERSION,
OptimisticLockType.NONE, OptimisticLockType.DIRTY or OptimisticLockType.ALL)
- </listitem>
- </itemizedlist></para>
-
- <para><note>
- <para>(a)javax.persistence.Entity is still mandatory,
- @org.hibernate.annotations.Entity is not a replacement.</para>
- </note></para>
-
- <para>Here are some additional Hibernate annotation extensions</para>
-
- <para><literal>(a)org.hibernate.annotations.BatchSize</literal>
allows you
- to define the batch size when fetching instances of this entity ( eg.
- <literal>@BatchSize(size=4)</literal> ). When loading a given entity,
- Hibernate will then load all the uninitialized entities of the same type
- in the persistence context up to the batch size.</para>
-
- <para><literal>(a)org.hibernate.annotations.Proxy</literal> defines
the
- laziness attributes of the entity. lazy (default to true) define whether
- the class is lazy or not. proxyClassName is the interface used to
- generate the proxy (default is the class itself).</para>
-
- <para><literal>(a)org.hibernate.annotations.Where</literal> defines
an
- optional SQL WHERE clause used when instances of this class is
- retrieved.</para>
-
- <para><literal>(a)org.hibernate.annotations.Check</literal> defines
an
- optional check constraints defined in the DDL statetement.</para>
-
- <para><literal>(a)OnDelete(action=OnDeleteAction.CASCADE)</literal>
on
- joined subclasses: use a SQL cascade delete on deletion instead of the
- regular Hibernate mechanism.</para>
-
- <para><literal>@Table(appliesTo="tableName", indexes = {
- @Index(name="index1", columnNames={"column1",
"column2"} ) } )</literal>
- creates the defined indexes on the columns of table
- <literal>tableName</literal>. This can be applied on the primary table
- or any secondary table. The <literal>@Tables</literal> annotation
allows
- your to apply indexes on different tables. This annotation is expected
- where <literal>(a)javax.persistence.Table</literal> or
- <literal>(a)javax.persistence.SecondaryTable</literal>(s)
occurs.</para>
-
- <note>
- <para><literal>(a)org.hibernate.annotations.Table</literal> is a
- complement, not a replacement to
- <literal>(a)javax.persistence.Table</literal>. Especially, if you want
- to change the default name of a table, you must use
- <literal>(a)javax.persistence.Table</literal>, not
- <literal>(a)org.hibernate.annotations.Table</literal>.</para>
- </note>
-
- <para><programlisting>@Entity
-@BatchSize(size=5)
-(a)org.hibernate.annotations.Entity(
- selectBeforeUpdate = true,
- dynamicInsert = true, dynamicUpdate = true,
- optimisticLock = OptimisticLockType.ALL,
- polymorphism = PolymorphismType.EXPLICIT)
-@Where(clause="1=1")
-(a)org.hibernate.annotations.Table(name="Forest", indexes = {
@Index(name="idx", columnNames = { "name", "length" } ) } )
-public class Forest { ... }</programlisting><programlisting>@Entity
-@Inheritance(
- strategy=InheritanceType.JOINED
-)
-public class Vegetable { ... }
-
-@Entity
-(a)OnDelete(action=OnDeleteAction.CASCADE)
-public class Carrot extends Vegetable { ... }</programlisting></para>
- </sect2>
-
- <sect2 id="entity-hibspec-identifier" label="Identifier"
revision="1">
- <title>Identifier</title>
-
-
<para><literal><literal>(a)org.hibernate.annotations.GenericGenerator</literal>
- allows you to define an Hibernate specific id
- generator.</literal></para>
-
- <para><programlisting>@Id
@GeneratedValue(generator="system-uuid")
-@GenericGenerator(name="system-uuid", strategy = "uuid")
-public String getId() {
-
-@Id @GeneratedValue(generator="hibseq")
-@GenericGenerator(name="hibseq", strategy = "seqhilo",
- parameters = {
- @Parameter(name="max_lo", value = "5"),
- @Parameter(name="sequence", value="heybabyhey")
- }
-)
-public Integer getId() {</programlisting></para>
-
- <para><literal>strategy</literal> is the short name of an
Hibernate3
- generator strategy or the fully qualified class name of an
- <classname>IdentifierGenerator</classname> implementation. You can add
- some parameters through the <literal>parameters</literal>
- attribute.</para>
-
- <para>Contrary to its standard counterpart,
- <literal>@GenericGenerator</literal> can be used in package level
- annotations, making it an application level generator (just like if it
- were in a JPA XML file).</para>
-
- <programlisting>@GenericGenerator(name="hibseq", strategy =
"seqhilo",
- parameters = {
- @Parameter(name="max_lo", value = "5"),
- @Parameter(name="sequence", value="heybabyhey")
- }
-)
-package org.hibernate.test.model</programlisting>
- </sect2>
-
- <sect2 id="entity-hibspec-property" revision="2">
- <title>Property</title>
-
- <sect3>
- <title>Access type</title>
-
- <para>The access type is guessed from the position of
- <literal>@Id</literal> or <literal>@EmbeddedId</literal>
in the entity
- hierarchy. Sub-entities, embedded objects and mapped superclass
- inherit the access type from the root entity.</para>
-
- <para>In Hibernate, you can override the access type to:</para>
-
- <itemizedlist>
- <listitem>
- <para>use a custom access type strategy</para>
- </listitem>
-
- <listitem>
- <para>fine tune the access type at the class level or at the
- property level</para>
- </listitem>
- </itemizedlist>
-
- <para>An @AccessType annotation has been introduced to support this
- behavior. You can define the access type on</para>
-
- <itemizedlist>
- <listitem>
- <para>an entity</para>
- </listitem>
-
- <listitem>
- <para>a superclass</para>
- </listitem>
-
- <listitem>
- <para>an embeddable object</para>
- </listitem>
-
- <listitem>
- <para>a property</para>
- </listitem>
- </itemizedlist>
-
- <para>The access type is overriden for the annotated element, if
- overriden on a class, all the properties of the given class inherit
- the access type. For root entities, the access type is considered to
- be the default one for the whole hierarchy (overridable at class or
- property level).</para>
-
- <para>If the access type is marked as "property", the getters
are
- scanned for annotations, if the access type is marked as "field", the
- fields are scanned for annotations. Otherwise the elements marked with
- @Id or @embeddedId are scanned.</para>
-
- <para>You can override an access type for a property, but the element
- to annotate will not be influenced: for example an entity having
- access type <literal>field</literal>, can annotate a field with
- <literal>@AccessType("property")</literal>, the access type
will then
- be property for this attribute, the the annotations still have to be
- carried on the field.</para>
-
- <para>If a superclass or an embeddable object is not annotated, the
- root entity access type is used (even if an access type has been
- define on an intermediate superclass or embeddable object). The
- russian doll principle does not apply.</para>
-
- <programlisting>@Entity
-public class Person implements Serializable {
- @Id @GeneratedValue //access type field
- Integer id;
-
- @Embedded
- @AttributeOverrides({
- @AttributeOverride(name = "iso2", column = @Column(name =
"bornIso2")),
- @AttributeOverride(name = "name", column = @Column(name =
"bornCountryName"))
- })
- Country bornIn;
-}
-
-@Embeddable
-<emphasis role="bold">@AccessType("property")</emphasis>
//override access type for all properties in Country
-public class Country implements Serializable {
- private String iso2;
- private String name;
-
- public String getIso2() {
- return iso2;
- }
-
- public void setIso2(String iso2) {
- this.iso2 = iso2;
- }
-
- @Column(name = "countryName")
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-}
-</programlisting>
- </sect3>
-
- <sect3>
- <title>Formula</title>
-
- <para>Sometimes, you want the Database to do some computation for you
- rather than in the JVM, you might also create some kind of virtual
- column. You can use a SQL fragment (aka formula) instead of mapping a
- property into a column. This kind of property is read only (its value
- is calculated by your formula fragment).</para>
-
- <programlisting>@Formula("obj_length * obj_height * obj_width")
-public long getObjectVolume()</programlisting>
-
- <para>The SQL fragment can be as complex as you want avec even include
- subselects.</para>
- </sect3>
-
- <sect3>
- <title>Type</title>
-
- <para><literal>(a)org.hibernate.annotations.Type</literal>
overrides the
- default hibernate type used: this is generally not necessary since the
- type is correctly inferred by Hibernate. Please refer to the Hibernate
- reference guide for more informations on the Hibernate types.</para>
-
- <para><literal>(a)org.hibernate.annotations.TypeDef</literal>
and
- <literal>(a)org.hibernate.annotations.TypeDefs</literal> allows you to
- declare type definitions. These annotations are placed at the class or
- package level. Note that these definitions will be global for the
- session factory (even at the class level) and that type definition has
- to be defined before any usage.</para>
-
- <programlisting>@TypeDefs(
- {
- @TypeDef(
- name="caster",
- typeClass = CasterStringType.class,
- parameters = {
- @Parameter(name="cast", value="lower")
- }
- )
- }
-)
-package org.hibernate.test.annotations.entity;
-
-...
-public class Forest {
- @Type(type="caster")
- public String getSmallText() {
- ...
-}
- </programlisting>
-
- <para>When using composite user type, you will have to express column
- definitions. The <literal>@Columns</literal> has been introduced for
- that purpose.</para>
-
-
<programlisting>(a)Type(type="org.hibernate.test.annotations.entity.MonetaryAmountUserType")
-@Columns(columns = {
- @Column(name="r_amount"),
- @Column(name="r_currency")
-})
-public MonetaryAmount getAmount() {
- return amount;
-}
-
-
-public class MonetaryAmount implements Serializable {
- private BigDecimal amount;
- private Currency currency;
- ...
-}</programlisting>
- </sect3>
-
- <sect3>
- <title>Index</title>
-
- <para>You can define an index on a particular column using the
- <literal>@Index</literal> annotation on a one column property, the
- columnNames attribute will then be ignored</para>
-
- <programlisting>@Column(secondaryTable="Cat1")
-@Index(name="story1index")
-public String getStoryPart1() {
- return storyPart1;
-}</programlisting>
- </sect3>
-
- <sect3>
- <title>@Parent</title>
-
- <para>When inside an embeddable object, you can define one of the
- properties as a pointer back to the owner element.</para>
-
- <programlisting>@Entity
-public class Person {
- @Embeddable public Address address;
- ...
-}
-
-@Embeddable
-public class Address {
- @Parent public Person owner;
- ...
-}
-
-
-person == person.address.owner</programlisting>
- </sect3>
-
- <sect3>
- <title>Generated properties</title>
-
- <para>Some properties are generated at insert or update time by your
- database. Hibernate can deal with such properties and triggers a
- subsequent select to read these properties.</para>
-
- <programlisting>@Entity
-public class Antenna {
- @Id public Integer id;
- @Generated(GenerationTime.ALWAYS) @Column(insertable = false, updatable = false)
- public String longitude;
-
- @Generated(GenerationTime.INSERT) @Column(insertable = false)
- public String latitude;
-}</programlisting>
-
- <para>Annotate your property as <literal>@Generated</literal>
You have
- to make sure your insertability or updatability does not conflict with
- the generation strategy you have chosen. When GenerationTime.INSERT is
- chosen, the property must not contains insertable columns, when
- GenerationTime.ALWAYS is chosen, the property must not contains
- insertable nor updatable columns.</para>
-
- <para><literal>@Version</literal> properties cannot be
- <literal>@Generated(INSERT)</literal> by design, it has to be either
- <literal>NEVER</literal> or
<literal>ALWAYS</literal>.</para>
- </sect3>
-
- <sect3>
- <title>@Target</title>
-
- <para>Sometimes, the type guessed by reflection is not the one you
- want Hibernate to use. This is especially true on components when an
- interface is used. You can use <literal>@Target</literal> to by pass
- the reflection guessing mechanism (very much like the
- <literal>targetEntity</literal> attribute available on
- associations.</para>
-
- <programlisting> @Embedded
- <emphasis role="bold">(a)Target(OwnerImpl.class)</emphasis>
- public Owner getOwner() {
- return owner;
- }</programlisting>
-
- <para></para>
- </sect3>
- </sect2>
-
- <sect2 id="entity-hibspec-inheritance" revision="1">
- <title>Inheritance</title>
-
- <para>SINGLE_TABLE is a very powerful strategy but sometimes, and
- especially for legacy systems, you cannot add an additional
- discriminator column. For that purpose Hibernate has introduced the
- notion of discriminator formula:
- <literal>@DiscriminatorFormula</literal> is a replacement of
- <literal>@DiscriminatorColumn</literal> and use a SQL fragment as a
- formula for discriminator resolution (no need to have a dedicated
- column).</para>
-
- <programlisting>@Entity
-@DiscriminatorForumla("case when forest_type is null then 0 else forest_type
end")
-public class Forest { ... }</programlisting>
-
- <para>By default, when querying the top entities, Hibernate does not put
- a restriction clause on the discriminator column. This can be
- inconvenient if this column contains values not mapped in your hierarchy
- (through <literal>@DiscriminatorValue</literal>). To work around that
- you can use <literal>@ForceDiscriminator</literal> (at the class
level,
- next to <literal>@DiscriminatorColumn</literal>). Hibernate will then
- list the available values when loading the entities.</para>
- </sect2>
-
- <sect2 id="entity-hibspec-singleassoc">
- <title>Single Association related annotations</title>
-
- <para>By default, when Hibernate cannot resolve the association because
- the expected associated element is not in database (wrong id on the
- association column), an exception is raised by Hibernate. This might be
- inconvenient for lecacy and badly maintained schemas. You can ask
- Hibernate to ignore such elements instead of raising an exception using
- the <literal>@NotFound</literal> annotation. This annotation can be
used
- on a <literal>@OneToOne</literal> (with FK),
- <literal>@ManyToOne</literal>,
<literal>@OneToMany</literal> or
- <literal>@ManyToMany</literal> association.</para>
-
- <programlisting>@Entity
-public class Child {
- ...
- @ManyToOne
- @NotFound(action=NotFoundAction.IGNORE)
- public Parent getParent() { ... }
- ...
-}</programlisting>
-
- <para>Sometimes you want to delegate to your database the deletion of
- cascade when a given entity is deleted.</para>
-
- <programlisting>@Entity
-public class Child {
- ...
- @ManyToOne
- @OnDelete(action=OnDeleteAction.CASCADE)
- public Parent getParent() { ... }
- ...
-}</programlisting>
-
- <para>In this case Hibernate generates a cascade delete constraint at
- the database level.</para>
-
- <para>Foreign key constraints, while generated by Hibernate, have a
- fairly unreadable name. You can override the constraint name by use
- <literal>(a)ForeignKey</literal>.</para>
-
- <programlisting>@Entity
-public class Child {
- ...
- @ManyToOne
- <emphasis
role="bold">@ForeignKey(name="FK_PARENT")</emphasis>
- public Parent getParent() { ... }
- ...
-}
-
-alter table Child add constraint FK_PARENT foreign key (parent_id) references
Parent</programlisting>
-
- <sect3 id="entity-hibspec-singleassoc-fetching"
- label="Lazy options and fetching modes">
- <title>Lazy options and fetching modes</title>
-
- <para>EJB3 comes with the <literal>fetch</literal> option to
define
- lazy loading and fetching modes, however Hibernate has a much more
- option set in this area. To fine tune the lazy loading and fetching
- strategies, some additional annotations have been introduced:</para>
-
- <itemizedlist>
- <listitem>
- <para><literal>@LazyToOne</literal>: defines the lazyness
option
- on <literal>@ManyToOne</literal> and
<literal>@OneToOne</literal>
- associations. <literal>LazyToOneOption</literal> can be
- <literal>PROXY</literal> (ie use a proxy based lazy loading),
- <literal>NO_PROXY</literal> (use a bytecode enhancement based
lazy
- loading - note that build time bytecode processing is necessary)
- and <literal>FALSE</literal> (association not lazy)</para>
- </listitem>
-
- <listitem>
- <para><literal>@LazyCollection</literal>: defines the
lazyness
- option on <literal>@ManyTo</literal>Many and
- <literal>@OneToMany</literal> associations. LazyCollectionOption
- can be <literal>TRUE</literal> (the collection is lazy and will
be
- loaded when its state is accessed), <literal>EXTRA</literal>
(the
- collection is lazy and all operations will try to avoid the
- collection loading, this is especially useful for huge collections
- when loading all the elements is not necessary) and FALSE
- (association not lazy)</para>
- </listitem>
-
- <listitem>
- <para><literal>@Fetch</literal>: defines the fetching
strategy
- used to load the association. <literal>FetchMode</literal> can
be
- <literal>SELECT</literal> (a select is triggered when the
- association needs to be loaded), <literal>SUBSELECT</literal>
- (only available for collections, use a subselect strategy - please
- refers to the Hibernate Reference Documentation for more
- information) or <literal>JOIN</literal> (use a SQL JOIN to load
- the association while loading the owner entity).
- <literal>JOIN</literal> overrides any lazy attribute (an
- association loaded through a <literal>JOIN</literal> strategy
- cannot be lazy).</para>
- </listitem>
- </itemizedlist>
-
- <para>The Hibernate annotations overrides the EJB3 fetching
- options.</para>
-
- <table>
- <title>Lazy and fetch options equivalent</title>
-
- <tgroup cols="3">
- <thead>
- <row>
- <entry>Annotations</entry>
-
- <entry>Lazy</entry>
-
- <entry>Fetch</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>(a)[One|Many]ToOne](fetch=FetchType.LAZY)</entry>
-
- <entry>@LazyToOne(PROXY)</entry>
-
- <entry>@Fetch(SELECT)</entry>
- </row>
-
- <row>
- <entry>(a)[One|Many]ToOne](fetch=FetchType.EAGER)</entry>
-
- <entry>@LazyToOne(FALSE)</entry>
-
- <entry>@Fetch(JOIN)</entry>
- </row>
-
- <row>
- <entry>(a)ManyTo[One|Many](fetch=FetchType.LAZY)</entry>
-
- <entry>@LazyCollection(TRUE)</entry>
-
- <entry>@Fetch(SELECT)</entry>
- </row>
-
- <row>
- <entry>(a)ManyTo[One|Many](fetch=FetchType.EAGER)</entry>
-
- <entry>@LazyCollection(FALSE)</entry>
-
- <entry>@Fetch(JOIN)</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect3>
- </sect2>
-
- <sect2 id="entity-hibspec-collection" revision="2">
- <title>Collection related annotations</title>
-
- <sect3 id="entity-hibspec-collection-enhance"
revision="2">
- <title>Enhance collection settings</title>
-
- <para>It is possible to set <itemizedlist>
- <listitem>
- the batch size for collections using @BatchSize
- </listitem>
-
- <listitem>
- the where clause, using @Where (applied on the target entity) or
@WhereJoinTable (applied on the association table)
- </listitem>
-
- <listitem>
- the check clause, using @Check
- </listitem>
-
- <listitem>
- the SQL order by clause, using @OrderBy
- </listitem>
-
- <listitem>
- the delete cascade strategy through
@OnDelete(action=OnDeleteAction.CASCADE)
- </listitem>
- </itemizedlist></para>
-
- <para>You can also declare a sort comparator. Use the
- <literal>@Sort</literal> annotation. Expressing the comparator type
- you want between unsorted, natural or custom comparator. If you want
- to use your own comparator implementation, you'll also have to express
- the implementation class using the <literal>comparator</literal>
- attribute. Note that you need to use either a
- <classname>SortedSet</classname> or a
<classname>SortedMap</classname>
- interface.</para>
-
- <programlisting> @OneToMany(cascade=CascadeType.ALL,
fetch=FetchType.EAGER)
- @JoinColumn(name="CUST_ID")
- @Sort(type = SortType.COMPARATOR, comparator = TicketComparator.class)
- @Where(clause="1=1")
- @OnDelete(action=OnDeleteAction.CASCADE)
- public SortedSet<Ticket> getTickets() {
- return tickets;
- }</programlisting>
-
- <para>Please refer to the previous descriptions of these annotations
- for more informations.</para>
-
- <para>Foreign key constraints, while generated by Hibernate, have a
- fairly unreadable name. You can override the constraint name by use
- <literal>@ForeignKey</literal>. Note that this annotation has to be
- placed on the owning side of the relationship,
- <literal>inverseName</literal> referencing to the other side
- constraint.</para>
-
- <programlisting>@Entity
-public class Woman {
- ...
- @ManyToMany(cascade = {CascadeType.ALL})
- <emphasis role="bold">@ForeignKey(name = "TO_WOMAN_FK",
inverseName = "TO_MAN_FK")</emphasis>
- public Set<Man> getMens() {
- return mens;
- }
-}
-
-alter table Man_Woman add constraint TO_WOMAN_FK foreign key (woman_id) references Woman
-alter table Man_Woman add constraint TO_MAN_FK foreign key (man_id) references
Man</programlisting>
- </sect3>
-
- <sect3 id="entity-hibspec-collection-extratype"
revision="1">
- <title>Extra collection types</title>
-
- <sect4>
- <title>List</title>
-
- <para>Beyond EJB3, Hibernate Annotations supports true
- <classname>List</classname> and
<classname>Array</classname>. Map
- your collection the same way as usual and add the
- @<literal>IndexColumn</literal>. This annotation allows you to
- describe the column that will hold the index. You can also declare
- the index value in DB that represent the first element (aka as base
- index). The usual value is <literal>0</literal> or
- <literal>1</literal>.</para>
-
- <programlisting>@OneToMany(cascade = CascadeType.ALL)
-@IndexColumn(name = "drawer_position", base=1)
-public List<Drawer> getDrawers() {
- return drawers;
-}</programlisting>
-
- <note>
- <para>If you forgot to set <literal>@IndexColumn</literal>,
the
- bag semantic is applied. If you want the bag semantic without the
- limitations of it, consider using
- <literal>(a)CollectionId</literal>.</para>
- </note>
- </sect4>
-
- <sect4 id="entity-hibspec-collection-extratype-map"
revision="1">
- <title>Map</title>
-
- <para>Hibernate Annotations also supports true Map mappings, if
- <literal>(a)javax.persistence.MapKey</literal> is not set, hibernate
- will map the key element or embeddable object in its/their own
- columns. To overrides the default columns, you can use
- <literal>(a)org.hibernate.annotations.MapKey</literal> if your key
is
- a basic type (defaulted to <literal>mapkey</literal>) or an
- embeddable object, or you can use
- <literal>(a)org.hibernate.annotations.MapKeyManyToMany</literal> if
- your key is an entity.</para>
-
- <para>Both
<literal>(a)org.hibernate.annotations.MapKey</literal> and
- <literal>(a)org.hibernate.annotations.MapKeyManyToMany</literal>
- allows you to override the target element to be used. This is
- especially useful if your collection does not use generics (or if
- you use interfaces).</para>
-
- <programlisting> @CollectionOfElements(targetElement =
SizeImpl.class)
- @MapKeyManyToMany(<emphasis role="bold">targetEntity =
LuggageImpl.class</emphasis>)
- private Map<Luggage, Size> sizePerLuggage = new HashMap<Luggage,
Size>();</programlisting>
-
- <para></para>
- </sect4>
-
- <sect4 id="entity-hibspec-collection-extratype-indexbidir">
- <title>Bidirectional association with indexed collections</title>
-
- <para>A bidirectional association where one end is represented as a
- <literal>@IndexColumn</literal> or
- <literal>(a)org.hibernate.annotations.MapKey[ManyToMany]</literal>
- requires special consideration. If there is a property of the child
- class which maps to the index column, no problem, we can continue
- using <literal>mappedBy</literal> on the collection
mapping:</para>
-
- <programlisting>@Entity
-public class Parent {
- @OneToMany(mappedBy="parent")
- @org.hibernate.annotations.MapKey(columns=@Column(name="name"))
- private Map<String, Child> children;
- ...
-}
-
-@Entity
-public class Parent {
- ...
- @Basic
- private String name;
-
- @ManyToOne
- @JoinColumn(name="parent_id", nullable=false)
- private Parent parent;
- ...
-}</programlisting>
-
- <para>But, if there is no such property on the child class, we can't
- think of the association as truly bidirectional (there is
- information available at one end of the association that is not
- available at the other end). In this case, we can't map the
- collection <literal>mappedBy</literal>. Instead, we could use the
- following mapping:</para>
-
- <programlisting>@Entity
-public class Parent {
- @OneToMany
- @org.hibernate.annotations.MapKey(columns=@Column(name="name"))
- @JoinColumn(name="parent_id", nullable=false)
- private Map<String, Child> children;
- ...
-}
-
-@Entity
-public class Parent {
- ...
- @ManyToOne
- @JoinColumn(name="parent_id", insertable=false, updatable=false,
nullable=false)
- private Parent parent;
- ...
-}</programlisting>
-
- <para>Note that in this mapping, the collection-valued end of the
- association is responsible for updates to the foreign key.</para>
- </sect4>
-
- <sect4>
- <title>Bag with primary key</title>
-
- <para>Another interesting feature is the ability to define a
- surrogate primary key to a bag collection. This remove pretty much
- all of the drawbacks of bags: update and removal are efficient, more
- than one <literal>EAGER</literal> bag per query or per entity.
This
- primary key will be contained in a additional column of your
- collection table but will not be visible to the Java application.
- @CollectionId is used to mark a collection as id bag, it also allow
- to override the primary key column(s), the primary key type and the
- generator strategy. The strategy can be
<literal>identity</literal>,
- or any defined generator name of your application.</para>
-
- <programlisting>@Entity
-@TableGenerator(name="ids_generator", table="IDS")
-public class Passport {
- ...
-
- @ManyToMany(cascade = CascadeType.ALL)
- @JoinTable(name="PASSPORT_VISASTAMP")
- <emphasis role="bold">@CollectionId(
- columns = @Column(name="COLLECTION_ID"),
- type=@Type(type="long"),
- generator = "ids_generator"
- )</emphasis>
- private Collection<Stamp> visaStamp = new ArrayList();
- ...
-}</programlisting>
- </sect4>
-
- <sect4>
- <title>Collection of element or composite elements</title>
-
- <para>Hibernate Annotations also supports collections of core types
- (Integer, String, Enums, ...), collections of embeddable objects and
- even arrays of primitive types. This is known as collection of
- elements.</para>
-
- <para>A collection of elements has to be annotated as
- <literal>@CollectionOfElements</literal> (as a replacement of
- <literal>@OneToMany</literal>) To define the collection table, the
- <literal>@JoinTable</literal> annotation is used on the
association
- property, <literal>joinColumns</literal> defines the join columns
- between the entity primary table and the collection table
- (inverseJoincolumn is useless and should be left empty). For
- collection of core types or array of primitive types, you can
- override the element column definition using a
- <literal>@Column</literal> on the association property. You can
also
- override the columns of a collection of embeddable object using
- <literal>@AttributeOverride</literal>. To reach the collection
- element, you need to append "element" to the attribute override name
- (eg "element" for core types, or "element.serial" for the
serial
- property of an embeddable element). To reach the index/key of a
- collection, append "key" instead.</para>
-
- <programlisting>@Entity
-public class Boy {
- private Integer id;
- private Set<String> nickNames = new HashSet<String>();
- private int[] favoriteNumbers;
- private Set<Toy> favoriteToys = new HashSet<Toy>();
- private Set<Character> characters = new
HashSet<Character>();
-
- @Id @GeneratedValue
- public Integer getId() {
- return id;
- }
-
- <emphasis role="bold">@CollectionOfElements
- public Set<String></emphasis> getNickNames() {
- return nickNames;
- }
-
- <emphasis role="bold">@CollectionOfElements
- @JoinTable(
- table=@Table(name="BoyFavoriteNumbers"),
- joinColumns = @JoinColumn(name="BoyId")
- )
- @Column(name="favoriteNumber", nullable=false)</emphasis>
- @IndexColumn(name="nbr_index")
- public int[] getFavoriteNumbers() {
- return favoriteNumbers;
- }
-
- <emphasis role="bold">@CollectionOfElements
- @AttributeOverride( name="element.serial",
column=@Column(name="serial_nbr") )</emphasis>
- public Set<Toy> getFavoriteToys() {
- return favoriteToys;
- }
-
- <emphasis role="bold">@CollectionOfElements
- public Set<Character></emphasis> getCharacters() {
- return characters;
- }
- ...
-}
-
-public enum Character {
- GENTLE,
- NORMAL,
- AGGRESSIVE,
- ATTENTIVE,
- VIOLENT,
- CRAFTY
-}
-
-@Embeddable
-public class Toy {
- public String name;
- public String serial;
- public Boy owner;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getSerial() {
- return serial;
- }
-
- public void setSerial(String serial) {
- this.serial = serial;
- }
-
- <emphasis role="bold">@Parent</emphasis>
- public Boy getOwner() {
- return owner;
- }
-
- public void setOwner(Boy owner) {
- this.owner = owner;
- }
-
- public boolean equals(Object o) {
- if ( this == o ) return true;
- if ( o == null || getClass() != o.getClass() ) return false;
-
- final Toy toy = (Toy) o;
-
- if ( !name.equals( toy.name ) ) return false;
- if ( !serial.equals( toy.serial ) ) return false;
-
- return true;
- }
-
- public int hashCode() {
- int result;
- result = name.hashCode();
- result = 29 * result + serial.hashCode();
- return result;
- }
-}</programlisting>
-
- <para>On a collection of embeddable objects, the embeddable object
- can have a property annotated with <literal>@Parent</literal>.
This
- property will then point back to the entity containing the
- collection.</para>
-
- <note>
- <para>Previous versions of Hibernate Annotations used the
- <literal>@OneToMany</literal> to mark a collection of elements.
- Due to semantic inconsistencies, we've introduced the annotation
- <literal>@CollectionOfElements</literal>. Marking collections of
- elements the old way still work but is considered deprecated and
- is going to be unsupported in future releases</para>
- </note>
- </sect4>
- </sect3>
- </sect2>
-
- <sect2>
- <title>Cache</title>
-
- <para>In order to optimize your database accesses, you can activave the
- so called second level cache of Hibernate. This cache is configurable on
- a per entity and per collection basis.</para>
-
- <para><literal>(a)org.hibernate.annotations.Cache</literal> defines
the
- caching strategy and region of a given second level cache. This
- annotation can be applied on the root entity (not the sub entities), and
- on the collections.</para>
-
- <programlisting>@Entity
-@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
-public class Forest { ... }</programlisting>
-
- <programlisting> @OneToMany(cascade=CascadeType.ALL,
fetch=FetchType.EAGER)
- @JoinColumn(name="CUST_ID")
- @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
- public SortedSet<Ticket> getTickets() {
- return tickets;
- }</programlisting>
-
- <para></para>
-
- <programlistingco>
- <areaspec>
- <area coords="2 55" id="hm1" />
-
- <area coords="3 55" id="hm2" />
-
- <area coords="4 55" id="hm3" />
- </areaspec>
-
- <programlisting>@Cache(
- CacheConcurrencyStrategy usage();
- String region() default "";
- String include() default "all";
-)</programlisting>
-
- <calloutlist>
- <callout arearefs="hm1">
- <para>usage: the given cache concurrency strategy (NONE,
- READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL)</para>
- </callout>
-
- <callout arearefs="hm2">
- <para>region (optional): the cache region (default to the fqcn of
- the class or the fq role name of the collection)</para>
- </callout>
-
- <callout arearefs="hm3">
- <para><literal>include</literal> (optional): all to include
all
- properties, non-lazy to only include non lazy properties (default
- all).</para>
- </callout>
- </calloutlist>
- </programlistingco>
- </sect2>
-
- <sect2 id="entity-hibspec-filters">
- <title>Filters</title>
-
- <para>Hibernate has the ability to apply arbitrary filters on top of
- your data. Those filters are applied at runtime on a given session.
- First, you need to define them.</para>
-
- <para><literal>(a)org.hibernate.annotations.FilterDef</literal> or
- <literal>@FilterDefs</literal> define filter definition(s) used by
- filter(s) using the same name. A filter definition has a name() and an
- array of parameters(). A parameter will allow you to adjust the behavior
- of the filter at runtime. Each parameter is defined by a
- <literal>@ParamDef</literal> which has a name and a type. You can also
- define a defaultCondition() parameter for a given
- <literal>@FilterDef</literal> to set the default condition to use when
- none are defined in each individual <literal>@Filter</literal>. A
- <literal>@FilterDef</literal>(s) can be defined at the class or
package
- level.</para>
-
- <para>We now need to define the SQL filter clause applied to either the
- entity load or the collection load. <literal>@Filter</literal> is used
- and placed either on the entity or the collection element</para>
-
- <para><programlisting>@Entity
-@FilterDef(name="minLength", parameters={ @ParamDef(
name="minLength", type="integer" ) } )
-@Filters( {
- @Filter(name="betweenLength", condition=":minLength <= length
and :maxLength >= length"),
- @Filter(name="minLength", condition=":minLength <=
length")
-} )
-public class Forest { ... }</programlisting></para>
-
- <para>When the collection use an association table as a relational
- representation, you might want to apply the filter condition to the
- association table itself or to the target entity table. To apply the
- constraint on the target entity, use the regular
- <literal>@Filter</literal> annotation. However, if you wan to target
the
- association table, use the <literal>@FilterJoinTable</literal>
- annotation.</para>
-
- <programlisting> @OneToMany
- @JoinTable
- //filter on the target entity table
- @Filter(name="betweenLength", condition=":minLength <= length
and :maxLength >= length")
- //filter on the association table
- @FilterJoinTable(name="security", condition=":userlevel >=
requredLevel")
- public Set<Forest> getForests() { ... }</programlisting>
- </sect2>
-
- <sect2 id="entity-hibspec-query">
- <title>Queries</title>
-
- <para>Since Hibernate has more features on named queries than the one
- defined in the EJB3 specification,
- <literal>(a)org.hibernate.annotations.NamedQuery</literal>,
- <literal>(a)org.hibernate.annotations.NamedQueries</literal>,
- <literal>(a)org.hibernate.annotations.NamedNativeQuery</literal> and
- <literal>(a)org.hibernate.annotations.NamedNativeQueries</literal> have
- been introduced. They add some attributes to the standard version and
- can be used as a replacement:</para>
-
- <itemizedlist>
- <listitem>
- <para>flushMode: define the query flush mode (Always, Auto, Commit
- or Never)</para>
- </listitem>
-
- <listitem>
- <para>cacheable: whether the query should be cached or not</para>
- </listitem>
-
- <listitem>
- <para>cacheRegion: cache region used if the query is cached</para>
- </listitem>
-
- <listitem>
- <para>fetchSize: JDBC statement fetch size for this query</para>
- </listitem>
-
- <listitem>
- <para>timeout: query time out</para>
- </listitem>
-
- <listitem>
- <para>callable: for native queries only, to be set to true for
- stored procedures</para>
- </listitem>
-
- <listitem>
- <para>comment: if comments are activated, the comment seen when the
- query is sent to the database.</para>
- </listitem>
-
- <listitem>
- <para>cacheMode: Cache interaction mode (get, ignore, normal, put or
- refresh)</para>
- </listitem>
-
- <listitem>
- <para>readOnly: whether or not the elements retrievent from the
- query are in read only mode.</para>
- </listitem>
- </itemizedlist>
-
- <para>Those hints can be set in a standard
- <literal>(a)javax.persistence.NamedQuery</literal> annotations through
the
- detyped <literal>@QueryHint</literal>. Another key advantage is the
- ability to set those annotations at a package level.</para>
- </sect2>
-
- <sect2 id="entity-hibspec-customsql">
- <title>Custom SQL for CRUD operations</title>
-
- <para>Hibernate gives you the avility to override every single SQL
- statement generated. We have seen native SQL query usage already, but
- you can also override the SQL statement used to load or change the state
- of entities.</para>
-
- <programlisting>@Entity
-@Table(name="CHAOS")
-<emphasis role="bold">@SQLInsert( sql="INSERT INTO CHAOS(size, name,
nickname, id) VALUES(?,upper(?),?,?)")
-@SQLUpdate( sql="UPDATE CHAOS SET size = ?, name = upper(?), nickname = ? WHERE id =
?")
-@SQLDelete( sql="DELETE CHAOS WHERE id = ?")
-@SQLDeleteAll( sql="DELETE CHAOS")
-</emphasis><emphasis role="bold">@Loader(namedQuery =
"chaos")</emphasis>
-@NamedNativeQuery(name="chaos", query="select id, size, name, lower(
nickname ) as nickname from CHAOS where id= ?", resultClass = Chaos.class)
-public class Chaos {
- @Id
- private Long id;
- private Long size;
- private String name;
- private String nickname;</programlisting>
-
- <para><literal>@SQLInsert</literal>,
<literal>@SQLUpdate</literal>,
- <literal>@SQLDelete</literal>,
<literal>@SQLDeleteAll</literal>
- respectively override the INSERT statement, UPDATE statement, DELETE
- statement, DELETE statement to remove all entities.</para>
-
- <para>If you expect to call a store procedure, be sure to set the
- <literal>callable</literal> attribute to true
- (<literal>@SQLInsert(callable=true, ...)</literal>).</para>
-
- <para>To check that the execution happens correctly, Hibernate allows
- you to define one of those three strategies:</para>
-
- <itemizedlist>
- <listitem>
- <para>NONE: no check is performed: the store procedure is expected
- to fail upon issues</para>
- </listitem>
-
- <listitem>
- <para>COUNT: use of rowcount to check that the update is
- successful</para>
- </listitem>
-
- <listitem>
- <para>PARAM: like COUNT but using an output parameter rather that
- the standard mechanism</para>
- </listitem>
- </itemizedlist>
-
- <para>To define the result check style, use the
<literal>check</literal>
- parameter (<literal>(a)SQLUpdate(check=ResultCheckStyle.COUNT,
- ...)</literal>).</para>
-
- <para>You can also override the SQL load statement by a native SQL query
- or a HQL query. You just have to refer to a named query with the
- <literal><literal>@Loader</literal></literal>
annotation.</para>
-
- <para>You can use the exact same set of annotations to override the
- collection related statements.</para>
-
- <programlisting>@OneToMany
-@JoinColumn(name="chaos_fk")
-<emphasis role="bold">@SQLInsert( sql="UPDATE CASIMIR_PARTICULE SET
chaos_fk = ? where id = ?")
-@SQLDelete( sql="UPDATE CASIMIR_PARTICULE SET chaos_fk = null where id =
?")</emphasis>
-private Set<CasimirParticle> particles = new
HashSet<CasimirParticle>();</programlisting>
-
- <para>The parameters order is important and is defined by the order
- Hibernate handle properties. You can see the expected order by enabling
- debug logging for the
<literal>org.hibernate.persister.entity</literal>
- level. With this level enabled Hibernate will print out the static SQL
- that is used to create, update, delete etc. entities. (To see the
- expected sequence, remember to not include your custom SQL through
- annotations as that will override the Hibernate generated static
- sql.)</para>
- </sect2>
- </sect1>
-</chapter>
\ No newline at end of file
Deleted: branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/lucene.xml
===================================================================
---
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/lucene.xml 2007-02-05
23:37:37 UTC (rev 11154)
+++
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/lucene.xml 2007-02-06
05:51:21 UTC (rev 11155)
@@ -1,670 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<chapter id="lucene" revision="2">
- <title>Hibernate Search: Apache <trademark>Lucene</trademark>
- Integration</title>
-
- <para><ulink url="http://lucene.apache.org">Apache
Lucene</ulink> is a
- high-performance Java search engine library available at the Apache Software
- Foundation. Hibernate Annotations includes a package of annotations that
- allows you to mark any domain model object as indexable and have Hibernate
- maintain a Lucene index of any instances persisted via Hibernate. Apache
- Lucene is also integrated with the Hibernate query facility.</para>
-
- <para>Hibernate Search is a work in progress and new features are cooking in
- this area. So expect some compatibility changes in subsequent
- versions.</para>
-
- <section id="lucene-architecture">
- <title>Architecture</title>
-
- <para>Hibernate Search is made of an indexing engine and an index search
- engine. Both are backed by Apache Lucene.</para>
-
- <para>When an entity is inserted, updated or removed to/from the database,
- <productname>Hibernate Search</productname> will keep track of this
event
- (through the Hibernate event system) and schedule an index update. When
- out of transaction, the update is executed right after the actual database
- operation. It is however recommended, for both your database and Hibernate
- Search, to execute your operation in a transaction (whether JDBC or JTA).
- When in a transaction, the index update is schedule for the transaction
- commit (and discarded in case of transaction rollback). You can think of
- this as the regular (infamous) autocommit vs transactional behavior. From
- a performance perspective, the <emphasis>in transaction</emphasis> mode
is
- recommended. All the index updates are handled for you without you having
- to use the Apache Lucene APIs.</para>
-
- <para>To interact with Apache Lucene indexes, Hibernate Search has the
- notion of <classname>DirectoryProvider</classname>. A directory provider
- will manage a given Lucene <classname>Directory</classname> type. You
can
- configure directory providers to adjust the directory target.</para>
-
- <para><productname>Hibernate Search</productname> can also use a
Lucene
- index to search an entity and return a (list of) managed entity saving you
- from the tedious Object / Lucene Document mapping and low level Lucene
- APIs. The application code use the unified
- <classname>org.hibernate.Query</classname> API exactly the way a HQL or
- native query would be done.</para>
- </section>
-
- <section id="lucene-configuration">
- <title>Configuration</title>
-
- <section id="lucene-configuration-directory" revision="1">
- <title>Directory configuration</title>
-
- <para>Apache Lucene has a notion of Directory where the index is stored.
- The Directory implementation can be customized but Lucene comes bundled
- with a file system and a full memory implementation.
- <productname>Hibernate Search</productname> has the notion of
- <literal>DirectoryProvider</literal> that handle the configuration and
- the initialization of the Lucene Directory.</para>
-
- <table>
- <title>List of built-in Directory Providers</title>
-
- <tgroup cols="3">
- <thead>
- <row>
- <entry align="center">Class</entry>
-
- <entry align="center">description</entry>
-
- <entry align="center">Properties</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>org.hibernate.search.store.FSDirectoryProvider</entry>
-
- <entry>File system based directory. The directory used will be
-
&lt;indexBase&gt;/&lt;<literal>(a)Indexed.name</literal>&gt;</entry>
-
- <entry><literal>indexBase</literal>: Base
directory</entry>
- </row>
-
- <row>
- <entry>org.hibernate.search.store.RAMDirectoryProvider</entry>
-
- <entry>Memory based directory, the directory will be uniquely
- indentified by the <literal>(a)Indexed.name</literal>
- element</entry>
-
- <entry>none</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>If the built-in directory providers does not fit your needs, you
- can write your own directory provider by implementing the
- <classname>org.hibernate.store.DirectoryProvider</classname>
- interface</para>
-
- <para>Each indexed entity is associated to a Lucene index (an index can
- be shared by several entities but this is not usually the case). You can
- configure the index through properties prefixed by
-
<constant>hibernate.search.</constant><replaceable>indexname</replaceable>.
- Default properties inherited to all indexes can be defined using the
- prefix <constant>hibernate.search.default.</constant></para>
-
- <para>To define the directory provider of a given index, you use the
-
<constant>hibernate.search.<replaceable>indexname</replaceable>.directory_provider</constant></para>
-
- <programlisting>hibernate.search.default.directory_provider
org.hibernate.search.store.FSDirectoryProvider
-hibernate.search.default.indexBase=/usr/lucene/indexes
-
-hibernate.search.Rules.directory_provider
org.hibernate.search.store.RAMDirectoryProvider
-</programlisting>
-
- <para>applied on</para>
-
- <programlisting>@Indexed(name="Status")
-public class Status { ... }
-
-@Indexed(name="Rules")
-public class Rule { ... }</programlisting>
-
- <para>will create a file system directory in
- <filename>/usr/lucene/indexes/Status</filename> where the Status
- entities will be indexed, and use an in memory directory named
- <literal>Rules</literal> where Rule entities will be
indexed.</para>
-
- <para>So you can easily defined common rules like the directory provider
- and base directory, and overide those default later on on a per index
- basis.</para>
-
- <para>Writing your own <classname>DirectoryProvider</classname>,
you can
- benefit this configuration mechanism too.</para>
- </section>
-
- <section id="lucene-configuration-event" revision="1">
- <title>Enabling automatic indexing</title>
-
- <para>Finally, we enable the
<literal>SearchEventListener</literal> for
- the three Hibernate events that occur after changes are executed to the
- database.</para>
-
- <programlisting><hibernate-configuration>
- ...
- <event type="post-update"
- <listener
class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
- <event type="post-insert"
- <listener
class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
- <event type="post-delete"
- <listener
class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
-</hibernate-configuration></programlisting>
- </section>
- </section>
-
- <section id="lucene-mapping" revision="2">
- <title>Mapping entities to the index structure</title>
-
- <para>All the metadata information related to indexed entities is
- described through some Java annotations. There is no need for xml mapping
- files nor a list of indexed entities. The list is discovered at startup
- time scanning the Hibernate mapped entities.</para>
-
- <para>First, we must declare a persistent class as indexable. This is done
- by annotating the class with <literal>@Indexed</literal> (all entities
not
- annotated with <literal>@Indexed</literal> will be ignored by the
indexing
- process):</para>
-
- <programlisting>@Entity
-<emphasis
role="bold">@Indexed(index="indexes/essays")</emphasis>
-public class Essay {
- ...
-}</programlisting>
-
- <para>The <literal>index</literal> attribute tells Hibernate what
the
- Lucene directory name is (usually a directory on your file system). If you
- wish to define a base directory for all Lucene indexes, you can use the
- <literal>hibernate.search.default.indexBase</literal> property in your
- configuration file. Each entity instance will be represented by a Lucene
- <classname>Document</classname> inside the given index (aka
- Directory).</para>
-
- <para>For each property (or attribute) of your entity, you have the
- ability to describe how it will be indexed. The default (ie no annotation)
- means that the property is completly ignored by the indexing process.
- <literal>@Field</literal> does declare a property as indexed. When
- indexing an element to a Lucene document you can specify how it is
- indexed:</para>
-
- <itemizedlist>
- <listitem>
- <para><literal>name</literal>: describe under which name, the
property
- should be stored in the Lucene Document. The default value is the
- property name (following the JavaBeans convention)</para>
- </listitem>
-
- <listitem>
- <para><literal>store</literal>: describe whether or not the
property
- is stored in the Lucene index. You can store the value
- <literal>Store.YES</literal> (comsuming more space in the index),
- store it in a compressed way <literal>Store.COMPRESS</literal> (this
- does consume more CPU), or avoid any storage
- <literal>Store.NO</literal> (this is the default value). When a
- property is stored, you can retrieve it from the Lucene Document (note
- that this is not related to whether the element is indexed or
- not).</para>
- </listitem>
-
- <listitem>
- <para>index: describe how the element is indexed (ie the process used
- to index the property and the type of information store). The
- different values are <literal>Index.NO</literal> (no indexing, ie
- cannot be found by a query), <literal>Index.TOKENIZED</literal> (use
- an analyzer to process the property),
- <literal>Index.UN_TOKENISED</literal> (no analyzer pre processing),
- <literal>Index.NO_NORM</literal> (do not store the normalization
- data).</para>
- </listitem>
- </itemizedlist>
-
- <para>These attributes are part of the <literal>@Field</literal>
- annotation.</para>
-
- <para>Whether or not you want to store the data depends on how you wish to
- use the index query result. As of today, for a pure <productname>Hibernate
- Search</productname> usage, storing is not necessary. Whether or not you
- want to tokenize a property or not depends on whether you wish to search
- the element as is, or only normalized part of it. It make sense to
- tokenize a text field, but it does not to do it for a date field (or an id
- field).</para>
-
- <para>Finally, the id property of an entity is a special property used by
- <productname>Hibernate Search</productname> to ensure index unicity of a
- given entity. By design, an id has to be stored and must not be tokenized.
- To mark a property as index id, use the <literal>@DocumentId</literal>
- annotation.</para>
-
- <programlisting>@Entity
-@Indexed(index="indexes/essays")
-public class Essay {
- ...
-
- @Id
- <emphasis role="bold">@DocumentId</emphasis>
- public Long getId() { return id; }
-
- <emphasis role="bold">@Field(name="Abstract",
index=Index.TOKENIZED, store=Store.YES)</emphasis>
- public String getSummary() { return summary; }
-
- @Lob
- <emphasis role="bold">(a)Field(index=Index.TOKENIZED)</emphasis>
- public String getText() { return text; }
-
-}</programlisting>
-
- <para>These annotations define an index with three fields:
- <literal>id</literal>, <literal>Abstract</literal> and
- <literal>text</literal>. Note that by default the field name is
- decapitalized, following the JavaBean specification.</para>
-
- <para>Note: you <emphasis>must</emphasis> specify
- <literal>@DocumentId</literal> on the identifier property of your entity
- class.</para>
-
- <para>Lucene has the notion of <emphasis>boost factor</emphasis>.
It's a
- way to give more weigth to a field or to an indexed element over an other
- during the indexation process. You can use <literal>@Boost</literal> at
- the field or the class level.</para>
-
- <programlisting>@Entity
-@Indexed(index="indexes/essays")
-<emphasis role="bold">@Boost(2)</emphasis>
-public class Essay {
- ...
-
- @Id
- @DocumentId
- public Long getId() { return id; }
-
- @Field(name="Abstract", index=Index.TOKENIZED, store=Store.YES)
- <emphasis role="bold">(a)Boost(2.5f)</emphasis>
- public String getSummary() { return summary; }
-
- @Lob
- @Field(index=Index.TOKENIZED)
- public String getText() { return text; }
-
-}</programlisting>
-
- <para>In our example, Essay's probability to reach the top of the search
- list will be multiplied by 2 and the summary field will be 2.5 more
- important than the test field. Note that this explaination is actually
- wrong, but it is simple and close enought to the reality. Please check the
- Lucene documentation or the excellent <citetitle>Lucene In
- Action</citetitle> from Otis Gospodnetic and Erik Hatcher.</para>
-
- <para>The analyzer class used to index the elements is configurable
- through the <literal>hibernate.search.analyzer</literal> property. If
none
- defined,
-
<classname>org.apache.lucene.analysis.standard.StandardAnalyzer</classname>
- is used as the default.</para>
- </section>
-
- <section id="lucene-bridge">
- <title>Property/Field Bridge</title>
-
- <para>All field of a full text index in Lucene have to be represented as
- Strings. Ones Java properties have to be indexed in a String form. For
- most of your properties, <productname>Hibernate Search</productname>
does
- the translation job for you thanks to a built-in set of bridges. In some
- cases, though you need a fine grain control over the translation
- process.</para>
-
- <section>
- <title>Built-in bridges</title>
-
- <para><literal>Hibernate Search</literal> comes bundled with a
set of
- built-in bridges between a Java property type and its full text
- representation.</para>
-
- <para><literal>Null</literal> elements are not indexed (Lucene
does not
- support null elements and it does not make much sense either)</para>
-
- <variablelist>
- <varlistentry>
- <term>null</term>
-
- <listitem>
- <para>null elements are not indexed. Lucene does not support null
- elements and this does not make much sense either.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>java.lang.String</term>
-
- <listitem>
- <para>String are indexed as is</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>short, Short, integer, Integer, long, Long, float, Float,
- double, Double, BigInteger, BigDecimal</term>
-
- <listitem>
- <para>Numbers are converted in their String representation. Note
- that numbers cannot be compared by Lucene (ie used in ranged
- queries) out of the box: they have to be padded <footnote>
- <para>Using a Range query is debattable and has drawbacks, an
- alternative approach is to use a Filter query which will
- filter the result query to the appropriate range.</para>
-
- <para><productname>Hibernate Search</productname> will
support
- a padding mechanism</para>
- </footnote></para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>java.util.Date</term>
-
- <listitem>
- <para>Dates are stored as yyyyMMddHHmmssSSS in GMT time
- (200611072203012 for Nov 7th of 2006 4:03PM and 12ms EST). You
- shouldn't really bother with the internal format. What is
- important is that when using a DateRange Query, you should know
- that the dates have to be expressed in GMT time.</para>
-
- <para>Usually, storing the date up to the milisecond is not
- necessary. <literal>@DateBridge</literal> defines the
appropriate
- resolution you are willing to store in the index
-
(<literal><literal>(a)DateBridge(resolution=Resolution.DAY)</literal></literal>).
- The date pattern will then be truncated accordingly.</para>
-
- <programlisting>@Entity @Indexed
-public class Meeting {
- @Field(index=Index.UN_TOKENIZED)
- <emphasis
role="bold">(a)DateBridge(resolution=Resolution.MINUTE)</emphasis>
- private Date date;
- ...
-}</programlisting>
-
- <warning>
- <para>A Date whose resolution is lower than
- <literal>MILLISECOND</literal> cannot be a
- <literal>@DocumentId</literal></para>
- </warning>
- </listitem>
- </varlistentry>
- </variablelist>
-
- <para></para>
- </section>
-
- <section>
- <title>Custom Bridge</title>
-
- <para>It can happen that the built-in bridges of Hibernate Search does
- not cover some of your property types, or that the String representation
- used is not what you expect.</para>
-
- <section>
- <title>StringBridge</title>
-
- <para>The simpliest custom solution is to give
<productname>Hibernate
- Search</productname> an implementation of your expected
- <emphasis>object to String</emphasis> bridge. To do so you need to
- implements the
- <literal>org.hibernate.search.bridge.StringBridge</literal>
- interface</para>
-
- <programlisting>/**
- * Padding Integer bridge.
- * All numbers will be padded with 0 to match 5 digits
- *
- * @author Emmanuel Bernard
- */
-public class PaddedIntegerBridge implements <emphasis
role="bold">StringBridge</emphasis> {
-
- private int PADDING = 5;
-
- <emphasis role="bold">public String objectToString(Object
object)</emphasis> {
- String rawInteger = ( (Integer) object ).toString();
- if (rawInteger.length() > PADDING) throw new IllegalArgumentException(
"Try to pad on a number too big" );
- StringBuilder paddedInteger = new StringBuilder( );
- for ( int padIndex = rawInteger.length() ; padIndex < PADDING ; padIndex++
) {
- paddedInteger.append('0');
- }
- return paddedInteger.append( rawInteger ).toString();
- }
-}</programlisting>
-
- <para>Then any property or field can use this bridge thanks to the
- <literal>@FieldBridge</literal> annotation</para>
-
- <programlisting><emphasis role="bold">@FieldBridge(impl =
PaddedIntegerBridge.class)</emphasis>
-private Integer length;</programlisting>
-
- <para>Parameters can be passed to the Bridge implementation making it
- more flexible. The Bridge implementation implements a
- <classname>ParameterizedBridge</classname> interface, and the
- parameters are passed through the <literal>@FieldBridge</literal>
- annotation.</para>
-
- <programlisting>public class PaddedIntegerBridge implements StringBridge,
<emphasis
- role="bold">ParameterizedBridge</emphasis> {
-
- public static String PADDING_PROPERTY = "padding";
- private int padding = 5; //default
-
- <emphasis role="bold">public void setParameterValues(Map
parameters)</emphasis> {
- Object padding = parameters.get( PADDING_PROPERTY );
- if (padding != null) this.padding = (Integer) padding;
- }
-
- public String objectToString(Object object) {
- String rawInteger = ( (Integer) object ).toString();
- if (rawInteger.length() > padding) throw new IllegalArgumentException(
"Try to pad on a number too big" );
- StringBuilder paddedInteger = new StringBuilder( );
- for ( int padIndex = rawInteger.length() ; padIndex < padding ; padIndex++
) {
- paddedInteger.append('0');
- }
- return paddedInteger.append( rawInteger ).toString();
- }
-}
-
-
-//property
-@FieldBridge(impl = PaddedIntegerBridge.class,
- <emphasis role="bold">params =
@Parameter(name="padding", value="10")</emphasis> )
-private Integer length;</programlisting>
-
- <para>The <classname>ParameterizedBridge</classname> interface
can be
- implemented by <classname>StringBridge</classname>,
- <classname>TwoWayStringBridge</classname>,
- <classname>FieldBridge</classname> implementations (see
- bellow).</para>
-
- <para>If you expect to use your bridge implementation on for an id
- property (ie annotated with <literal>@DocumentId</literal>), you
need
- to use a slightly extended version of
<literal>StringBridge</literal>
- named <classname>TwoWayStringBridge</classname>.
<literal>Hibernate
- Search</literal> needs to read the string representation of the
- identifier and generate the object out of it. There is not difference
- in the way the <literal>@FieldBridge</literal> annotation is
- used.</para>
-
- <programlisting>public class PaddedIntegerBridge implements
TwoWayStringBridge, ParameterizedBridge {
-
- public static String PADDING_PROPERTY = "padding";
- private int padding = 5; //default
-
- public void setParameterValues(Map parameters) {
- Object padding = parameters.get( PADDING_PROPERTY );
- if (padding != null) this.padding = (Integer) padding;
- }
-
- public String objectToString(Object object) {
- String rawInteger = ( (Integer) object ).toString();
- if (rawInteger.length() > padding) throw new IllegalArgumentException(
"Try to pad on a number too big" );
- StringBuilder paddedInteger = new StringBuilder( );
- for ( int padIndex = rawInteger.length() ; padIndex < padding ; padIndex++
) {
- paddedInteger.append('0');
- }
- return paddedInteger.append( rawInteger ).toString();
- }
-
- <emphasis role="bold">public Object stringToObject(String
stringValue)</emphasis> {
- return new Integer(stringValue);
- }
-}
-
-
-//id property
-@DocumentId
-@FieldBridge(impl = PaddedIntegerBridge.class,
- params = @Parameter(name="padding", value="10") )
-private Integer id;</programlisting>
-
- <para>It is critically important for the two-way process to be
- idempotent (ie object = stringToObject( objectToString( object ) )
- ).</para>
- </section>
-
- <section>
- <title>FieldBridge</title>
-
- <para>Some usecase requires more than a simple object to string
- translation when mapping a property to a Lucene index. To give you
- most of the flexibility you can also implement a bridge as a
- <classname>FieldBridge</classname>. This interface give you a
property
- value and let you map it the way you want in your Lucene
- <classname>Document</classname>.This interface is very similar in
its
- concept to the <productname>Hibernate</productname>
- <classname>UserType</classname>.</para>
-
- <para>You can for example store a given property in two different
- document fields</para>
-
- <programlisting>/**
- * Store the date in 3 different field year, month, day
- * to ease Range Query per year, month or day
- * (eg get all the elements of december for the last 5 years)
- *
- * @author Emmanuel Bernard
- */
-public class DateSplitBridge implements FieldBridge {
- private final static TimeZone GMT = TimeZone.getTimeZone("GMT");
-
- <emphasis role="bold">public void set(String name, Object value,
Document document, Field.Store store, Field.Index index, Float boost) {</emphasis>
- Date date = (Date) value;
- Calendar cal = GregorianCalendar.getInstance( GMT );
- cal.setTime( date );
- int year = cal.get( Calendar.YEAR );
- int month = cal.get( Calendar.MONTH ) + 1;
- int day = cal.get( Calendar.DAY_OF_MONTH );
- //set year
- Field field = new Field( name + ".year", String.valueOf(year), store,
index );
- if ( boost != null ) field.setBoost( boost );
- document.add( field );
- //set month and pad it if needed
- field = new Field( name + ".month", month < 10 ? "0" :
"" + String.valueOf(month), store, index );
- if ( boost != null ) field.setBoost( boost );
- document.add( field );
- //set day and pad it if needed
- field = new Field( name + ".day", day < 10 ? "0" :
"" + String.valueOf(day), store, index );
- if ( boost != null ) field.setBoost( boost );
- document.add( field );
- }
-}
-
-
-//property
-<emphasis role="bold">@FieldBridge(impl =
DateSplitBridge.class)</emphasis>
-private Integer length;</programlisting>
-
- <para></para>
- </section>
- </section>
- </section>
-
- <section id="lucene-query">
- <title>Querying</title>
-
- <para>The second most important capability of <productname>Hibernate
- Search</productname> is the ability to execute a Lucene query and retrieve
- entities managed by an Hibernate session, providing the power of Lucene
- without living the Hibernate paradygm, and giving another dimension to the
- Hibernate classic search mechanisms (HQL, Criteria query, native SQL
- query).</para>
-
- <para>To access the <productname>Hibernate Search</productname>
querying
- facilities, you have to use an Hibernate
- <classname>FullTextSession</classname>. A SearchSession wrap an regular
- <classname>org.hibernate.Session</classname> to provide query and
indexing
- capabilities.</para>
-
- <programlisting>Session session = sessionFactory.openSession();
-...
-FullTextSession fullTextSession =
Search.createFullTextSession(session);</programlisting>
-
- <para>The search facility is built on native Lucene queries.</para>
-
- <programlisting>org.apache.lucene.QueryParser parser = new
QueryParser("title", new StopAnalyzer() );
-
-org.hibernate.lucene.search.Query luceneQuery = parser.parse( "summary:Festina Or
brand:Seiko" );
-<emphasis role="bold">org.hibernate.Query fullTextQuery =
fullTextSession.createFullTextQuery( luceneQuery );</emphasis>
-
-List result = fullTextQuery.list(); //return a list of managed
objects</programlisting>
-
- <para>The Hibernate query built on top of the Lucene query is a regular
- <literal>org.hibernate.Query</literal>, you are is the same paradygm as
- the other Hibernate query facilities (HQL, Native or Criteria). The
- regular <literal>list()</literal>,
<literal>uniqueResult()</literal>,
- <literal>iterate()</literal> and <literal>scroll()</literal>
can be
- used.</para>
-
- <para>If you expect a reasonnable result number and expect to work on all
- of them, <methodname>list()</methodname> or
- <methodname>uniqueResult()</methodname> are recommanded.
- <methodname>list()</methodname> work best if the entity
- <literal>batch-size</literal> is set up properly. Note that Hibernate
- Seach has to process all Lucene Hits elements when using
- <methodname>list()</methodname>,
<methodname>uniqueResult()</methodname>
- and <methodname>iterate()</methodname>. If you wish to minimize Lucene
- document loading, <methodname>scroll()</methodname> is more appropriate,
- Don't forget to close the <classname>ScrollableResults</classname>
object
- when you're done, since it keeps Lucene resources.</para>
-
- <para>An efficient way to work with queries is to use pagination. The
- pagination API is exactly the one available in
- <classname>org.hibernate.Query</classname>:</para>
-
- <programlisting><emphasis role="bold">org.hibernate.Query
fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery );</emphasis>
-fullTextQuery.setFirstResult(30);
-fullTextQuery.setMaxResult(20);
-fullTextQuery.list(); //will return a list of 20 elements starting from the
30th</programlisting>
-
- <para>Only the relevant Lucene Documents are accessed.</para>
- </section>
-
- <section id="lucene-index">
- <title>Indexing</title>
-
- <para>It is sometimes useful to index an object event if this object is
- not inserted nor updated to the database. This is especially true when you
- want to build your index the first time. You can achieve that goal using
- the <classname>FullTextSession</classname>.</para>
-
- <programlisting>FullTextSession fullTextSession =
Search.createFullTextSession(session);
-Transaction tx = fullTextSession.beginTransaction();
-for (Customer customer : customers) {
- <emphasis
role="bold">fullTextSession.index(customer);</emphasis>
-}
-tx.commit(); //index are written at commit time</programlisting>
-
- <para>For maximum efficiency, Hibernate Search batch index operations
- which and execute them at commit time (Note: you don't need to use
- <classname>org.hibernate.Transaction</classname> in a JTA
- environment).</para>
- </section>
-</chapter>
\ No newline at end of file
Deleted: branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/setup.xml
===================================================================
---
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/setup.xml 2007-02-05
23:37:37 UTC (rev 11154)
+++
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/setup.xml 2007-02-06
05:51:21 UTC (rev 11155)
@@ -1,153 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<chapter>
- <title id="setup" revision="1">Setting up an annotations
project</title>
-
- <section id="setup-requirements">
- <title>Requirements</title>
-
- <itemizedlist>
- <listitem>
- <para>Download and unpack the Hibernate Annotations distribution from
- the Hibernate website.</para>
- </listitem>
-
- <listitem>
- <para><emphasis>This release requires Hibernate 3.2.0.GA and above.
- Do not use this release of Hibernate Annotations with an older version
- of Hibernate 3.x!</emphasis></para>
- </listitem>
-
- <listitem>
- <para>This release is known to work on Hibernate core 3.2.0.CR5, 3.2.0.GA
- and 3.2.1.GA</para>
- </listitem>
-
- <listitem>
- <para>Make sure you have JDK 5.0 installed. You can of course continue
- using XDoclet and get some of the benefits of annotation-based
- metadata with older JDK versions. Note that this document only
- describes JDK 5.0 annotations and you have to refer to the XDoclet
- documentation for more information.</para>
- </listitem>
- </itemizedlist>
- </section>
-
- <section id="setup-configuration">
- <title>Configuration</title>
-
- <para>First, set up your classpath (after you have created a new project
- in your favorite IDE): <itemizedlist>
- <listitem>
- <para>Copy all Hibernate3 core and required 3rd party library files
- (see lib/README.txt in Hibernate).</para>
- </listitem>
-
- <listitem>
- <para>Copy <filename>hibernate-annotations.jar</filename>
and
- <filename>lib/ejb3-persistence.jar</filename> from the Hibernate
- Annotations distribution to your classpath as well.</para>
- </listitem>
-
- <listitem>
- <para>To use the <xref linkend="lucene" />, add the
lucene jar
- file.</para>
- </listitem>
- </itemizedlist></para>
-
- <para>We also recommend a small wrapper class to startup Hibernate in a
- static initializer block, known as <classname>HibernateUtil</classname>.
- You might have seen this class in various forms in other areas of the
- Hibernate documentation. For Annotation support you have to enhance this
- helper class as follows: <programlisting>package hello;
-
-import org.hibernate.*;
-import org.hibernate.cfg.*;
-import test.*;
-import test.animals.Dog;
-
-public class HibernateUtil {
-
-private static final SessionFactory sessionFactory;
-
- static {
- try {
-
- sessionFactory = new <emphasis
role="bold">AnnotationConfiguration()</emphasis>.buildSessionFactory();
- } catch (Throwable ex) {
- // Log exception!
- throw new ExceptionInInitializerError(ex);
- }
- }
-
- public static Session getSession()
- throws HibernateException {
- return sessionFactory.openSession();
- }
-}
- </programlisting></para>
-
- <para>Interesting here is the use of
- <classname>AnnotationConfiguration</classname>. The packages and
annotated
- classes are declared in your regular XML configuration file (usually
- <filename>hibernate.cfg.xml</filename>). Here is the equivalent of the
- above declaration:</para>
-
- <programlisting><!DOCTYPE hibernate-configuration PUBLIC
- "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
-
- <hibernate-configuration>
- <session-factory>
- <emphasis role="bold"><mapping
package="test.animals"/>
- <mapping class="test.Flight"/>
- <mapping class="test.Sky"/>
- <mapping class="test.Person"/>
- <mapping class="test.animals.Dog"/></emphasis>
-<emphasis role="bold"> <mapping
resource="test/animals/orm.xml"/></emphasis>
- </session-factory>
- </hibernate-configuration>
- </programlisting>
-
- <para>Note that you can mix the hbm.xml use and the new annotation one.
- The resource element can be either an hbm file or an EJB3 XML deployment
- descriptor. The distinction is transparent for your configuration
- process.</para>
-
- <para>Alternatively, you can define the annotated classes and packages
- using the programmatic API</para>
-
- <programlisting> sessionFactory = new <emphasis
role="bold">AnnotationConfiguration()
- .addPackage("test.animals") //the fully qualified package
name
- .addAnnotatedClass(Flight.class)
- .addAnnotatedClass(Sky.class)
- .addAnnotatedClass(Person.class)
- .addAnnotatedClass(Dog.class)</emphasis>
-<emphasis role="bold">
.addResource("test/animals/orm.xml")</emphasis>
- .buildSessionFactory();</programlisting>
-
- <para>You can also use the Hibernate EntityManager which has its own
- configuration mechanism. Please refer to this project documentation for
- more details.</para>
-
- <para>There is no other difference in the way you use Hibernate APIs with
- annotations, except for this startup routine change or in the
- configuration file. You can use your favorite configuration method for
- other properties ( <filename>hibernate.properties</filename>,
- <filename>hibernate.cfg.xml</filename>, programmatic APIs, etc). You can
- even mix annotated persistent classes and classic
- <filename>hbm.cfg.xml</filename> declarations with the same
- <classname>SessionFactory</classname>. You can however not declare a
class
- several times (whether annotated or through hbm.xml). You cannot mix
- configuration strategies (hbm vs annotations) in a mapped entity hierarchy
- either.</para>
-
- <para>To ease the migration process from hbm files to annotations, the
- configuration mechanism detects the mapping duplication between
- annotations and hbm files. HBM files are then prioritized over annotated
- metadata on a class to class basis. You can change the priority using
- <literal>hibernate.mapping.precedence</literal> property. The default is
- <literal>hbm, class</literal>, changing it to <literal>class,
- hbm</literal> will prioritize the annotated classes over hbm files when a
- conflict occurs.</para>
- </section>
-</chapter>
\ No newline at end of file
Deleted: branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/validator.xml
===================================================================
---
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/validator.xml 2007-02-05
23:37:37 UTC (rev 11154)
+++
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/validator.xml 2007-02-06
05:51:21 UTC (rev 11155)
@@ -1,560 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<chapter id="validator">
- <title>Hibernate Validator</title>
-
- <para>Annotations are a very convenient and elegant way to specify invariant
- constraints for a domain model. You can, for example, express that a
- property should never be null, that the account balance should be strictly
- positive, etc. These domain model constraints are declared in the bean
- itself by annotating its properties. A validator can then read them and
- check for constraint violations. The validation mechanism can be executed in
- different layers in your application without having to duplicate any of
- these rules (presentation layer, data access layer). Hibernate Validator has
- been designed for that purpose.</para>
-
- <para>Hibernate Validator works at two levels. First, it is able to check
- in-memory instances of a class for constraint violations. Second, it can
- apply the constraints to the Hibernate metamodel and incorporate them into
- the generated database schema.</para>
-
- <para>Each constraint annotation is associated to a validator implementation
- responsible for checking the constraint on the entity instance. A validator
- can also (optionally) apply the constraint to the Hibernate metamodel,
- allowing Hibernate to generate DDL that expresses the constraint. With the
- appropriate event listener, you can execute the checking operation on
- inserts and updates done by Hibernate. Hibernate Validator is not limited to
- use with Hibernate. You can easily use it anywhere in your
- application.</para>
-
- <para>When checking instances at runtime, Hibernate Validator returns
- information about constraint violations in an array of
- <classname>InvalidValue</classname>s. Among other information, the
- <classname>InvalidValue</classname> contains an error description message
- that can embed the parameter values bundle with the annotation (eg. length
- limit), and message strings that may be externalized to a
- <classname>ResourceBundle</classname>.</para>
-
- <sect1 id="validator-constraints">
- <title>Constraints</title>
-
- <sect2>
- <title>What is a constraint?</title>
-
- <para>A constraint is represented by an annotation. A constraint usually
- has some attributes used to parameterize the constraints limits. The
- constraint apply to the annotated element.</para>
- </sect2>
-
- <sect2 id="validator-constraints-built-in" revision="1">
- <title>Built in constraints</title>
-
- <para>Hibernate Validator comes with some built-in constraints, which
- covers most basic data checks. As we'll see later, you're not limited to
- them, you can in a minute write your own constraints.</para>
-
- <table>
- <title>Built-in constraints</title>
-
- <tgroup cols="4">
- <colspec align="center" />
-
- <thead>
- <row>
- <entry>Annotation</entry>
-
- <entry>Apply on</entry>
-
- <entry>Runtime checking</entry>
-
- <entry>Hibernate Metadata impact</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>@Length(min=, max=)</entry>
-
- <entry>property (String)</entry>
-
- <entry>check if the string length match the range</entry>
-
- <entry>Column length will be set to max</entry>
- </row>
-
- <row>
- <entry>@Max(value=)</entry>
-
- <entry>property (numeric or string representation of a
- numeric)</entry>
-
- <entry>check if the value is less than or equals to
max</entry>
-
- <entry>Add a check constraint on the column</entry>
- </row>
-
- <row>
- <entry>@Min(value=)</entry>
-
- <entry>property (numeric or string representation of a
- numeric)</entry>
-
- <entry>check if the value is more than or equals to
min</entry>
-
- <entry>Add a check constraint on the column</entry>
- </row>
-
- <row>
- <entry>@NotNull</entry>
-
- <entry>property</entry>
-
- <entry>check if the value is not null</entry>
-
- <entry>Column(s) are not null</entry>
- </row>
-
- <row>
- <entry>@NotEmpty</entry>
-
- <entry>property</entry>
-
- <entry>check if the string is not null nor empty. Check if the
- connection is not null nor empty</entry>
-
- <entry>Column(s) are not null (for String)</entry>
- </row>
-
- <row>
- <entry>@Past</entry>
-
- <entry>property (date or calendar)</entry>
-
- <entry>check if the date is in the past</entry>
-
- <entry>Add a check constraint on the column</entry>
- </row>
-
- <row>
- <entry>@Future</entry>
-
- <entry>property (date or calendar)</entry>
-
- <entry>check if the date is in the future</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@Pattern(regex="regexp", flag=)</entry>
-
- <entry>property (string)</entry>
-
- <entry>check if the property match the regular expression given
- a match flag (see <classname> java.util.regex.Pattern
- </classname> )</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@Range(min=, max=)</entry>
-
- <entry>property (numeric or string representation of a
- numeric)</entry>
-
- <entry>check if the value is between min and max
- (included)</entry>
-
- <entry>Add a check constraint on the column</entry>
- </row>
-
- <row>
- <entry>@Size(min=, max=)</entry>
-
- <entry>property (array, collection, map)</entry>
-
- <entry>check if the element size is between min and max
- (included)</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@AssertFalse</entry>
-
- <entry>property</entry>
-
- <entry>check that the method evaluates to false (useful for
- constraints expressed in code rather than annotations)</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@AssertTrue</entry>
-
- <entry>property</entry>
-
- <entry>check that the method evaluates to true (useful for
- constraints expressed in code rather than annotations)</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@Valid</entry>
-
- <entry>property (object)</entry>
-
- <entry>perform validation recursively on the associated object.
- If the object is a Collection or an array, the elements are
- validated recursively. If the object is a Map, the value
- elements are validated recursively.</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@Email</entry>
-
- <entry>property (String)</entry>
-
- <entry>check whether the string is conform to the email address
- specification</entry>
-
- <entry>none</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect2>
-
- <sect2 id="validator-constraints-error" xreflabel="Error
messages">
- <title>Error messages</title>
-
- <para>Hibernate Validator comes with a default set of error messages
- translated in about ten languages (if yours is not part of it, please
- sent us a patch). You can override those messages by creating a
- <filename>ValidatorMessages.properties</filename> or
- (<filename>ValidatorMessages_loc.properties</filename>) and override
the
- needed keys. You can even add your own additional set of messages while
- writing your validator annotations. If Hibernate Validator cannot
- resolve a key from your resourceBundle nor from ValidatorMessage, it
- falls back to the default built-in values.</para>
-
- <para>Alternatively you can provide a
- <classname>ResourceBundle</classname> while checking programmatically
- the validation rules on a bean or if you want a completly different
- interpolation mechanism, you can provide an implementation of
- <literal>org.hibernate.validator.MessageInterpolator</literal> (check
- the JavaDoc for more informations).</para>
- </sect2>
-
- <sect2>
- <title>Writing your own constraints</title>
-
- <para>Extending the set of built-in constraints is extremely easy. Any
- constraint consists of two pieces: the constraint
- <emphasis>descriptor</emphasis> (the annotation) and the constraint
- <emphasis>validator</emphasis> (the implementation class). Here is a
- simple user-defined descriptor:</para>
-
- <programlisting>(a)ValidatorClass(CapitalizedValidator.class)
-@Target(METHOD)
-@Retention(RUNTIME)
-@Documented
-public @interface Capitalized {
- CapitalizeType type() default Capitalize.FIRST;
- String message() default "has incorrect capitalization";
-}</programlisting>
-
- <para><literal>type</literal> is a parameter describing how the
property
- should to be capitalized. This is a user parameter fully dependant on
- the annotation business.</para>
-
- <para><literal>message</literal> is the default string used to
describe
- the constraint violation and is mandatory. You can hard code the string
- or you can externalize part/all of it through the Java ResourceBundle
- mechanism. Parameters values are going to be injected inside the message
- when the <literal>{parameter}</literal> string is found (in our
example
- <literal>Capitalization is not {type}</literal> would generate
- <literal>Capitalization is not FIRST</literal>), externalizing the
whole
- string in <filename>ValidatorMessages.properties</filename> is
- considered good practice. See <xref
- linkend="validator-constraints-error" />.</para>
-
- <programlisting>(a)ValidatorClass(CapitalizedValidator.class)
-@Target(METHOD)
-@Retention(RUNTIME)
-@Documented
-public @interface Capitalized {
- CapitalizeType type() default Capitalize.FIRST;
- String message() default "{validator.capitalized}";
-}
-
-...
-#in ValidatorMessages.properties
-validator.capitalized=<literal>Capitalization is not
{type}</literal></programlisting>
-
- <para>As you can see the {} notation is recursive.</para>
-
- <para>To link a descriptor to its validator implementation, we use the
- <literal>@ValidatorClass</literal> meta-annotation. The validator
class
- parameter must name a class which implements
-
<literal>Validator<ConstraintAnnotation></literal>.</para>
-
- <para>We now have to implement the validator (ie. the rule checking
- implementation). A validation implementation can check the value of the
- a property (by implementing <literal>PropertyConstraint</literal>)
- and/or can modify the hibernate mapping metadata to express the
- constraint at the database level (by implementing
- <literal>PersistentClassConstraint</literal>).</para>
-
- <programlisting>public class CapitalizedValidator
- implements Validator<Capitalized>, PropertyConstraint {
- private CapitalizeType type;
-
- //part of the Validator<Annotation> contract,
- //allows to get and use the annotation values
- public void initialize(Capitalized parameters) {
- type = parameters.type();
- }
-
- //part of the property constraint contract
- public boolean isValid(Object value) {
- if (value==null) return true;
- if ( !(value instanceof String) ) return false;
- String string = (String) value;
- if (type == CapitalizeType.ALL) {
- return string.equals( string.toUpperCase() );
- }
- else {
- String first = string.substring(0,1);
- return first.equals( first.toUpperCase();
- }
- }
-}</programlisting>
-
- <para>The <literal>isValid()</literal> method should return false
if the
- constraint has been violated. For more examples, refer to the built-in
- validator implementations.</para>
-
- <para>We only have seen property level validation, but you can write a
- Bean level validation annotation. Instead of receiving the return
- instance of a property, the bean itself will be passed to the validator.
- To activate the validation checking, just annotated the bean itself
- instead. A small sample can be found in the unit test suite.</para>
- </sect2>
-
- <sect2>
- <title>Annotating your domain model</title>
-
- <para>Since you are already familiar with annotations now, the syntax
- should be very familiar.</para>
-
- <programlisting>public class Address {
- private String line1;
- private String line2;
- private String zip;
- private String state;
- private String country;
- private long id;
-
- // a not null string of 20 characters maximum
- @Length(max=20)
- @NotNull
- public String getCountry() {
- return country;
- }
-
- // a non null string
- @NotNull
- public String getLine1() {
- return line1;
- }
-
- //no constraint
- public String getLine2() {
- return line2;
- }
-
- // a not null string of 3 characters maximum
- @Length(max=3) @NotNull
- public String getState() {
- return state;
- }
-
- // a not null numeric string of 5 characters maximum
- // if the string is longer, the message will
- //be searched in the resource bundle at key 'long'
- @Length(max=5, message="{long}")
- @Pattern(regex="[0-9]+")
- @NotNull
- public String getZip() {
- return zip;
- }
-
- // should always be true
- @AssertTrue
- public boolean isValid() {
- return true;
- }
-
- // a numeric between 1 and 2000
- @Id @Min(1)
- @Range(max=2000)
- public long getId() {
- return id;
- }
-}</programlisting>
-
- <para>While the example only shows public property validation, you can
- also annotate fields of any kind of visibility.</para>
-
- <programlisting>@MyBeanConstraint(max=45)
-public class Dog {
- @AssertTrue private boolean isMale;
- @NotNull protected String getName() { ... };
- ...
-}</programlisting>
-
- <para>You can also annotate interfaces. Hibernate Validator will check
- all superclasses and interfaces extended or implemented by a given bean
- to read the appropriate validator annotations.</para>
-
- <programlisting>public interface Named {
- @NotNull String getName();
- ...
-}
-
-public class Dog implements Named {
-
- @AssertTrue private boolean isMale;
-
- public String getName() { ... };
-
-}</programlisting>
-
- <para>The name property will be checked for nullity when the Dog bean is
- validated.</para>
- </sect2>
- </sect1>
-
- <sect1>
- <title>Using the Validator framework</title>
-
- <para>Hibernate Validator is intended to be used to implement
- multi-layered data validation, where we express constraints in one place
- (the annotated domain model) and apply them at various different layers of
- the application.</para>
-
- <sect2>
- <title>Database schema-level validation</title>
-
- <para>Out of the box, Hibernate Annotations will translate the
- constraints you have defined for your entities into mapping metadata.
- For example, if a property of your entity is annotated
- <literal>@NotNull</literal>, its columns will be declared as
- <literal>not null</literal> in the DDL schema generated by
- Hibernate.</para>
- </sect2>
-
- <sect2>
- <title>Hibernate event-based validation</title>
-
- <para>Hibernate Validator has two built-in Hibernate event listeners.
- Whenever a <literal>PreInsertEvent</literal> or
- <literal>PreUpdateEvent</literal> occurs, the listeners will verify
all
- constraints of the entity instance and throw an exception if any
- constraint is violated. Basically, objects will be checked before any
- inserts and before any updates made by Hibernate. This is the most
- convenient and the easiest way to activate the validation process. On
- constraint violation, the event will raise a runtime
- <classname>InvalidStateException</classname> which contains an array
of
- <literal>InvalidValue</literal>s describing each failure.</para>
-
- <programlisting><hibernate-configuration>
- ...
- <event type="pre-update">
- <listener
-
class="org.hibernate.validator.event.ValidatePreUpdateEventListener"/>
- </event>
- <event type="pre-insert">
- <listener
-
class="org.hibernate.validator.event.ValidatePreInsertEventListener"/>
- </event>
-</hibernate-configuration></programlisting>
-
- <para><note>
- <para>When using Hibernate Entity Manager, the Validation framework
- is activated out of the box. If the beans are not annotated with
- validation annotations, there is no performance cost.</para>
- </note></para>
- </sect2>
-
- <sect2>
- <title>Application-level validation</title>
-
- <para>Hibernate Validator can be applied anywhere in your application
- code.</para>
-
- <programlisting>ClassValidator personValidator = new ClassValidator(
Person.class );
-ClassValidator addressValidator = new ClassValidator( Address.class,
ResourceBundle.getBundle("messages", Locale.ENGLISH) );
-
-InvalidValue[] validationMessages =
addressValidator.getInvalidValues(address);</programlisting>
-
- <para>The first two lines prepare the Hibernate Validator for class
- checking. The first one relies upon the error messages embedded in
- Hibernate Validator (see <xref
- linkend="validator-constraints-error" />), the second one uses a
- resource bundle for these messages. It is considered a good practice to
- execute these lines once and cache the validator instances.</para>
-
- <para>The third line actually validates the
<literal>Address</literal>
- instance and returns an array of <literal>InvalidValue</literal>s.
Your
- application logic will then be able to react to the failure.</para>
-
- <para>You can also check a particular property instead of the whole
- bean. This might be useful for property per property user
- interaction</para>
-
- <programlisting>ClassValidator addressValidator = new ClassValidator(
Address.class, ResourceBundle.getBundle("messages", Locale.ENGLISH) );
-
-//only get city property invalid values
-InvalidValue[] validationMessages = addressValidator.getInvalidValues(address,
"city");
-
-//only get potential city property invalid values
-InvalidValue[] validationMessages =
addressValidator.getPotentialInvalidValues("city",
"Paris")</programlisting>
- </sect2>
-
- <sect2>
- <title>Validation informations</title>
-
- <para>As a validation information carrier, hibernate provide an array of
- <classname>InvalidValue</classname>. Each
- <literal>InvalidValue</literal> has a buch of methods describing the
- individual issues.</para>
-
- <para><methodname>getBeanClass()</methodname> retrieves the
failing bean
- type</para>
-
- <para><methodname>getBean()</methodname>retrieves the failing
instance
- (if any ie not when using
- <methodname>getPotentianInvalidValues()</methodname>)</para>
-
- <para><methodname>getValue()</methodname> retrieves the failing
- value</para>
-
- <para><methodname>getMessage()</methodname> retrieves the proper
- internationalized error message</para>
-
- <para><methodname>getRootBean()</methodname> retrieves the root
bean
- instance generating the issue (useful in conjunction with
- <literal>@Valid</literal>), is null if getPotentianInvalidValues() is
- used.</para>
-
- <para><literal>getPropertyPath()</literal> retrieves the dotted
path of
- the failing property starting from the root bean</para>
- </sect2>
- </sect1>
-</chapter>
\ No newline at end of file
Deleted:
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/xml-overriding.xml
===================================================================
---
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/xml-overriding.xml 2007-02-05
23:37:37 UTC (rev 11154)
+++
branches/HAN_SPLIT/HibernateExt/validator/doc/reference/en/modules/xml-overriding.xml 2007-02-06
05:51:21 UTC (rev 11155)
@@ -1,402 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<chapter id="xml-overriding" label="Overriding metadata through
XML">
- <title>Overriding metadata through XML</title>
-
- <para>The primary target for metadata in EJB3 is annotations, but the EJB3
- specification provides a way to override or replace the annotation defined
- metadata through an XML deployment descriptor. In the current release only
- pure EJB3 annotations overriding are supported. If you wish to use Hibernate
- specific features in some entities, you'll have to either use annotations or
- fallback to hbm files. You can of course mix and match annotated entities
- and entities describes in hbm files.</para>
-
- <para>The unit test suite shows some additional XML file samples.</para>
-
- <section id="xml-overriding-principles">
- <title>Principles</title>
-
- <para>The XML deployment descriptor structure has been designed to reflect
- the annotations one. So if you know the annotations structure, using the
- XML schema will be straightforward for you.</para>
-
- <para>You can define one ot more XML files describing your metadata, these
- files will be merged by the overriding engine.</para>
-
- <section>
- <title>Global level metadata</title>
-
- <para>You can define global level metadata available for all XML files.
- You must not define these metadata more than once per deployment.</para>
-
- <programlisting><?xml version="1.0"
encoding="UTF-8"?>
-
-<entity-mappings
-
xmlns="http://java.sun.com/xml/ns/persistence/orm"
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
- version="1.0">
-
- <persistence-unit-metadata>
- <xml-mapping-metadata-complete/>
- <persistence-unit-defaults>
- <schema>myschema</schema>
- <catalog>mycatalog</catalog>
- <cascade-persist/>
- </persistence-unit-defaults>
- </persistence-unit-metadata></programlisting>
-
- <para><literal>xml-mapping-metadata-complete</literal> means that
all
- entity, mapped-superclasses and embeddable metadata should be picked up
- from XML (ie ignore annotations).</para>
-
- <para><literal>schema / catalog</literal> will override all
default
- definitions of schema and catalog in the metadata (both XML and
- annotations).</para>
-
- <para><literal>cascade-persist</literal> means that all
associations
- have PERSIST as a cascade type. We recommend you to not use this
- feature.</para>
- </section>
-
- <section id="xml-overriding-principles-entity"
revision="1">
- <title>Entity level metadata</title>
-
- <para>You can either define or override metadata informations on a given
- entity.</para>
-
- <programlistingco>
- <areaspec>
- <area coords="3 85" id="aa1" />
-
- <area coords="9 85" id="aa2" />
-
- <area coords="10 85" id="aa3" />
-
- <area coords="11 85" id="aa4" />
-
- <area coords="17 85" id="aa5" />
-
- <area coords="23 85" id="aa6" />
-
- <area coords="24 85" id="aa7" />
-
- <area coords="25 85" id="aa8" />
-
- <area coords="26 85" id="aa9" />
-
- <area coords="31 85" id="aa10" />
- </areaspec>
-
- <programlisting><?xml version="1.0"
encoding="UTF-8"?>
-
-<entity-mappings
-
xmlns="http://java.sun.com/xml/ns/persistence/orm"
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
- version="1.0">
-
-
<package>org.hibernate.test.annotations.reflection</package>
- <entity class="Administration" access="PROPERTY"
metadata-complete="true">
- <table name="tbl_admin">
- <unique-constraint>
- <column-name>firstname</column-name>
- <column-name>lastname</column-name>
- </unique-constraint>
- </table>
- <secondary-table name="admin2">
- <primary-key-join-column name="admin_id"
referenced-column-name="id"/>
- <unique-constraint>
- <column-name>address</column-name>
- </unique-constraint>
- </secondary-table>
- <id-class class="SocialSecurityNumber"/>
- <inheritance strategy="JOINED"/>
- <sequence-generator name="seqhilo"
sequence-name="seqhilo"/>
- <table-generator name="table"
table="tablehilo"/>
- ...
- </entity>
-
- <entity class="PostalAdministration">
- <primary-key-join-column name="id"/>
- ...
- </entity>
-</entity-mappings></programlisting>
-
- <calloutlist>
- <callout arearefs="aa1">
- <para><literal>entity-mappings</literal>: entity-mappings
is the
- root element for all XML files. You must declare the xml schema,
- the schema file is included in the hibernate-annotations.jar file,
- no internet access will be processed by Hibernate
- Annotations.</para>
- </callout>
-
- <callout arearefs="aa2">
- <para><literal>package</literal> (optional): default
package used
- for all non qualified class names in the given deployment
- descriptor file.</para>
- </callout>
-
- <callout arearefs="aa3">
- <para><literal>entity</literal>: desribes an
entity.</para>
-
- <para><literal>metadata-complete</literal> defines whether
the
- metadata description for this element is complete or not (in other
- words, if annotations present at the class level should be
- considered or not).</para>
-
- <para>An entity has to have a <literal>class</literal>
attribute
- refering the java class the metadata applies on.</para>
-
- <para>You can overrides entity name through the
- <literal>name</literal> attribute, if none is defined and if an
- <literal>(a)Entity.name</literal> is present, then it is used
- (provided that metadata complete is not set).</para>
-
- <para>For netadata complete (see below) element, you can define an
- <literal>access</literal> (either
<literal>FIELD</literal> or
- <literal>PROPERTY</literal> (default)). For non medatada
complete
- element, if <literal>access</literal> is not defined, the @Id
- position will lead position, if <literal>access</literal> is
- defined, the value is used.</para>
- </callout>
-
- <callout arearefs="aa4">
- <para><literal>table</literal>: you can declare table
properties
- (name, schema, catalog), if none is defined, the java annotation
- is used.</para>
-
- <para>You can define one or several unique constraints as seen in
- the example</para>
- </callout>
-
- <callout arearefs="aa5">
- <para><literal>secondary-table</literal>: defines a
secondary
- table very much like a regular table except that you can define
- the primary key / foreign key column(s) through the
- <literal>primary-key-join-column</literal> element. On non
- metadata complete, annotation secondary tables are used only if
- there is no <literal>secondary-table</literal> definition,
- annotations are ignored otherwise.</para>
- </callout>
-
- <callout arearefs="aa6">
- <para><literal>id-class</literal>: defines the id class in
a
- similar way <literal>@IdClass</literal> does</para>
- </callout>
-
- <callout arearefs="aa7">
- <para><literal>inheritance</literal>: defines the
inheritance
- strategy (<literal>JOINED</literal>,
- <literal>TABLE_PER_CLASS</literal>,
- <literal>SINGLE_TABLE</literal>), Available only at the root
- entity level</para>
- </callout>
-
- <callout arearefs="aa8">
- <para><literal>sequence-generator</literal>: defines a
sequence
- generator</para>
- </callout>
-
- <callout arearefs="aa9">
- <para><literal>table-generator</literal>: defines a table
- generator</para>
- </callout>
-
- <callout arearefs="aa10">
-
<para><literal><literal>primary-key-join-column</literal></literal>:
- defines the primary key join column for sub entities when JOINED
- inheritance strategy is used</para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <programlistingco>
- <areaspec>
- <area coords="11 85" id="ab1" />
-
- <area coords="18 85" id="ab2" />
-
- <area coords="22 85" id="ab3" />
-
- <area coords="28 85" id="ab4" />
-
- <area coords="34 85" id="ab5" />
- </areaspec>
-
- <programlisting><?xml version="1.0"
encoding="UTF-8"?>
-
-<entity-mappings
-
xmlns="http://java.sun.com/xml/ns/persistence/orm"
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
- version="1.0">
-
-
<package>org.hibernate.test.annotations.reflection</package>
- <entity class="Music" access="PROPERTY"
metadata-complete="true">
- <discriminator-value>Generic</discriminator-value>
- <discriminator-column length="34"/>
- ...
- </entity>
-
- <entity class="PostalAdministration">
- <primary-key-join-column name="id"/>
- <named-query name="adminById">
- <query>select m from Administration m where m.id =
:id</query>
- <hint name="org.hibernate.timeout"
value="200"/>
- </named-query>
- <named-native-query name="allAdmin"
result-set-mapping="adminrs">
- <query>select *, count(taxpayer_id) as taxPayerNumber
- from Administration, TaxPayer
- where taxpayer_admin_id = admin_id group by ...</query>
- <hint name="org.hibernate.timeout"
value="200"/>
- </named-native-query>
- <sql-result-set-mapping name="adminrs">
- <entity-result entity-class="Administration">
- <field-result name="name"
column="fld_name"/>
- </entity-result>
- <column-result name="taxPayerNumber"/>
- </sql-result-set-mapping>
- <attribute-override name="ground">
- <column name="fld_ground" unique="true"
scale="2"/>
- </attribute-override>
- <association-override name="referer">
- <join-column name="referer_id"
referenced-column-name="id"/>
- </association-override>
- ...
- </entity>
-</entity-mappings></programlisting>
-
- <calloutlist>
- <callout arearefs="ab1">
- <para><literal>discriminator-value /
- discriminator-column</literal>: defines the discriminator value
- and the column holding it when the SINGLE_TABLE inheritance
- strategy is chosen</para>
- </callout>
-
- <callout arearefs="ab2">
- <para><literal>named-query</literal>: defines named queries
and
- possibly the hints associated to them. Those definitions are
- additive to the one defined in annotations, if two definitions
- have the same name, the XML one has priority.</para>
- </callout>
-
- <callout arearefs="ab3">
- <para><literal>named-native-query</literal>: defines an
named
- native query and its sql result set mapping. Alternatively, you
- can define the <literal>result-class</literal>. Those
definitions
- are additive to the one defined in annotations, if two definitions
- have the same name, the XML one has priority.</para>
- </callout>
-
- <callout arearefs="ab4">
- <para><literal>sql-result-set-mapping</literal>: describes
the
- result set mapping structure. You can define both entity and
- column mappings. Those definitions are additive to the one defined
- in annotations, if two definitions have the same name, the XML one
- has priority</para>
- </callout>
-
- <callout arearefs="ab5">
- <para><literal>attribute-override /
- association-override</literal>: defines a column or join column
- overriding. This overriding is additive to the one defined in
- annotations</para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>Same applies for
<literal><embeddable></literal> and
- <literal><mapped-superclass></literal>.</para>
- </section>
-
- <section>
- <title>Property level metadata</title>
-
- <para>You can of course defines XML overriding for properties. If
- metadata complete is defined, then additional properties (ie at the Java
- level) will be ignored. Otherwise, once you start overriding a property,
- all annotations on the given property are ignored. All property level
- metadata behave in <literal>entity/attributes</literal>,
- <literal>mapped-superclass/attributes</literal> or
- <literal>embeddable/attributes</literal>.</para>
-
- <programlisting> <attributes>
- <id name="id">
- <column name="fld_id"/>
- <generated-value generator="generator"
strategy="SEQUENCE"/>
- <temporal>DATE</temporal>
- <sequence-generator name="generator"
sequence-name="seq"/>
- </id>
- <version name="version"/>
- <embedded name="embeddedObject">
- <attribute-override name"subproperty">
- <column name="my_column"/>
- </attribute-override>
- </embedded>
- <basic name="status" optional="false">
- <enumerated>STRING</enumerated>
- </basic>
- <basic name="serial" optional="true">
- <column name="serialbytes"/>
- <lob/>
- </basic>
- <basic name="terminusTime" fetch="LAZY">
- <temporal>TIMESTAMP</temporal>
- </basic>
- </attributes></programlisting>
-
- <para>You can override a property through <literal>id</literal>,
- <literal>embedded-id</literal>,
<literal>version</literal>,
- <literal>embedded</literal> and <literal>basic</literal>.
Each of these
- elements can have subelements accordingly: <literal>lob</literal>,
- <literal>temporal</literal>,
<literal>enumerated</literal>,
- <literal>column</literal>.</para>
- </section>
-
- <section>
- <title>Association level metadata</title>
-
- <para>You can define XML overriding for associations. All association
- level metadata behave in <literal>entity/attributes</literal>,
- <literal>mapped-superclass/attributes</literal> or
- <literal>embeddable/attributes</literal>.</para>
-
- <programlisting> <attributes>
- <one-to-many name="players" fetch="EAGER">
- <map-key name="name"/>
- <join-column name="driver"/>
- <join-column name="number"/>
- </one-to-many>
- <many-to-many name="roads"
target-entity="Administration">
- <order-by>maxSpeed</order-by>
- <join-table name="bus_road">
- <join-column name="driver"/>
- <join-column name="number"/>
- <inverse-join-column name="road_id"/>
- <unique-constraint>
- <column-name>driver</column-name>
- <column-name>number</column-name>
- </unique-constraint>
- </join-table>
- </many-to-many>
- <many-to-many name="allTimeDrivers"
mapped-by="drivenBuses">
- </attributes></programlisting>
-
- <para>You can override an association through
- <literal>one-to-many</literal>,
<literal>one-to-one</literal>,
- <literal>many-to-one</literal>, and
<literal>many-to-many</literal>.
- Each of these elements can have subelements accordingly:
- <literal>join-table</literal> (which can have
- <literal>join-column</literal>s and
- <literal>inverse-join-column</literal>s),
- <literal><literal>join-column</literal>s</literal>,
- <literal>map-key</literal>, and
<literal>order-by</literal>.
- <literal>mapped-by</literal> and
<literal>target-entity</literal> can be
- defined as attributes when it makes sense. Once again the structure is
- reflects the annotations structure. You can find all semantic
- informations in the chapter describing annotations.</para>
- </section>
- </section>
-</chapter>
\ No newline at end of file