openjpa/openjpa-project/src/doc/manual/ref_guide_pc.xml

2489 lines
108 KiB
XML
Raw Normal View History

<chapter id="ref_guide_pc">
<title>Persistent Classes</title>
<indexterm zone="ref_guide_pc">
<primary>persistent classes</primary>
</indexterm>
<para>
Persistent class basics are covered in
<xref linkend="jpa_overview_pc"/> of the JPA Overview.
This chapter details the persistent class features OpenJPA offers beyond the
core JPA specification.
</para>
<section id="ref_guide_pc_pcclasses">
<title>Persistent Class List</title>
<indexterm zone="ref_guide_pc_pcclasses">
<primary>persistent classes</primary>
<secondary>list</secondary>
</indexterm>
<indexterm zone="ref_guide_pc_pcclasses">
<primary>PCClasses</primary>
</indexterm>
<para>
Unlike many ORM products, OpenJPA does not need to know about all of your
persistent classes at startup. OpenJPA discovers new persistent classes
automatically as they are loaded into the JVM; in fact you can introduce
new persistent classes into running applications under OpenJPA. However,
there are certain situations in which providing OpenJPA with a persistent
class list is helpful:
</para>
<itemizedlist>
<listitem>
<para>
OpenJPA must be able to match entity names in JPQL queries to
persistent classes. OpenJPA automatically knows the entity names
of any persistent classes already loaded into the JVM. To match
entity names to classes that have not been loaded, however,
you must supply a persistent class list.
</para>
</listitem>
<listitem>
<para>
When OpenJPA manipulates classes in a persistent inheritance
hierarchy, OpenJPA must be aware of all the classes in the
hierarchy. If some of the classes have not been loaded into the
JVM yet, OpenJPA may not know about them, and queries may return
incorrect results.
</para>
</listitem>
<listitem>
<para>
If you configure OpenJPA to create the needed database schema
on startup (see <xref linkend="ref_guide_mapping_synch"/>),
OpenJPA must know all of your persistent classes up-front.
</para>
</listitem>
</itemizedlist>
<para>
When any of these conditions are a factor in your JPA
application, use the <literal>class</literal>, <literal>
mapping-file</literal>, and <literal>jar-file</literal> elements of
JPA's standard XML format to list your
persistent classes. See
<xref linkend="jpa_overview_persistence_xml"/> for details.
</para>
<note>
<para>
Listing persistent classes (or their metadata or jar files) is an
all-or-nothing endeavor. If your persistent class list is
non-empty, OpenJPA will assume that any unlisted class is not
persistent.
</para>
</note>
</section>
<section id="ref_guide_pc_enhance">
<title>Enhancement</title>
<indexterm zone="ref_guide_pc_enhance">
<primary>enhancer</primary>
</indexterm>
<indexterm>
<primary>openjpac</primary>
<see>enhancer</see>
</indexterm>
<para>
In order to provide optimal runtime performance, flexible lazy loading,
and efficient, immediate dirty tracking, OpenJPA uses an <emphasis>
enhancer</emphasis>. An enhancer is a tool that automatically adds
code to your persistent classes after you have written them.
The enhancer post-processes the bytecode generated by your Java
compiler, adding the necessary fields and methods to implement the
required persistence features. This bytecode modification perfectly
preserves the line numbers in stack traces and is compatible with Java
debuggers.
<phrase>
In fact, the only change to debugging is that the persistent setter
and getter methods of entity classes using property access will be
prefixed with <literal>pc</literal> in stack traces and
step-throughs.
For example, if your entity has a <methodname>getId</methodname> method
for persistent property <literal>id</literal>, and that method throws
an exception, the stack trace will report the exception from method
<methodname>pcgetId</methodname>. The line numbers, however, will
correctly correspond to the <methodname>getId</methodname> method
in your source file.
</phrase>
</para>
<mediaobject>
<imageobject>
<!-- PNG image data, 509 x 133 (see README) -->
<imagedata fileref="img/enhancement.png" width="339px"/>
</imageobject>
</mediaobject>
<para>
The diagram above illustrates the compilation of a persistent class.
</para>
<para>
You can add the OpenJPA enhancer to your build process,
or use Java 1.5's new instrumentation features to transparently enhance
persistent classes when they are loaded into the JVM. The following
sections describe each option.
</para>
<section id="ref_guide_pc_enhance_build">
<title>Enhancing at Build Time</title>
<indexterm zone="ref_guide_pc_enhance_build">
<primary>enhancer</primary>
<secondary>build time</secondary>
</indexterm>
<para>
The enhancer can be invoked at build time via the
included <literal>openjpac</literal> script or via its Java class,
<classname>org.apache.openjpa.enhance.PCEnhancer</classname>.
</para>
<note>
<para>
You can also enhance via Ant; see
<xref linkend="ref_guide_integration_enhance"/>.
</para>
</note>
<example id="ref_guide_pc_enhance_enhancer">
<title>Using the OpenJPA Enhancer</title>
<programlisting format="linespecific">
openjpac Magazine.java
</programlisting>
</example>
<para>
The enhancer accepts the standard set of command-line arguments
defined by the configuration framework
(see <xref linkend="ref_guide_conf_devtools"/>), along with the
following flags:
</para>
<itemizedlist>
<listitem>
<para><literal>-directory/-d &lt;output directory&gt;</literal>:
Path to the output directory. If the directory does not
match the enhanced class' package, the package structure
will be created beneath the directory. By default, the
enhancer overwrites the original <filename>.class</filename>
file.
</para>
</listitem>
<listitem>
<para><literal>-enforcePropertyRestrictions/-epr &lt;true/t |
false/f&gt;</literal>: Whether to throw an exception when
it appears that a property access entity is not obeying the
restrictions placed on property access. Defaults to false.
</para>
</listitem>
<listitem>
<para><literal>-addDefaultConstructor/-adc &lt;true/t
| false/f&gt;</literal>: The spec requires that all
persistent classes define a no-arg constructor. This flag
tells the enhancer whether to add a protected no-arg
constructor to any persistent classes that don't already
have one. Defaults to <literal>true</literal>.
</para>
</listitem>
<listitem>
<para><literal>-tmpClassLoader/-tcl &lt;true/t
| false/f&gt;</literal>: Whether to load persistent classes
with a temporary class loader. This allows other code to
then load the enhanced version of the class within the same
JVM. Defaults to <literal>true</literal>. Try setting
this flag to <literal>false</literal> as a debugging step
if you run into class loading problems when running the
enhancer.
</para>
</listitem>
</itemizedlist>
<para>
Each additional argument to the enhancer must be one of the
following:
</para>
<itemizedlist>
<listitem>
<para>The full name of a class.</para>
</listitem>
<listitem>
<para>The .java file for a class.</para>
</listitem>
<listitem>
<para>
The <filename>.class</filename> file of a class.
</para>
</listitem>
</itemizedlist>
<para>
If you do not supply any arguments to the enhancer, it will run on
the classes in your persistent class list (see
<xref linkend="ref_guide_pc_pcclasses"/>).
</para>
<para>
You can run the enhancer over classes that have already been
enhanced, in which case it will not further modify the class. You
can also run it over classes that are not persistence-capable, in
which case it will treat the class as persistence-aware.
Persistence-aware classes can directly manipulate the persistent
fields of persistence-capable classes.
</para>
<para>
Note that the enhancement process for subclasses introduces
dependencies on the persistent parent class being enhanced. This
is normally not problematic; however, when running the enhancer
multiple times over a subclass whose parent class is not yet
enhanced, class loading errors can occur. In the event of a class
load error, simply re-compile and re-enhance the offending classes.
</para>
</section>
<section id="ref_guide_pc_enhance_runtime_container">
<title>Enhancing JPA Entities on Deployment</title>
<indexterm zone="ref_guide_pc_enhance_runtime_container">
<primary>enhancer</primary>
<secondary>runtime</secondary>
<tertiary>in an EJB container</tertiary>
</indexterm>
<para>
The JEE 5 specification includes hooks to automatically enhance
JPA entities when they are deployed into a container. Thus, if you
are using a JEE 5-compliant application server, OpenJPA will enhance
your entities automatically at runtime. Note that if you prefer
build-time enhancement, OpenJPA's runtime enhancer will correctly
recognize and skip pre-enhanced classes.
</para>
<para>
If your application server does not support the JEE 5 enhancement
hooks, consider using the build-time enhancement described above,
or the more general runtime enhancement described in the next
section.
</para>
</section>
<section id="ref_guide_pc_enhance_runtime">
<title>Enhancing at Runtime</title>
<indexterm zone="ref_guide_pc_enhance_runtime">
<primary>enhancer</primary>
<secondary>runtime</secondary>
<tertiary>outside a container</tertiary>
</indexterm>
<para>
OpenJPA includes a <emphasis>Java agent</emphasis> for automatically
enhancing persistent classes as they are loaded into the JVM.
Java agents are classes that are invoked prior to your application's
<methodname>main</methodname> method. OpenJPA's agent uses JVM
hooks to intercept all class loading to enhance classes that
have persistence metadata before the JVM loads them.
</para>
<note>
<para>
Java agents are new to Java 5;
if you are using a previous Java version, you must use OpenJPA's
<link linkend="ref_guide_pc_enhance_build">build-time
enhancement</link> option.
</para>
</note>
<para>
Searching for metadata for every class loaded by the JVM can slow
application initialization. One way to speed things up is to
take advantage of the optional persistent class list described in
<xref linkend="ref_guide_pc_pcclasses"/>. If you declare a
persistent class list, OpenJPA will only search for metadata for
classes in that list.
</para>
<para>
To employ the OpenJPA agent, invoke <literal>java</literal> with the
<literal>-javaagent</literal> set to the path to your
<filename>org.apache.openjpa.jar</filename> or
<filename>openjpa-runtime.jar</filename> file.
</para>
<example id="ref_guide_pc_enhance_runtime_ex">
<title>Using the OpenJPA Agent for Runtime Enhancement</title>
<programlisting format="linespecific">
java -javaagent:/home/dev/openjpa/lib/org.apache.openjpa.jar com.xyz.Main
</programlisting>
</example>
<para>
You can pass settings to the agent using OpenJPA's plugin syntax
(see <xref linkend="ref_guide_conf_plugins"/>). The agent accepts
the long form of any of the standard configuration options
(<xref linkend="ref_guide_conf_devtools"/>). It also accepts the
following options, the first three of which correspond exactly to
to the same-named options of the enhancer tool described in
<xref linkend="ref_guide_pc_enhance_build"/>:
</para>
<itemizedlist>
<listitem>
<para>
<literal>addDefaultConstructor</literal>
</para>
</listitem>
<listitem>
<para>
<literal>jdoEnhance</literal>
</para>
</listitem>
<listitem>
<para>
<literal>enforcePropertyRestrictions</literal>
</para>
</listitem>
<listitem>
<para><literal>scanDevPath</literal>: Boolean indicating whether
to scan the classpath for persistent types if none have
been configured. If you do not specify a persistent types
list and do not set this option to true, OpenJPA will check
whether each class loaded into the JVM is persistent, and
enhance it accordingly. This may slow down class load times
significantly.
</para>
</listitem>
</itemizedlist>
<example id="ref_guide_pc_enhance_runtime_opt_ex">
<title>Passing Options to the OpenJPA Agent</title>
<programlisting format="linespecific">
java -javaagent:/home/dev/openjpa/lib/org.apache.openjpa.jar=jdoEnhance=true,addDefaultConstructor=false com.xyz.Main
</programlisting>
</example>
</section>
<section id="ref_guide_pc_enhance_sercompat">
<title>Serializing Enhanced Types</title>
<indexterm zone="ref_guide_pc_enhance_sercompat">
<primary>enhancer</primary>
<secondary>serialization</secondary>
<tertiary>of enhanced types</tertiary>
</indexterm>
<indexterm zone="ref_guide_pc_enhance_sercompat">
<primary>serialization</primary>
<secondary>of enhanced types</secondary>
</indexterm>
<para>
By default, OpenJPA maintains serialization compatibility
between the enhanced and unenhanced versions of a class. This
allows you to serialize instances between a server using OpenJPA and
a client that does not have access to enhanced classes or OpenJPA
libraries. In some cases, however, you can make the persist and
attach processes more robust and efficient by allowing breaks in
serialization compatibility. See
<xref linkend="ref_guide_detach_graph"/> for details.
</para>
</section>
</section>
<!-- ### proxy
<section id="ref_guide_pc_prop">
<title>Restrictions on Property Access Types</title>
<indexterm zone="ref_guide_pc_prop">
<primary>persistent classes</primary>
<secondary>property access restrictions</secondary>
</indexterm>
<indexterm zone="ref_guide_pc_prop">
<primary>property access</primary>
<secondary>restrictions</secondary>
</indexterm>
<para>
The JPA Overview explains the choice between property and
field access for your entities and embeddable types in
<xref linkend="jpa_overview_meta"/>. As you saw in the previous
section, OpenJPA uses an <emphasis>enhancer</emphasis> to transparently
intercept operations on persistent state in field access classes. For
property access classes, however, OpenJPA uses a different strategy. OpenJPA
generates dynamic subclasses of your persistent classes at runtime.
These subclasses override your persistent property "getter" and
"setter" methods to control the loading and dirtying of persistent
state.
</para>
<para>
Any time you look up an entity by id, merge an entity, or retrieve an
entity by query, OpenJPA returns an instance of the entity's
dynamically-generated subclass. When you persist new entities,
however, you typically create them with the Java <literal>new</literal>
operator, then pass them to
<ulink url="&ejb-javadoc-dir;/javax/persistence/EntityManager.html">
<methodname>EntityManager.persist</methodname></ulink>. Obviously,
these entities are not subclassed. We must therefore consider two
categories of restrictions on property access entities: general
restrictions that allow your class to be dynamically subclassed by OpenJPA,
and special restrictions on non-subclassed instances you have created
with the <literal>new</literal> operator.
</para>
<section id="ref_guide_pc_prop_sub">
<title>General Restrictions</title>
<para>
<xref linkend="jpa_overview_pc"/> of the JPA Overview
covers the restrictions imposed on persistent classes by the
JPA specification. In order for dynamic subclassing
to work properly, your property access entities and
embeddable types must obey those restrictions, as well as the
following additions:
</para>
<orderedlist>
<listitem>
<para>
<emphasis role="bold">Use <literal>
instanceof</literal>.</emphasis> Because OpenJPA will return
instances of dynamically-generated subclasses, comparisons
on <classname>Class</classname> objects may fail. Use
the <literal>instanceof</literal> operator instead when
testing for specific persistent types.
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">Define <literal>public</literal>
or <literal>protected</literal> methods.</emphasis>
OpenJPA's subclass must be able to override your persistent
property accessor and mutator methods.
</para>
</listitem>
<listitem>
<para>
<emphasis role="bold">Do not access persistent fields
directly.</emphasis> The OpenJPA runtime relies on getter
and setter method invocations to detect state access.
Thus, outside of your getter and setter methods themselves,
you should not manipulate persistent fields directly. This
restriction applies not only to access from outside
code, but also to access from within the business methods
of your entity class. All manipulation of persistent
state must go through your getter and setter methods.
</para>
</listitem>
</orderedlist>
</section>
<section id="ref_guide_pc_prop_new">
<title>Restrictions on New Instances</title>
<para>
Non-subclassed property access objects do not afford OpenJPA any
opportunities to intercept persistent state manipulation or store
additional bookkeeping information in the object itself. This is
not normally problematic, but does limit the use of these
objects in an extended persistence context (see
<xref linkend="jpa_overview_emfactory_perscontext"/>).
</para>
<itemizedlist>
<listitem>
<para>
New instances using OpenJPA's datastore identity feature
(see <xref linkend="ref_guide_pc_oid"/> below) that become
detached cannot be merged. OpenJPA has no place to store the
datastore identity value in the non-subclassed detached
instance, so the object's identity is lost.
</para>
</listitem>
<listitem>
<para>
New instances without a
<link linkend="jpa_overview_meta_version">version field
</link> must use a <link linkend="jpa_overview_meta_id">
<literal>generate</literal> strategy</link> other than
<literal>GeneratorType.NONE</literal> for at least one
primary key field to be merged after being detached.
Otherwise, OpenJPA has no criteria with which to differentiate
a detached object from a new one.
</para>
</listitem>
<listitem>
<para>
OpenJPA typically detects attempts to read an auto-assigned
field in a new instance. OpenJPA generates the value or
flushes to the database transparently on access.
OpenJPA cannot detect state reads in non-subclassed property
access classes, however. Thus,
reading an auto-assigned property will return its
Java default value until you flush or commit.
</para>
</listitem>
<listitem>
<para>
If you continue using a property access object created with
<literal>new</literal> in subsequent transactions of an
extended persistence context, OpenJPA will not be able to
lazy-load its state. On boundaries where OpenJPA would
normally clear state (such as when entering a non-optimistic
transaction), OpenJPA will clear, then immediately re-load
all data. Because OpenJPA cannot detect state manipulation
on a non-subclassed instance, this is the only way to ensure
that all properties have the correct values should you
access them.
</para>
</listitem>
</itemizedlist>
<para>
If you find yourself running up against these limitations in
practice, consider using field access, or taking advantage of the
<ulink url="&javadoc-dir;/openjpa/persistence/OpenJPAEntityManager.html">
<classname>OpenJPAEntityManager</classname></ulink>, OpenJPA's
extended <classname>EntityManager</classname> interface:
</para>
<programlisting>
public &lt;T> T createInstance (Class&lt;T> cls);
</programlisting>
<para>
The <classname>OpenJPAEntityManager</classname>'s
<literal>createInstance</literal> method acts as a factory for
entity and embeddable types.
When the given class uses property access, it returns a generated
subclass instance. This instance is not subject to the
limitations of objects created with <literal>new</literal>.
</para>
</section>
</section>
-->
<section id="ref_guide_pc_oid">
<title>Object Identity</title>
<indexterm zone="ref_guide_pc_oid">
<primary>identity</primary>
</indexterm>
<para>
The JPA specification requires you to declare one or more
identity fields in your persistent classes. OpenJPA fully supports
this form of object identity, called <emphasis>application</emphasis>
identity. OpenJPA, however, also supports <emphasis>datastore</emphasis>
identity. In datastore identity, you do not declare any primary key
fields. OpenJPA manages the identity of your persistent objects for
you through a surrogate key in the database.
</para>
<para>
You can control how your JPA datastore identity value is generated
through OpenJPA's
<ulink url="../apidocs/org/apache/openjpa/persistence/DataStoreId.html"><classname>org.apache.openjpa.persistence.DataStoreId</classname></ulink> class
annotation. This annotation has <literal>strategy</literal> and
<literal>generator</literal> properties that mirror the same-named
properties on the standard <classname>javax.persistence.GeneratedValue
</classname> annotation described in
<xref linkend="jpa_overview_meta_id"/> of the JPA Overview.
</para>
<para>
To retrieve the identity value of a datastore identity entity, use the
<methodname>OpenJPAEntityManager.getObjectId (Object entity)
</methodname> method. See
<xref linkend="ref_guide_runtime_em"/>
for more information on the <classname>OpenJPAEntityManager</classname>.
</para>
<example id="ref_guide_pc_oid_datastoreentityex">
<title>JPA Datastore Identity Metadata</title>
<programlisting format="linespecific">
import org.apache.openjpa.persistence.*;
@Entity
@DataStoreId
public class LineItem
{
... no @Id fields declared ...
}
</programlisting>
</example>
<section id="ref_guide_pc_oid_datastore">
<title>Datastore Identity Objects</title>
<indexterm zone="ref_guide_pc_oid">
<primary>identity</primary>
<secondary>datastore</secondary>
</indexterm>
<para>
Internally, OpenJPA uses the public
<ulink url="../apidocs/org/apache/openjpa/util/Id.html"><classname>org.apache.openjpa.util.Id
</classname></ulink> class for datastore identity objects. When
writing OpenJPA plugins, you can manipulate datastore identity objects
by casting them to this class. You can also create your own
<classname>Id</classname> instances and pass them to any internal
OpenJPA method that expects an identity object.
</para>
<para>
In JPA, you will never see <classname>Id</classname> instances
directly. Instead, calling <classname>OpenJPAEntityManager.getObjectId
</classname> on a datastore identity object will return the
<classname>Long</classname> surrogate primary key value for that
object. You can then use this value in calls to
<classname>EntityManager.find</classname> for subsequent lookups
of the same record.
</para>
</section>
<section id="ref_guide_pc_oid_application">
<title>Application Identity Tool</title>
<indexterm zone="ref_guide_pc_oid_application">
<primary>identity</primary>
<secondary>application</secondary>
<tertiary>application identity tool</tertiary>
</indexterm>
<indexterm zone="ref_guide_pc_oid_application">
<primary>application identity tool</primary>
</indexterm>
<para>
If you choose to use application identity, you may want to take
advantage of OpenJPA <phrase>JPA</phrase>'s application identity tool.
The application identity tool generates Java code implementing the
identity class for any persistent type using application
identity. The code satisfies all the requirements the specification
places on identity classes. You can use it as-is, or simply use it
as a starting point, editing it to meet your needs.
</para>
<para>
Before you can run the application identity tool on a persistent
class, the class must be compiled and must have complete
metadata. All primary key fields must be marked as such in the
metadata.
</para>
<para>
In JPA metadata, do not attempt to specify the
<literal>@IdClass</literal> annotation unless you are using the
application identity tool to overwrite an existing identity class.
Attempting to set the value of the <literal>@IdClass</literal> to
a non-existent class will prevent your persistent class from
compiling. Instead, use the <literal>-name</literal> or
<literal>-suffix</literal> options described below to tell OpenJPA
what name to give your generated identity class. Once the
application identity tool has generated the class code, you can
set the <literal>@IdClass</literal> annotation.
</para>
<para>
The application identity tool can be invoked via the included
<literal>appidtool</literal> shell/bat script or via its Java class,
<ulink url="../apidocs/org/apache/openjpa/enhance/ApplicationIdTool"><classname>org.apache.openjpa.enhance.ApplicationIdTool</classname></ulink>.
</para>
<note>
<para><xref linkend="ref_guide_integration_appidtool"/> describes
the application identity tool's Ant task.
</para>
</note>
<example id="ref_guide_pc_appid_appidtool">
<title>Using the Application Identity Tool</title>
<programlisting format="linespecific">
appidtool -s Id Magazine.java
</programlisting>
</example>
<para>
The application identity tool accepts the standard set of
command-line arguments defined by the configuration framework
(see <xref linkend="ref_guide_conf_devtools"/>),
including code formatting flags described in
<xref linkend="ref_guide_conf_devtools_format"/>.
It also accepts the following arguments:
</para>
<itemizedlist>
<listitem>
<para><literal>-directory/-d &lt;output directory&gt;</literal>:
Path to the output directory. If the directory does not
match the generated oid class' package, the package
structure will be created beneath the directory. If not
specified, the tool will first try to find the directory of
the <filename>.java</filename> file for the
persistence-capable class, and failing that will use the
current directory.
</para>
</listitem>
<listitem>
<para><literal>-ignoreErrors/-i &lt;true/t | false/f&gt;
</literal>: If <literal>false</literal>, an exception will
be thrown if the tool is run on any class that does not
use application identity, or is not the base class in the
inheritance hierarchy (recall that subclasses never define
the application identity class; they inherit it from their
persistent superclass).
</para>
</listitem>
<listitem>
<para><literal>-token/-t &lt;token&gt;</literal>: The token
to use to separate stringified primary key values in the
string form of the object id. This option is only used
if you have multiple primary key fields. It defaults to
"::".
</para>
</listitem>
<listitem>
<para><literal>-name/-n &lt;id class name&gt;</literal>: The name
of the identity class to generate. If this option is
specified, you must run the tool on exactly one class.
If the class metadata already names an object id class,
this option is ignored. If the name is not fully qualified,
the persistent class' package is prepended to form the
qualified name.
</para>
</listitem>
<listitem>
<para><literal>-suffix/-s &lt;id class suffix&gt;</literal>: A
string to suffix each persistent class name with to form
the identity class name. This option is overridden by
<literal>-name</literal> or by any object id class specified
in metadata.
</para>
</listitem>
</itemizedlist>
<para>
Each additional argument to the tool must be one of the following:
</para>
<itemizedlist>
<listitem>
<para>The full name of a persistent class.</para>
</listitem>
<listitem>
<para>The .java file for a persistent class.</para>
</listitem>
<listitem>
<para>
The <filename>.class</filename> file of a persistent class.
</para>
</listitem>
</itemizedlist>
<para>
If you do not supply any arguments to the tool, it will act on the
classes in your persistent classes list (see
<xref linkend="ref_guide_pc_pcclasses"/>).
</para>
</section>
<section id="ref_guide_pc_oid_pkgen_autoinc">
<title>Autoassign / Identity Strategy Caveats</title>
<indexterm zone="ref_guide_pc_oid_pkgen_autoinc">
<primary>datastore identity</primary>
<secondary>autoassign strategy</secondary>
</indexterm>
<indexterm zone="ref_guide_pc_oid_pkgen_autoinc">
<primary>datastore identity</primary>
<secondary>autoassign strategy</secondary>
</indexterm>
<indexterm zone="ref_guide_pc_oid_pkgen_autoinc">
<primary>persistent fields</primary>
<secondary>autoassign strategy</secondary>
</indexterm>
<para><xref linkend="jpa_overview_meta_gen"/> explains how to use JPA's
<literal>IDENTITY</literal> generation type to automatically assign
field values. However, here are some additional caveats you
should be aware of when using <literal>IDENTITY</literal>
generation:
</para>
<orderedlist>
<listitem>
<para>
Your database must support auto-increment / identity
columns, or some equivalent (see
<xref linkend="ref_guide_dbsetup_dbsupport_oracle"/> for
how to configure a combination of triggers and sequences to
fake auto-increment support in Oracle).
</para>
</listitem>
<listitem>
<para>
Auto-increment / identity columns must be an integer or
long integer type.
</para>
</listitem>
<listitem>
<para>
Databases support auto-increment / identity columns
to varying degrees. Some do not support them at all.
Others only allow a single such column per
table, and require that it be the primary key column.
More lenient databases may allow non-primary key
auto-increment columns, and may allow more than one
per table. See your database documentation for
details.
</para>
</listitem>
<listitem>
<para>
Statements inserting into tables with auto-increment
/ identity columns cannot be batched. After each insert,
OpenJPA must go back to the database to retrieve the last
inserted auto-increment value to set back in the
persistent object. This can have a negative
impact on performance.
</para>
</listitem>
</orderedlist>
</section>
</section>
<section id="ref_guide_inverses">
<title>Managed Inverses</title>
<indexterm zone="ref_guide_inverses">
<primary>bidirectional relations</primary>
<secondary>automatic management</secondary>
</indexterm>
<para>
Bidirectional relations are an essential part of data modeling.
<xref linkend="jpa_overview_mapping"/> in the JPA Overview
explains how to use the <literal>mappedBy</literal> annotation attribute
to form bidirectional relations that also share datastore storage
in JPA.
</para>
<para>
OpenJPA also allows you to define purely logical bidirectional
relations.
<phrase>
The <ulink url="../apidocs/org/apache/openjpa/persistence/InverseLogical.html"><classname>org.apache.openjpa.persistence.InverseLogical</classname></ulink>
annotation names a logical inverse in JPA metadata.
</phrase>
</para>
<example id="ref_guide_inverses_logicalex">
<title>Specifying Logical Inverses</title>
<para><literal>Magazine.coverPhoto</literal> and <literal>Photograph.mag
</literal> are each mapped to different foreign keys in their
respective tables, but form a logical bidirectional relation. Only
one of the fields needs to declare the other as its logical inverse,
though it is not an error to set the logical inverse of both fields.
</para>
<programlisting format="linespecific">
import org.apache.openjpa.persistence.*;
@Entity
public class Magazine
{
@OneToOne
private Photograph coverPhoto;
...
}
@Entity
public class Photograph
{
@OneToOne
@InverseLogical("coverPhoto")
private Magazine mag;
...
}
</programlisting>
<programlisting format="linespecific">
&lt;class name="Magazine"&gt;
&lt;field name="coverPhoto"/&gt;
...
&lt;/class&gt;
&lt;class name="Photograph"&gt;
&lt;field name="mag"&gt;
&lt;extension vendor-name="openjpa" key="inverse-logical" value="coverPhoto"/&gt;
&lt;/field&gt;
...
&lt;/class&gt;
</programlisting>
</example>
<para>
Java does not provide any native facilities to ensure that both sides
of a bidirectional relation remain consistent.
Whenever you set one side of the relation, you must manually set the
other side as well.
</para>
<para>
By default, OpenJPA behaves the same way. OpenJPA does not automatically
propagate changes from one field in bidirectional relation to the other
field. This is in keeping with the philosophy of transparency, and
also provides higher performance, as OpenJPA does not need to analyze
your object graph to correct inconsistent relations.
</para>
<para><indexterm><primary>InverseManager</primary></indexterm>
If convenience is more important to you than strict transparency,
however, you can enable inverse relation management in OpenJPA.
Set the <link linkend="openjpa.InverseManager"><classname>openjpa.InverseManager</classname></link> plugin property to
<literal>true</literal> for standard management. Under this setting,
OpenJPA detects changes to either side of a bidirectional relation (logical
or physical), and automatically sets the other side appropriately on
flush.
</para>
<example id="ref_guide_inversesex">
<title>Enabling Managed Inverses</title>
<programlisting format="linespecific">
&lt;property name="openjpa.InverseManager" value="true"/&gt;
</programlisting>
</example>
<para>
The inverse manager has options to log a warning or throw an exception
when it detects an inconsistent bidirectional relation, rather than
correcting it. To use these modes, set the manager's <literal>Action
</literal> property to <literal>warn</literal> or
<literal>exception</literal>, respectively.
</para>
<para>
By default, OpenJPA excludes <link linkend="ref_guide_pc_scos_proxy_lrs">
large result set fields</link> from management. You can force
large result set fields to be included by setting the
<literal>ManageLRS</literal> plugin property to <literal>true</literal>.
</para>
<example id="ref_guide_inverses_logex">
<title>Log Inconsistencies</title>
<programlisting format="linespecific">
&lt;property name="openjpa.InverseManager" value="true(Action=warn)"/&gt;
</programlisting>
</example>
</section>
<section id="ref_guide_pc_scos">
<title>Persistent Fields</title>
<indexterm zone="ref_guide_pc_scos">
<primary>persistent fields</primary>
</indexterm>
<para>
OpenJPA enhances the specification's support for persistent
fields in many ways. This section documents aspects of OpenJPA's
persistent field handling that may affect the way you design your
persistent classes.
</para>
<section id="ref_guide_pc_scos_restore">
<title>Restoring State</title>
<indexterm zone="ref_guide_pc_scos">
<primary>persistent fields</primary>
<secondary>field rollback</secondary>
</indexterm>
<indexterm zone="ref_guide_pc_scos_restore">
<primary>RestoreState</primary>
</indexterm>
<para>
While the JPA specification says that you should not use rolled
back objects, such objects are perfectly valid in OpenJPA. You can
control whether the objects' managed state is rolled back to its
pre-transaction values with the <link linkend="openjpa.RestoreState"><literal>openjpa.RestoreState</literal></link> configuration property.
<literal>none</literal> does not roll back state (the object
becomes hollow, and will re-load its state the next time it
is accessed), <literal>immutable</literal> restores immutable values
(primitives, primitive wrappers, strings) and clears mutable values
so that they are reloaded on next access, and <literal>all</literal>
restores all managed values to their pre-transaction state.
</para>
</section>
<section id="ref_guide_pc_scos_order">
<title>Typing and Ordering</title>
<indexterm zone="ref_guide_pc_scos_order">
<primary>persistent fields</primary>
<secondary>comparators</secondary>
</indexterm>
<para>
When loading data into a field, OpenJPA examines the value you assign
the field in your declaration code or in your no-args constructor.
If the field value's type is more specific than the field's
declared type, OpenJPA uses the value type to hold the loaded data.
OpenJPA also uses the comparator you've initialized the field with, if
any. Therefore, you can use custom comparators on your persistent
field simply by setting up the comparator and using it in your
field's initial value.
</para>
<example id="ref_guide_pc_scos_order_initialvals">
<title>Using Initial Field Values</title>
<para>
Though the annotations are left out for simplicity, assume
<literal>employeesBySal</literal> and
<literal>departments</literal> are persistent fields in the
class below.
</para>
<programlisting format="linespecific">
public class Company
{
// OpenJPA will detect the custom comparator in the initial field value
// and use it whenever loading data from the database into this field
private Collection employeesBySal = new TreeSet (new SalaryComparator ());
private Map departments;
public Company
{
// or we can initialize fields in our no-args constructor; even though
// this field is declared type Map, OpenJPA will detect that it's actually
// a TreeMap and use natural ordering for loaded data
departments = new TreeMap ();
}
// rest of class definition...
}
</programlisting>
</example>
</section>
<section id="ref_guide_pc_calendar_timezone">
<title>Calendar Fields and TimeZones</title>
<indexterm zone="ref_guide_pc_calendar_timezone">
<primary>persistent fields</primary>
<secondary>calendar</secondary>
</indexterm>
<para>
OpenJPA's support for the <classname>java.util.Calendar</classname>
type will store only the <classname>Date</classname> part of the
field, not the <classname>TimeZone</classname> associated with the
field. When loading the date into the <classname>Calendar
</classname> field, OpenJPA will use the <classname>TimeZone
</classname> that was used to initialize the field.
</para>
<note>
<para>
OpenJPA will automatically track changes made via modification
methods in fields of type
<classname>Calendar</classname>, with one exception:
when using Java version 1.3, the <methodname>set()</methodname>
method cannot be overridden, so when altering the calendar
using that method, the field must be explicitly marked
as dirty. This limitation does not apply when running with
Java version 1.4 and higer.
</para>
</note>
</section>
<section id="ref_guide_pc_scos_proxy">
<title>Proxies</title>
<indexterm zone="ref_guide_pc_scos_proxy">
<primary>proxies</primary>
</indexterm>
<indexterm>
<primary>persistent fields</primary>
<secondary>proxies</secondary>
<see>proxies</see>
</indexterm>
<para>
At runtime, the values of all mutable second class object fields
in persistent and transactional objects are replaced with
implementation-specific proxies. On modification, these proxies
notify their owning instance that they have been changed, so that
the appropriate updates can be made on the datastore.
</para>
<section id="ref_guide_pc_scos_proxy_smart">
<title>Smart Proxies</title>
<indexterm zone="ref_guide_pc_scos_proxy_smart">
<primary>proxies</primary>
<secondary>smart</secondary>
</indexterm>
<para>
Most proxies only track whether or not they have been modified.
Smart proxies for collection and map fields, however, keep a
record of which elements have been added, removed, and changed.
This record enables the OpenJPA runtime to make more efficient
database updates on these fields.
</para>
<para>
When designing your persistent classes, keep in mind that
you can optimize for OpenJPA smart proxies by using fields of type
<classname>java.util.Set</classname>,
<classname>java.util.TreeSet</classname>, and
<classname>java.util.HashSet</classname> for your collections
whenever possible. Smart proxies for these types are more
efficient than proxies for <classname>List</classname>s. You
can also design your own smart proxies to further optimize OpenJPA
for your usage patterns. See the section on
<link linkend="ref_guide_pc_scos_proxy_custom">custom proxies
</link> for details.
</para>
</section>
<section id="ref_guide_pc_scos_proxy_lrs">
<title>Large Result Set Proxies</title>
<indexterm zone="ref_guide_pc_scos_proxy_lrs">
<primary>proxies</primary>
<secondary>large result set</secondary>
</indexterm>
<indexterm zone="ref_guide_pc_scos_proxy_lrs">
<primary>large result sets</primary>
<secondary>fields</secondary>
</indexterm>
<para>
Under standard ORM behavior, traversing a persistent collection
or map field brings the entire contents of that field into
memory. Some persistent fields, however, might represent
huge amounts of data, to the point that attempting to fully
instantiate them can overwhelm the JVM or seriously degrade
performance.
</para>
<para>
OpenJPA uses special proxy types to represent these "large result
set" fields. OpenJPA's large result set proxies do not cache
any data in memory. Instead, each operation on the proxy
offloads the work to the database and returns the proper result.
For example, the <methodname>contains</methodname> method
of a large result set collection will perform a <literal>
SELECT COUNT(*)</literal> query with the proper <literal>WHERE
</literal> conditions to find out if the given element exists
in the database's
record of the collection. Similarly, each time you obtain
an iterator OpenJPA performs the proper query using the current
<link linkend="ref_guide_dbsetup_lrs">
large result set settings</link>, as discussed in the
<link linkend="ref_guide_dbsetup">JDBC</link> chapter. As you
invoke <methodname>Iterator.next</methodname>, OpenJPA
instantiates the result objects on-demand.
</para>
<para>
You can free the resources used by a large result set iterator
by passing it to the static
<link linkend="ref_guide_runtime_openjpapersistence"><methodname>OpenJPAPersistence.close</methodname></link> method.
</para>
<example id="ref_guide_pc_scos_proxy_lrs_itr">
<title>Using a Large Result Set Iterator</title>
<programlisting format="linespecific">
import org.apache.openjpa.persistence.*;
...
Collection employees = company.getEmployees (); // employees is a lrs collection
Iterator itr = employees.iterator ();
while (itr.hasNext ())
process ((Employee) itr.next ());
OpenJPAPersistence.close (itr);
</programlisting>
</example>
<para>
You can also add and remove from large result set proxies, just
as with standard fields. OpenJPA keeps a record of all changes
to the elements of the proxy, which it uses to make sure
the proper results are always returned from collection and
map methods, and to update the field's database record on
commit.
</para>
<para>
<phrase>
In order to use large result set proxies in JPA, add the
<ulink url="../apidocs/org/apache/openjpa/persistence/LRS.html"><classname>
org.apache.openjpa.persistence.LRS</classname></ulink> annotation to the
persistent field.
</phrase>
</para>
<para>
The following restrictions apply to large result set fields:
</para>
<itemizedlist>
<listitem>
<para>
The field must be declared as either a
<classname>java.util.Collection</classname> or
<classname>java.util.Map</classname>. It cannot be
declared as any other type, including any sub-interface
of collection or map, or any concrete collection or map
class.
</para>
</listitem>
<listitem>
<para>
The field cannot have an externalizer
(see <xref linkend="ref_guide_pc_extern"/>).
</para>
</listitem>
<listitem>
<para>
Because they rely on their owning object for context,
large result set proxies cannot be transferred from one
persistent field to another. The following code would
result in an error on commit:
</para>
<programlisting format="linespecific">
Collection employees = company.getEmployees () // employees is a lrs collection
company.setEmployees (null);
anotherCompany.setEmployees (employees);
</programlisting>
</listitem>
</itemizedlist>
<example id="ref_guide_pc_scos_proxy_lrs_extension">
<title>Marking a Large Result Set Field</title>
<programlisting format="linespecific">
import org.apache.openjpa.persistence.*;
@Entity
public class Company
{
@ManyToMany
@LRS private Collection&lt;Employee&gt; employees;
...
}
</programlisting>
</example>
</section>
<section id="ref_guide_pc_scos_proxy_custom">
<title>Custom Proxies</title>
<indexterm zone="ref_guide_pc_scos_proxy_custom">
<primary>proxies</primary>
<secondary>custom</secondary>
</indexterm>
<indexterm zone="ref_guide_pc_scos_proxy_custom">
<primary>proxies</primary>
<secondary>ProxyManager</secondary>
</indexterm>
<para>
OpenJPA manages proxies through the
<ulink url="../apidocs/org/apache/openjpa/util/ProxyManager.html"><classname>org.apache.openjpa.util.ProxyManager</classname></ulink> interface.
OpenJPA includes a default proxy manager, the
<classname>org.apache.openjpa.util.ProxyManagerImpl</classname> (with a plugin
alias name of <literal>default</literal>),
that will meet the needs of most users. The default proxy
manager understands the following configuration properties:
</para>
<itemizedlist>
<listitem>
<para><literal>TrackChanges</literal>: Whether to use
<link linkend="ref_guide_pc_scos_proxy_smart">smart
proxies</link>. Defaults to <literal>true</literal>.
</para>
</listitem>
</itemizedlist>
<para>
For custom behavior, OpenJPA allows you to define your own
proxy classes, and your own proxy manager. See the
<literal>openjpa.util</literal> package
<ulink url="../apidocs/">Javadoc</ulink> for details on the
interfaces involved, and the utility classes OpenJPA provides to
assist you.
</para>
<para>
You can plug your custom proxy manager into the OpenJPA runtime
through the <link linkend="openjpa.ProxyManager"><literal>
openjpa.ProxyManager</literal></link> configuration property.
</para>
<example id="ref_guide_pc_scos_proxy_custom_ex">
<title>Configuring the Proxy Manager</title>
<programlisting format="linespecific">
&lt;property name="openjpa.ProxyManager" value="TrackChanges=false"/&gt;
</programlisting>
</example>
</section>
</section>
<section id="ref_guide_pc_extern">
<title>Externalization</title>
<indexterm zone="ref_guide_pc_extern">
<primary>externalization</primary>
</indexterm>
<indexterm>
<primary>persistent fields</primary>
<secondary>externalization</secondary>
<see>externalization</see>
</indexterm>
<para>
OpenJPA offers the ability to write
<link linkend="ref_guide_mapping_custom_field">custom field
mappings</link> in order to have complete control over the
mechanism with which fields are stored, queried, and loaded from
the datastore. Often, however, a custom mapping is overkill.
There is often a simple transformation from a Java field value
to its database representation. Thus, OpenJPA provides the
externalization service. Externalization allows you to specify
methods that will externalize a field value to its database
equivalent on store and then rebuild the value from its
externalized form on load.
</para>
<note>
<para>
Fields of embeddable classes used for <literal>@EmbeddedId
</literal> values in JPA cannot have externalizers.
</para>
</note>
<para>
The
<phrase>
JPA <ulink url="../apidocs/org/apache/openjpa/persistence/Externalizer.html"><classname>org.apache.openjpa.persistence.Externalizer</classname></ulink>
annotation
</phrase>
sets the name of a method that will be invoked to convert the field
into its external form for database storage. You can specify
either the name of a non-static method, which will be invoked on
the field value, or a static method, which will be invoked with
the field value as a parameter. Each method can also take an
optional
<ulink url="../apidocs/org/apache/openjpa/kernel/StoreContext.html"><classname>StoreContext</classname></ulink> parameter for
access to a persistence context. The return value of the method is
the field's external
form. By default, OpenJPA assumes that all named methods belong to the
field value's class (or its superclasses). You can, however,
specify static methods of other classes using the format
<literal>&lt;class-name&gt;.&lt;method-name&gt;</literal>.
</para>
<para>
Given a field of type <classname>CustomType</classname> that
externalizes to a string, the table below demonstrates several
possible externalizer methods and their corresponding
metadata extensions.
</para>
<table tocentry="1">
<title>Externalizer Options</title>
<tgroup cols="2" align="left" colsep="1" rowsep="1">
<colspec colname="method"/>
<colspec colname="extension"/>
<thead>
<row>
<entry colname="method">Method</entry>
<entry colname="extension">Extension</entry>
</row>
</thead>
<tbody>
<row>
<entry colname="method">
<literal>
public String CustomType.toString()
</literal>
</entry>
<entry colname="extension">
<literal>
@Externalizer("toString")
</literal>
</entry>
</row>
<row>
<entry colname="method">
<literal>
public String CustomType.toString(StoreContext ctx)
</literal>
</entry>
<entry colname="extension">
<literal>
@Externalizer("toString")
</literal>
</entry>
</row>
<row>
<entry colname="method">
<literal>
public static String AnyClass.toString(CustomType ct)
</literal>
</entry>
<entry colname="extension">
<literal>
@Externalizer("AnyClass.toString")
</literal>
</entry>
</row>
<row>
<entry colname="method">
<literal>
public static String AnyClass.toString(CustomType ct, StoreContext ctx)
</literal>
</entry>
<entry colname="extension">
<literal>
@Externalizer("AnyClass.toString")
</literal>
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
The
<phrase>
JPA <ulink url="../apidocs/org/apache/openjpa/persistence/Factory.html"><classname>org.apache.openjpa.persistence.Factory</classname></ulink> annotation
</phrase>
contains the name of a method that will be invoked to
instantiate the field from the external form stored in
the database. Specify a static method name. The method will
will be invoked with the externalized value and must return
an instance of the field type. The method can also take an optional
<ulink url="../apidocs/org/apache/openjpa/kernel/StoreContext.html"><classname>StoreContext</classname></ulink> parameter for
access to a persistence context.
If a factory is not specified, OpenJPA will use the constructor
of the field type that takes a single argument of the external
type, or will throw an exception if no constructor with that
signature exists.
</para>
<para>
Given a field of type <classname>CustomType</classname> that
externalizes to a string, the table below demonstrates several
possible factory methods and their corresponding
metadata extensions.
</para>
<table tocentry="1">
<title>Factory Options</title>
<tgroup cols="2" align="left" colsep="1" rowsep="1">
<colspec colname="method"/>
<colspec colname="extension"/>
<thead>
<row>
<entry colname="method">Method</entry>
<entry colname="extension">Extension</entry>
</row>
</thead>
<tbody>
<row>
<entry colname="method">
<literal>
public CustomType(String str)
</literal>
</entry>
<entry colname="extension">
none
</entry>
</row>
<row>
<entry colname="method">
<literal>
public static CustomType CustomType.fromString(String str)
</literal>
</entry>
<entry colname="extension">
<literal>
@Factory("fromString")
</literal>
</entry>
</row>
<row>
<entry colname="method">
<literal>
public static CustomType CustomType.fromString(String str, StoreContext ctx)
</literal>
</entry>
<entry colname="extension">
<literal>
@Factory("fromString")
</literal>
</entry>
</row>
<row>
<entry colname="method">
<literal>
public static CustomType AnyClass.fromString(String str)
</literal>
</entry>
<entry colname="extension">
<literal>
@Factory("AnyClass.fromString")
</literal>
</entry>
</row>
<row>
<entry colname="method">
<literal>
public static CustomType AnyClass.fromString(String str, StoreContext ctx)
</literal>
</entry>
<entry colname="extension">
<literal>
@Factory("AnyClass.fromString")
</literal>
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
If your externalized field is not a standard persistent type, you
must explicitly mark it persistent.
<phrase>
In JPA, you can force a persistent field by annotating it with
<link linkend="ref_guide_meta_jpa_persistent"><classname>
org.apache.openjpa.persistence.Persistent</classname></link> annotation.
</phrase>
</para>
<note>
<para>
If your custom field type is mutable and is not a standard
collection, map, or date class, OpenJPA will not be able to
detect changes to the field. You must mark the field dirty
manully, or create a custom field proxy.
</para>
<para>
<phrase>
See <ulink url="../../api/openjpa/persistence/OpenJPAEntityManager.html"><methodname>OpenJPAEntityManager.dirty</methodname></ulink> for how
to mark a field dirty manually in JPA.
</phrase>
</para>
<para>
See <xref linkend="ref_guide_pc_scos_proxy"/> for a discussion
of proxies.
</para>
</note>
<para>
You can externalize a field to virtually any value that is
supported by OpenJPA's field mappings (embedded relations are the
exception; you must declare your field to be a persistence-capable
type in order to embed it). This means that
a field can externalize to something as simple as a primitive,
something as complex as a collection or map of
persistence-capable objects, or anything in between. If you do
choose to externalize to a collection or map, OpenJPA recognizes a
family of metadata extensions for specying type information
for the externalized form of your fields - see
<xref linkend="type"/>. If the external form of your field
is a persistence-capable object, or contains persistence-capable
objects, OpenJPA will correctly include the objects in its
persistence-by-reachability algorithms and its delete-dependent
algorithms.
</para>
<para>
The example below demonstrates a few forms of externalization.
</para>
<example id="ref_guide_pc_externex">
<title>Using Externalization</title>
<programlisting format="linespecific">
import org.apache.openjpa.persistence.*;
@Entity
public class Magazine
{
// use Class.getName and Class.forName to go to/from strings
@Persistent
@Externalizer("getName")
@Factory("forName")
private Class cls;
// use URL.getExternalForm for externalization. no factory;
// we can rely on the URL string constructor
@Persistent
@Externalizer("toExternalForm")
private URL url;
// use our custom methods; notice how we use the KeyType and ElementType
// annotations to specify the metadata for our externalized map
@Persistent
@Externalizer("Magazine.mapFromCustomType")
@Factory("Magazine.mapToCustomType")
@KeyType(String.class) @ElementType(String.class)
private CustomType customType;
public static Map mapFromCustomType (CustomType customType)
{
... logic to pack custom type into a map ...
}
public static CustomType mapToCustomType (Map map)
{
... logic to create custom type from a map ...
}
...
}
</programlisting>
</example>
<para><indexterm><primary>externalization</primary><secondary>queries</secondary></indexterm>
You can query externalized fields using parameters.
Pass in a value of the field type when executing the query. OpenJPA
will externalize the parameter using the externalizer method named
in your metadata, and compare the externalized parameter with the
value stored in the database. As a shortcut, OpenJPA
also allows you to use parameters or literals of the field's
externalized type in queries, as demonstrated in the example below.
</para>
<note>
<para>
Currently, queries are limited
to fields that externalize to a primitive, primitive wrapper,
string, or date types, due to constraints on query syntax.
</para>
</note>
<example id="ref_guide_pc_extern_queryex">
<title>Querying Externalization Fields</title>
<para>
Assume the <classname>Magazine</classname> class has the
same fields as in the previous example.
</para>
<programlisting format="linespecific">
// you can query using parameters
Query q = em.createQuery ("select m from Magazine m where m.url = :u");
q.setParameter ("u", new URL ("http://www.solarmetric.com"));
List results = q.getResultList ();
// or as a shortcut, you can use the externalized form directly
q = em.createQuery ("select m from Magazine m where m.url = 'http://www.solarmetric.com'");
results = q.getResultList ();
</programlisting>
</example>
<section id="ref_guide_pc_extern_values">
<title>External Values</title>
<indexterm zone="ref_guide_pc_extern_values">
<primary>externalization</primary>
<secondary>external values</secondary>
</indexterm>
<para>
Externalization often takes simple constant values and
transforms them to constant values of a different type.
An example would be storing a <classname>boolean</classname>
field as a <classname>char</classname>, where <literal>true
</literal> and <literal>false</literal> would be stored
in the database as <literal>'T'</literal> and
<literal>'F'</literal> respectively.
</para>
<para>
OpenJPA allows you to define these simple translations in
metadata, so that the field behaves as in
<link linkend="ref_guide_pc_extern">full-fledged
externalization</link> without requiring
externalizer and factory methods. External values supports
translation of pre-defined simple types
(primitives, primitive wrappers, and Strings), to other
pre-defined simple values.
</para>
<para>
Use the
<phrase>
JPA
<ulink url="../apidocs/org/apache/openjpa/persistence/ExternalValues.html"><classname>org.apache.openjpa.persistence.ExternalValues</classname></ulink>
annotation
</phrase>
to define external value translations. The
values are defined in a format similar to that of
<link linkend="ref_guide_conf_plugins">configuration
plugins</link>, except that the value pairs represent Java and
datastore values. To convert the Java boolean
values of <literal>true</literal> and <literal>false</literal>
to the character values <literal>T</literal> and <literal>F
</literal>, for example, you would use the extension value:
<literal>true=T,false=F</literal>.
</para>
<para>
If the type of the datastore value is different from
the field's type, use the
<phrase>
JPA <ulink url="../apidocs/org/apache/openjpa/persistence/Type.html"><classname>org.apache.openjpa.persistence.Type</classname></ulink> annotation
</phrase>
to define the datastore type.
</para>
<example id="externvalues_ex">
<title>Using External Values</title>
<para>
This example uses external value translation to transform
a string field to an integer in the database.
</para>
<programlisting format="linespecific">
public class Magazine
{
@ExternalValues({"SMALL=5", "MEDIUM=8", "LARGE=10"})
@Type(int.class)
private String sizeWidth;
...
}
</programlisting>
</example>
</section>
</section>
</section>
<section id="ref_guide_fetch">
<title>Fetch Groups</title>
<indexterm zone="ref_guide_fetch">
<primary>fetch groups</primary>
</indexterm>
<para>
Fetch groups are sets of fields that load together. They can be used to
to pool together associated fields in order to provide performance
improvements over standard data fetching. Specifying fetch groups allows
for tuning of lazy loading and eager fetching behavior.
</para>
<para>
The JPA Overview's <xref linkend="jpa_overview_meta_fetch"/>
describes how to use JPA metadata annotations to control whether a field is
fetched eagerly or lazily. Fetch groups add a dynamic aspect to this
standard ability. As you will see, OpenJPA's JPA extensions allow you can add
and remove fetch groups at runtime to vary the sets of fields that are
eagerly loaded.
</para>
<section id="ref_guide_fetch_custom">
<title>Custom Fetch Groups</title>
<para>
OpenJPA places any field that is eagerly loaded according to the JPA
metadata rules into the built-in <emphasis>default
</emphasis> fetch group. The default fetch group is always active;
you cannot remove it at runtime. Thus fields in this group are
always loaded immediately when an object is fetched from the datastore.
</para>
<para>
A field can be a member of zero or one fetch groups, including the
default fetch group. That is, fields in the default fetch group cannot
be in an additional fetch group, and a field cannot declare itself a
member of more than one fetch group. So to place a field in a custom
fetch group, you must first exclude it from eager fetching in your
JPA metadata, if it does not already default to lazy loading.
</para>
<para>
When lazy-loading a field, OpenJPA checks to see
if that field declares itself to be a member of a fetch group. If so,
OpenJPA will load all fields in that fetch group.
</para>
<para>
Additionally, it is possible to configure a OpenJPA <classname>
EntityManager</classname> or <classname>Query</classname> to use a
particular fetch group or set of fetch groups
when loading new objects, as described later in this chapter.
When this is the case, OpenJPA loads the default fetch group plus any
fields in the specified set of additional fetch groups.
</para>
<para>
You create fetch groups with the
<ulink url="../apidocs/org/apache/openjpa/persistence/FetchGroup.html"><classname>org.apache.openjpa.persistence.FetchGroup</classname></ulink> annotation.
If your class only has one custom fetch group, you can place this
annotation directly on the class declaration. Otherwise, use the
<ulink url="../apidocs/org/apache/openjpa/persistence/FetchGroups.html"><classname>org.apache.openjpa.persistence.FetchGroups</classname></ulink> annotation
to declare an array of individual <classname>FetchGroup</classname>
values. The <classname>FetchGroup</classname> annotation has the
following properties:
</para>
<itemizedlist>
<listitem>
<para><literal>String name</literal>: The name of the fetch group.
Fetch group names are global, and are expected to be shared
among classes. For example, a shopping website may use a
<emphasis>detail</emphasis> fetch group in each product class
to efficiently load all the data needed to display a product's
"detail" page. The website might also define a
sparse <emphasis>list</emphasis> fetch group containing only
the fields needed to display a table of products, as in a search
result.
</para>
<para>
The following names are reserved for use by OpenJPA:
<literal>default</literal>, <literal>values</literal>,
<literal>all</literal>, <literal>none</literal>, and any name
beginning with <literal>jdo</literal>, <literal>ejb</literal>,
or <literal>openjpa</literal>.
</para>
</listitem>
<!--
<listitem>
<para>
<literal>String[] fetchGroups</literal>: Other fetch groups
whose fields to include in this group.
</para>
</listitem>
-->
<listitem>
<para><literal>FetchAttribute[] attributes</literal>: The set of
persistent fields or properties in the fetch group.
</para>
</listitem>
</itemizedlist>
<para>
As you might expect, listing a
<ulink url="../apidocs/org/apache/openjpa/persistence/FetchAttribute.html"><classname>org.apache.openjpa.persistence.FetchAttribute</classname></ulink>
within a <classname>FetchGroup</classname> includes the corresponding
persistent field or property in the fetch group. Each <classname>
FetchAttribute</classname> has the following properties:
</para>
<itemizedlist>
<listitem>
<para><literal>String name</literal>: The name of the persistent
field or property to include in the fetch group.
</para>
</listitem>
<listitem>
<para><literal>depth</literal>: If the attribute represents a
relation, the depth to which to recurse. The current fetch
group will be applied to the related object when fetching it,
and so on until the depth is exhausted or the related object has
no relations in the current fetch group. Under the
default depth of 1, the related object will be fetched, but none
of its relations will be traversed, even if they are in
the current fetch group. With a depth of 2, the related object
will be fetched, and if it has any relations in the
current fetch group, those will be fetched with a depth of 1.
A depth of 0 indicates that the recursion continues until the
graph is exhausted or a related object has no relations
in the current fetch group.
</para>
</listitem>
</itemizedlist>
<para>
Thus, to create a <emphasis>detail</emphasis> fetch group consisting of
the <literal>publisher</literal> and <literal>articles</literal>
relations, with the fetch group applied recursively to the related
objects, use:
</para>
<example id="ref_guide_fetch_customgroups">
<title>Custom Fetch Group Metadata</title>
<programlisting format="linespecific">
import org.apache.openjpa.persistence.*;
@Entity
@FetchGroups({
@FetchGroup(name="detail", attributes={
@FetchAttribute(name="publisher" depth=0),
@FetchAttribute(name="articles" depth=0)
}),
...
})
public class Magazine
{
...
}
</programlisting>
</example>
<note>
<para>
OpenJPA currently only supports a depth of 0 for fetch attributes.
This restriction will be lifted in a future release, along with the
restriction limiting each attribute to a single fetch group.
</para>
</note>
</section>
<section id="ref_guide_fetch_conf">
<title>Custom Fetch Group Configuration</title>
<indexterm zone="ref_guide_fetch_conf">
<primary>fetch groups</primary>
<secondary>custom configuration</secondary>
</indexterm>
<para><indexterm><primary>fetch groups</primary><secondary>FetchGroups</secondary></indexterm>
You can control the default set of fetch groups with the
<link linkend="openjpa.FetchGroups"><literal>openjpa.FetchGroups</literal></link> configuration property. Set this property to a comma-separated
list of fetch group names.
</para>
<para>
In JPA, OpenJPA's <classname>OpenJPAEntityManager</classname> and
<classname>OpenJPAQuery</classname> extensions to the standard
<classname>EntityManager</classname> and <classname>Query</classname>
interfaces provide access to a
<ulink url="../../api/openjpa/persistence/FetchPlan.html"><classname>org.apache.openjpa.persistence.FetchPlan</classname></ulink>
object. The <classname>FetchPlan</classname>
maintains the set of active fetch groups. It begins with the
groups defined in the <literal>openjpa.FetchGroups</literal> property,
but allows you to add and remove groups for an individual
<classname>EntityManager</classname> or <classname>Query</classname>
through the methods below.
</para>
<programlisting format="linespecific">
public FetchPlan addFetchGroup (String group);
public FetchPlan addFetchGroups (String... groups);
public FetchPlan addFetchGroups (Collection groups);
public FetchPlan removeFetchGroup (String group);
public FetchPlan removeFetchGroups (String... groups);
public FetchPlan removeFetchGroups (Collection groups);
public FetchPlan resetFetchGroups ();
public Collection&lt;String&gt; getFetchGroups ();
public void clearFetchGroups ();
</programlisting>
<para><xref linkend="ref_guide_runtime"/> details the <classname>
OpenJPAEntityManager</classname>, <classname>OpenJPAQuery</classname>, and
<classname>FetchPlan</classname> interfaces.
</para>
<example id="ref_guide_fetch_conf_query">
<title>Using the FetchPlan</title>
<programlisting format="linespecific">
import org.apache.openjpa.persistence.*;
...
OpenJPAQuery kq = OpenJPAPersistence.cast (em.createQuery (...));
kq.getFetchPlan ().addFetchGroup ("detail");
List results = kq.getResultList ();
</programlisting>
</example>
</section>
<section id="ref_guide_fetch_single_field">
<title>Per-field Fetch Configuration</title>
<indexterm zone="ref_guide_fetch_single_field">
<primary>fetch groups</primary>
<secondary>single fields</secondary>
</indexterm>
<para>
In addition to controlling fetch configuration on a
per-fetch-group basis, you can configure OpenJPA to include
particular fields in the current fetch configuration. This
allows you to add individual fields that are not in the default
fetch group or in any other currently-active fetch groups to the
set of fields that will be eagerly loaded from the
database.
</para>
<para>
JPA <classname>FetchPlan</classname> methods:
</para>
<programlisting format="linespecific">
public FetchPlan addField (String field);
public FetchPlan addFields (String... fields);
public FetchPlan addFields (Class cls, String... fields);
public FetchPlan addFields (Collection fields);
public FetchPlan addFields (Class cls, Collection fields);
public FetchPlan removeField (String field);
public FetchPlan removeFields (String... fields);
public FetchPlan removeFields (Class cls, String... fields);
public FetchPlan removeFields (Collection fields);
public FetchPlan removeFields (Class cls, Collection fields);
public Collection&lt;String&gt; getFields ();
public void clearFields ();
</programlisting>
<para>
The methods that take only string arguments use the fully-qualified
field name, such as <literal>org.mag.Magazine.publisher</literal>.
Similarly, <methodname>getFields</methodname> returns the set of
fully-qualified field names. In all methods, the named field
must be defined in the class specified in the invocation, not a
superclass. So, if the field <literal>publisher</literal> is
defined in base class <classname>Publication</classname> rather than
subclass <classname>Magazine</classname>, you must
invoke <literal>addField (Publication.class, "publisher")</literal>
and not <literal>addField (Magazine.class, "publisher")</literal>.
This is stricter than Java's default field-masking algorithms, which
would allow the latter method behavior if <literal>Magazine</literal>
did not also define a field called <literal>publisher</literal>.
</para>
<para>
In order to avoid the cost of reflection, OpenJPA does not perform
any validation of the field name / class name pairs that you put
into the fetch configuration. If you specify non-existent class /
field pairs, nothing adverse will happen, but you will receive
no notification of the fact that the specified configuration is
not being used.
</para>
<example id="ref_guide_fetch-conf_per_field">
<title>Adding an Eager Field</title>
<programlisting format="linespecific">
import org.apache.openjpa.persistence.*;
...
OpenJPAEntityManager kem = OpenJPAPersistence.cast (em);
kem.getFetchPlan ().addField (Magazine.class, "publisher");
Magazine mag = em.find (Magazine.class, magId);
</programlisting>
</example>
</section>
<section id="ref_guide_fetch_impl">
<title>Implementation Notes</title>
<itemizedlist>
<listitem>
<para>
Even when a direct relation is not eagerly fetched, OpenJPA
selects the foreign key columns and caches the values. This
way when you do traverse the relation, OpenJPA can often find the
related object in its cache, or at least avoid joins when
loading the related object from the database.
</para>
</listitem>
<listitem>
<para>
The above implicit foreign key-selecting behavior does not
always apply when the relation is in a subclass table. If the
subclass table would not otherwise be joined into the select,
OpenJPA avoids the extra join just to select the foreign key
values.
</para>
</listitem>
</itemizedlist>
</section>
</section>
<section id="ref_guide_perfpack_eager">
<title>Eager Fetching</title>
<indexterm zone="ref_guide_perfpack_eager">
<primary>eager fetching</primary>
</indexterm>
<indexterm>
<primary>persistent fields</primary>
<see>eager fetching</see>
</indexterm>
<indexterm zone="ref_guide_perfpack_eager">
<primary>fetch groups</primary>
<secondary>eager fetching</secondary>
<seealso>eager fetching</seealso>
</indexterm>
<indexterm>
<primary>lazy loading</primary>
<seealso>eager fetching</seealso>
<seealso>fetch groups</seealso>
</indexterm>
<para>
Eager fetching is the ability to efficiently load subclass data and
related objects along with the base instances being queried.
Typically, OpenJPA has to make a trip to the database whenever a
relation is loaded, or when you first access data that is mapped to a
table other than the least-derived superclass table. If you perform a
query that returns 100 <classname>Person</classname> objects, and then
you have to retrieve the <classname>Address</classname> for each
person, OpenJPA may make as many as 101 queries (the initial
query, plus one for the address of each person returned). Or if some
of the <classname>Person</classname> instances turn out to be
<classname>Employee</classname>s, where <classname>Employee</classname>
has additional data in its own joined table, OpenJPA once again might need
to make extra database trips to access the additional employee data.
With eager fetching, OpenJPA can reduce these cases to a single query.
</para>
<para>
Eager fetching only affects relations in the fetch groups being loaded
(see <xref linkend="ref_guide_fetch"/>). In
other words, relations that would not normally be loaded immediately
when retrieving an object or accessing a field are not affected by
eager fetching. In our example above, the address of each person would
only be eagerly fetched if the query were configured to include the
address field or its fetch group, or if the address were in the default
fetch group. This allows you to control exactly which fields are
eagerly fetched in different situations. Similarly, queries that
exclude subclasses aren't affected by eager subclass fetching,
described below.
</para>
<para>
Eager fetching has three modes:
</para>
<itemizedlist>
<listitem>
<para><literal>none</literal>: No eager fetching is performed.
Related objects are always loaded in an independent select
statement. No joined subclass data is loaded unless it is in
the table(s) for the base type being queried. Unjoined subclass
data is loaded using separate select statements rather than
a SQL UNION operation.
</para>
</listitem>
<listitem>
<para><indexterm><primary>eager fetching</primary><secondary>join mode</secondary></indexterm><literal>join</literal>: In this mode, OpenJPA joins to to-one
relations in the configured fetch groups. If OpenJPA is loading
data for a single instance, then OpenJPA will also
join to any collection field in the configured
fetch groups. When loading data for multiple instances, though,
(such as when executing a <classname>Query</classname>) OpenJPA
will not join to collections by default. Instead, OpenJPA defaults
to <literal>parallel</literal> mode for collections, as
described below. You can force OpenJPA use a join rather than
parallel mode for a collection field using the metadata
extension described in <xref linkend="eager-fetch-mode"/>.
</para>
<para><indexterm><primary>outer joins</primary></indexterm>
Under <literal>join</literal> mode, OpenJPA uses a left outer join
(or inner join, if the relations' field metadata declares the
relation non-nullable) to select the
related data along with the data for the target objects.
This process works recursively for to-one joins, so that if
<classname>Person</classname> has an
<classname>Address</classname>, and
<classname>Address</classname> has a
<classname>TelephoneNumber</classname>, and the fetch groups
are configured correctly, OpenJPA might issue a single select that
joins across the tables for all three classes. To-many joins
can not recursively spawn other to-many joins, but they can
spawn recursive to-one joins.
</para>
<para>
Under the <literal>join</literal> subclass fetch mode, subclass
data in joined tables is selected by outer joining to all
possible subclass tables of the type being queried. Unjoined
subclass data is selected with a SQL UNION where possible.
As you'll see below, subclass data fetching is configured
separately from relation fetching, and can be disabled for
specific classes.
</para>
<note>
<para>
Some databases may not support UNIONs or outer joins. Also,
OpenJPA can not use outer joins if you have set the
<link linkend="openjpa.jdbc.DBDictionary"><literal>
DBDictionary</literal></link>'s <literal>JoinSyntax
</literal> to <literal>traditional</literal>.
See <xref linkend="ref_guide_dbsetup_sql92"/>.
</para>
</note>
</listitem>
<listitem>
<para><indexterm><primary>eager fetching</primary><secondary>parallel mode</secondary></indexterm><literal>parallel</literal>: Under this mode, OpenJPA selects
to-one relations and joined collections as outlined
in the <literal>join</literal> mode description above. Unjoined
collection fields, however, are eagerly fetched using a
separate select statement for each collection, executed in
parallel with the select statement for the target objects.
The parallel selects use the <literal>WHERE</literal>
conditions from the primary select, but add their own joins to
reach the related data. Thus, if you perform a query that
returns 100 <classname>Company</classname> objects, where each
company has a list of <classname>Employee</classname> objects
and <classname>Department</classname> objects, OpenJPA will make
3 queries. The first will select the company objects, the second
will select the employees for those companies, and
the third will select the departments for the same companies.
Just as for joins, this process can be
recursively applied to the objects in the relations being
eagerly fetched. Continuing our example, if the
<classname>Employee</classname> class
had a list of <classname>Projects</classname> in one of the
fetch groups being loaded, OpenJPA would execute a single
additional select in parallel to load the projects of all
employees of the matching companies.
</para>
<para>
Using an additional select to load each collection avoids
transferring more data than necessary from the database to
the application. If eager joins were used instead of parallel
select statements, each collection added to the
configured fetch groups would cause the amount of data being
transferred to rise dangerously, to the point that you could
easily overwhelm the network.
</para>
<para>
Polymorphic to-one relations to table-per-class mappings use
parallel eager fetching because proper joins are impossible.
You can force other to-one relations to use parallel rather than
join mode eager fetching using the metadata extension described
in <xref linkend="eager-fetch-mode"/>.
</para>
<para>
Setting your subclass fetch mode to <literal>parallel</literal>
affects table-per-class and vertical inheritance hierarchies.
Under parallel mode, OpenJPA issues separate selects for each
subclass in a table-per-class inheritance hierarchy, rather
than UNIONing all subclass tables together as in join mode.
This applies to any operation on a table-per-class base class:
query, by-id lookup, or relation traversal.
</para>
<para>
When dealing with a vertically-mapped hierarchy, on the other
hand, parallel subclass fetch mode only applies to queries.
Rather than outer-joining to subclass tables, OpenJPA will issue
the query separately for each subclass. In all other
situations, parallel subclass fetch mode acts just like join
mode in regards to vertically-mapped subclasses.
</para>
<para>
When OpenJPA knows that it is selecting for a single object only,
it never uses <literal>parallel</literal> mode, because the
additional selects can be made lazily just as efficiently.
This mode only increases efficiency over <literal>join
</literal> mode when multiple objects with eager relations
are being loaded, or when multiple selects might be faster than
joining to all possible subclasses.
</para>
</listitem>
</itemizedlist>
<section id="ref_guide_perfpack_eager_conf">
<title>Configuring Eager Fetching</title>
<indexterm zone="ref_guide_perfpack_eager_conf">
<primary>eager fetching</primary>
<secondary>configuration</secondary>
</indexterm>
<para><indexterm><primary>EagerFetchMode</primary></indexterm><indexterm><primary>SubclassFetchMode</primary></indexterm><indexterm><primary>eager fetching</primary><secondary>EagerFetchMode</secondary></indexterm><indexterm><primary>eager fetching</primary><secondary>SubclassFetchMode</secondary></indexterm>
You can control OpenJPA's default eager fetch mode through the
<link linkend="openjpa.jdbc.EagerFetchMode"><literal>
openjpa.jdbc.EagerFetchMode</literal></link> and
<link linkend="openjpa.jdbc.SubclassFetchMode"><literal>openjpa.jdbc.SubclassFetchMode</literal></link> configuration
properties. Set each of these properties to one of the mode names
described in the previous section: <literal>none, join,
parallel</literal>. If left unset, the eager fetch mode defaults
to <literal>parallel</literal> and the subclass fetch mode defaults
to <literal>join</literal> These are generally the most robust and
performant strategies.
</para>
<para>
You can easily override the default fetch modes at runtime for any
lookup or query through OpenJPA's fetch configuration APIs. See
<xref linkend="ref_guide_runtime"/> for details.
</para>
<example id="ref_guide_perfpack_eager_def">
<title>Setting the Default Eager Fetch Mode</title>
<programlisting format="linespecific">
&lt;property name="openjpa.jdbc.EagerFetchMode" value="parallel"/&gt;
&lt;property name="openjpa.jdbc.SubclassFetchMode" value="join"/&gt;
</programlisting>
</example>
<example id="ref_guide_perfpack_eager_runtime">
<title>Setting the Eager Fetch Mode at Runtime</title>
<programlisting format="linespecific">
import org.apache.openjpa.persistence.*;
import org.apache.openjpa.persistence.jdbc.*;
...
Query q = em.createQuery ("select p from Person p where p.address.state = 'TX'");
OpenJPAQuery kq = OpenJPAPersistence.cast (q);
JDBCFetchPlan fetch = (JDBCFetchPlan) kq.getFetchPlan ();
fetch.setEagerFetchMode (JDBCFetchPlan.EAGER_PARALLEL);
fetch.setSubclassFetchMode (JDBCFetchPlan.EAGER_JOIN);
List results = q.getResultList ();
</programlisting>
</example>
<para>
You can specify a default subclass fetch mode for an individual
class with the metadata extension described in
<xref linkend="subclass-fetch-mode"/>.
Note, however, that you cannot "upgrade" the runtime fetch mode
with your class setting. If the runtime fetch mode is
<literal>none</literal>, no eager subclass data fetching will
take place, regardless of your metadata setting.
</para>
<para>
This applies to the eager fetch mode metadata extension as well
(see <xref linkend="eager-fetch-mode"/>).
You can use this extension to disable eager fetching on a field or
to declare that a collection would rather use joins than parallel
selects or vice versa. But an extension value of
<literal>join</literal> won't cause any eager joining if the fetch
configuration's setting is <literal>none</literal>.
</para>
</section>
<section id="ref_guide_perfpack_eager_consider">
<title>Eager Fetching Considerations and Limitations</title>
<para>
There are several important points that you should consider when
using eager fetching:
</para>
<itemizedlist>
<listitem>
<para><indexterm><primary>eager fetching</primary><secondary>with large result sets</secondary></indexterm><indexterm><primary>large result sets</primary><secondary>interaction with eager fetching</secondary></indexterm>
When you are using <literal>parallel</literal> eager fetch
mode and you have large result sets enabled (see
<xref linkend="ref_guide_dbsetup_lrs"/>) or you place
a range on a query, OpenJPA performs the needed parallel
selects on one page of results at a time. For example,
suppose your <literal>FetchBatchSize</literal> is set to
20, and you perform a large result set
query on a class that has collection fields in the
configured fetch groups. OpenJPA will immediately cache
the first <literal>20</literal> results of the query using
<literal>join</literal> mode eager fetching only. Then,
it will issue the extra selects needed to eager fetch
your collection fields according to <literal>parallel
</literal> mode. Each select will use a SQL
<literal>IN</literal> clause (or multiple <literal>OR
</literal> clauses if your class has a compound primary key)
to limit the selected collection elements to those owned
by the 20 cached results.
</para>
<para>
Once you iterate past the first 20 results, OpenJPA will
cache the next 20 and again issue any needed extra selects
for collection fields, and so on. This pattern ensures that
you get the benefits of eager fetching without bringing
more data into memory than anticipated.
</para>
</listitem>
<listitem>
<para>
Eager fetching can sometimes be <emphasis>less</emphasis>
efficient than standard fetching when circular relations
are included in the configured fetch groups.
</para>
</listitem>
<listitem>
<para>
Once OpenJPA eager-joins into a class, it cannot issue any
further eager to-many joins or parallel selects from that
class in the same query. To-one joins, however, can
recurse to any level.
</para>
</listitem>
<listitem>
<para>
Using a to-many join makes it impossible to determine the
number of instances the result set contains without
traversing the entire set. This is because each result
object might be represented by multiple rows. Thus, queries
with a range specification or queries configured for lazy
result set traversal automatically turn off eager to-many
joining.
</para>
</listitem>
<listitem>
<para>
OpenJPA cannot eagerly join to polymorphic relations to
non-leaf classes in a table-per-class inheritance hierarchy.
You can work around this restriction using the mapping
extensions described in <xref linkend="nonpolymorphic"/>.
</para>
</listitem>
</itemizedlist>
</section>
</section>
<section id="ref_guide_lock_groups">
<title>Lock Groups</title>
<indexterm zone="ref_guide_lock_groups">
<primary>locking</primary>
<secondary>lock groups</secondary>
</indexterm>
<indexterm zone="ref_guide_lock_groups">
<primary>lock groups</primary>
<seealso>locking</seealso>
</indexterm>
<para>
OpenJPA supports both optimistic and datastore locking strategies, but
optimistic locking is the preferred approach in most applications.
Typically, optimistic locking is performed at the object level of
granularity. That is, changes to any part of the same object in concurrent
transactions will result in an optimistic locking exception being thrown
by the transaction that commits last. In many applications, this is
acceptable. However, if your application has a high likelihood of
concurrent writes to different parts of the same object, then it may
be advantageous to use a finer-grained optimistic
lock. Additionally, certain parts of an object model may be best
modeled without any locking at all, or with a last-commit-wins
strategy. It is for these types of situations that OpenJPA offers
customizable optimistic lock groups, which allow you to achieve
sub-object-level locking granularity.
</para>
<para>
For example, an <classname>Employee</classname> class may have some fields
configurable by the employee the object represents (<literal>
firstName</literal>, <literal>lastName</literal>, <literal>
phoneNumber</literal>), some that are only modifiable by that employee's
manager (<literal>salary</literal>, <literal>title</literal>), and some in
which concurrent updates are acceptable (a list of <literal>
projects</literal>). In such a model, you can greatly
improve the success of concurrent updates in optimistic transactions
by putting <literal>firstName</literal>, <literal>lastName</literal>, and
<literal>phoneNumber</literal> into one lock group,
<literal>salary</literal> and <literal>title</literal> into another, and
excluding the <literal>projects</literal> field from optimistic lock
checks altogether.
</para>
<para><phrase>
You specify a field's lock group in JPA metadata with the
<ulink url="../apidocs/org/apache/openjpa/persistence/LockGroup.html"><classname>org.apache.openjpa.persistence.LockGroup</classname></ulink> annotation.
</phrase>
See <xref linkend="lock-group"/> for details on lock group metadata.
</para>
<example id="ref_guide_lock_groups_metadata">
<title>Lock Group Metadata</title>
<programlisting format="linespecific">
import org.apache.openjpa.persistence.*;
@Entity
public class Employee
{
// default lock group
private String firstName;
private String lastName;
private String phoneNumber;
// named lock group
@LockGroup("corporate") private float salary;
@LockGroup("corporate") private String title;
// no lock group; allow concurrent modifications
@LockGroup(LockGroup.NONE) private Set&lt;Project&gt; projects;
...
}
</programlisting>
</example>
<para>
Currently, lock groups are only supported when using number and
timestamp version strategies. They are not supported in the
state-comparison strategy, though you can still exclude
fields from participating in optimistic versioning under this strategy
by setting the their lock group to <literal>none</literal>.
</para>
<section id="ref_guide_lock_groups_and_subclasses">
<title>Lock Groups and Subclasses</title>
<indexterm zone="ref_guide_lock_groups_and_subclasses">
<primary>lock groups</primary>
<secondary>subclasses</secondary>
</indexterm>
<para>
Due to mapping restrictions, subclasses cannot simply declare
additional lock groups implicitly, as is done in the example shown
above. Instead, the least-derived mapped type in the persistent
hierarchy must list all lock groups that its children can use via the
<phrase><ulink url="../apidocs/org/apache/openjpa/persistence/LockGroups.html"><classname>
org.apache.openjpa.persistence.LockGroups</classname></ulink> annotation
</phrase>
For example, if the <classname>Employee</classname>
class in the last example extended <classname>Person</classname>, the
metadata would have looked like so:
</para>
<example id="ref_guide_lock_groups_and_subclasses_metadata">
<title>Lock Group Metadata</title>
<!-- ### EJBDOC -->
<programlisting format="linespecific">
import org.apache.openjpa.persistence.*;
@Entity
@LockGroups({"corporate"})
public class Person
{
// default lock group
private String firstName;
private String lastName;
private String phoneNumber;
...
}
@Entity
public class Employee
extends Person
{
// named lock group
@LockGroup("corporate") private float salary;
@LockGroup("corporate") private String title;
// no lock group; allow concurrent modifications
@LockGroup(LockGroup.NONE) private Set&lt;Project&gt; projects;
...
}
</programlisting>
<programlisting format="linespecific">
public class Person
{
private String firstName;
private String lastName;
private String phoneNumber;
...
}
public class Employee
extends Person
{
// these fields can only be set by the employee's manager
private float salary;
private String title;
// this field might be updated concurrently by the employee,
// other team members, or the employee's manager
private Set projects;
...
}
&lt;?xml version="1.0"?&gt;
&lt;jdo&gt;
&lt;package name=""&gt;
&lt;class name="Person"&gt;
&lt;!-- here we list the lock groups that will be used by Employee --&gt;
&lt;extension vendor-name="openjpa" key="lock-groups" value="corporate"/&gt;
&lt;/class&gt;
&lt;class name="Employee"&gt;
&lt;!-- named lock group --&gt;
&lt;field name="salary"&gt;
&lt;extension vendor-name="openjpa" key="lock-group" value="corporate"/&gt;
&lt;/field&gt;
&lt;field name="title"&gt;
&lt;extension vendor-name="openjpa" key="lock-group" value="corporate"/&gt;
&lt;/field&gt;
&lt;!-- no lock group; allow concurrent modifications --&gt;
&lt;field name="projects"&gt;
&lt;collection element-type="Project"/&gt;
&lt;extension vendor-name="openjpa" key="lock-group" value="none"/&gt;
&lt;/field&gt;
&lt;/class&gt;
&lt;/package&gt;
&lt;/jdo&gt;
</programlisting>
</example>
<para>
The exceptions to this rule are the <literal>none</literal> and
<literal>default</literal> built-in lock groups. They can be used
at any point in the inheritance hierarchy without pre-declaration.
Additionally, the lock groups listing can contain
lock groups that would otherwise be implicitly defined in the
least-derived type metadata.
</para>
</section>
<section id="ref_guide_lock_group_mapping">
<title>Lock Group Mapping</title>
<indexterm zone="ref_guide_lock_group_mapping">
<primary>lock groups</primary>
<secondary>mapping metadata</secondary>
</indexterm>
<indexterm zone="ref_guide_lock_group_mapping">
<primary>mapping metadata</primary>
<secondary>version</secondary>
<tertiary>lock group mapping</tertiary>
<seealso>lock groups</seealso>
</indexterm>
<para>
When using custom lock groups with a relational database,
OpenJPA will need a version column for each of the groups, instead of
just one version column. This means that you must use surrogate
versioning; you cannot use a version field. OpenJPA also currently
requires that all the version columns for a given object be in the
same table. Finally, it is only possible to use a single version
strategy for a given object. That is, you cannot have one version
number column and another timestamp version column.
</para>
<para>
<phrase>
Use the
<ulink url="../apidocs/org/apache/openjpa/persistence/jdbc/VersionColumn.html"><classname>org.apache.openjpa.persistence.jdbc.VersionColumn(s)</classname></ulink>
annotation to specify the version column for each lock group in JPA
mapping.
</phrase>
</para>
<example id="ref_guide_lock_groups_mapping_ex">
<title>Mapping Lock Groups</title>
<programlisting format="linespecific">
import org.apache.openjpa.persistence.jdbc.*;
@Entity
@Table(name="EMP")
@VersionColumns({
@VersionColumn(name="VERS_CORP" lockGroup="corporate"),
@VersionColumn(name="VERS")
})
public class Employee
{
...
}
</programlisting>
</example>
</section>
</section>
</chapter>