mirror of https://github.com/apache/openjpa.git
2489 lines
108 KiB
XML
2489 lines
108 KiB
XML
|
|
||
|
<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 <output directory></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 <true/t |
|
||
|
false/f></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 <true/t
|
||
|
| false/f></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 <true/t
|
||
|
| false/f></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 <T> T createInstance (Class<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 <output directory></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 <true/t | false/f>
|
||
|
</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 <token></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 <id class name></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 <id class suffix></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">
|
||
|
<class name="Magazine">
|
||
|
<field name="coverPhoto"/>
|
||
|
...
|
||
|
</class>
|
||
|
<class name="Photograph">
|
||
|
<field name="mag">
|
||
|
<extension vendor-name="openjpa" key="inverse-logical" value="coverPhoto"/>
|
||
|
</field>
|
||
|
...
|
||
|
</class>
|
||
|
</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">
|
||
|
<property name="openjpa.InverseManager" value="true"/>
|
||
|
</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">
|
||
|
<property name="openjpa.InverseManager" value="true(Action=warn)"/>
|
||
|
</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<Employee> 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">
|
||
|
<property name="openjpa.ProxyManager" value="TrackChanges=false"/>
|
||
|
</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><class-name>.<method-name></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<String> 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<String> 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">
|
||
|
<property name="openjpa.jdbc.EagerFetchMode" value="parallel"/>
|
||
|
<property name="openjpa.jdbc.SubclassFetchMode" value="join"/>
|
||
|
</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<Project> 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<Project> 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;
|
||
|
|
||
|
...
|
||
|
}
|
||
|
|
||
|
|
||
|
<?xml version="1.0"?>
|
||
|
<jdo>
|
||
|
<package name="">
|
||
|
<class name="Person">
|
||
|
<!-- here we list the lock groups that will be used by Employee -->
|
||
|
<extension vendor-name="openjpa" key="lock-groups" value="corporate"/>
|
||
|
</class>
|
||
|
<class name="Employee">
|
||
|
<!-- named lock group -->
|
||
|
<field name="salary">
|
||
|
<extension vendor-name="openjpa" key="lock-group" value="corporate"/>
|
||
|
</field>
|
||
|
<field name="title">
|
||
|
<extension vendor-name="openjpa" key="lock-group" value="corporate"/>
|
||
|
</field>
|
||
|
<!-- no lock group; allow concurrent modifications -->
|
||
|
<field name="projects">
|
||
|
<collection element-type="Project"/>
|
||
|
<extension vendor-name="openjpa" key="lock-group" value="none"/>
|
||
|
</field>
|
||
|
</class>
|
||
|
</package>
|
||
|
</jdo>
|
||
|
</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>
|