2006-08-24 16:41:12 -04:00
|
|
|
<chapter id="ref_guide_pc">
|
|
|
|
<title>
|
|
|
|
Persistent Classes
|
|
|
|
</title>
|
|
|
|
<indexterm zone="ref_guide_pc">
|
|
|
|
<primary>
|
|
|
|
persistent classes
|
|
|
|
</primary>
|
|
|
|
</indexterm>
|
|
|
|
<para>
|
2006-09-05 15:28:36 -04:00
|
|
|
Persistent class basics are covered in <xref linkend="jpa_overview_pc"/>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
<indexterm zone="ref_guide_pc_pcclasses">
|
2006-08-24 16:41:12 -04:00
|
|
|
<primary>
|
|
|
|
persistent classes
|
|
|
|
</primary>
|
|
|
|
<secondary>
|
|
|
|
list
|
|
|
|
</secondary>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<indexterm zone="ref_guide_pc_pcclasses">
|
2006-08-24 16:41:12 -04:00
|
|
|
<primary>
|
|
|
|
PCClasses
|
|
|
|
</primary>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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:
|
2006-08-22 17:28:53 -04:00
|
|
|
</para>
|
2006-08-24 16:41:12 -04:00
|
|
|
<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
|
2006-09-05 15:28:36 -04:00
|
|
|
<xref linkend="ref_guide_mapping_synch"/> ), OpenJPA must know all of your
|
2006-08-24 16:41:12 -04:00
|
|
|
persistent classes up-front.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
2006-08-22 17:28:53 -04:00
|
|
|
</itemizedlist>
|
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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
|
2006-09-05 15:28:36 -04:00
|
|
|
classes. See <xref linkend="jpa_overview_persistence_xml"/> for details.
|
2006-08-24 16:41:12 -04:00
|
|
|
</para>
|
2006-08-22 17:28:53 -04:00
|
|
|
<note>
|
2006-08-24 16:41:12 -04:00
|
|
|
<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>
|
2006-08-22 17:28:53 -04:00
|
|
|
</note>
|
2006-08-24 16:41:12 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_pc_enhance">
|
|
|
|
<title>
|
|
|
|
Enhancement
|
|
|
|
</title>
|
2006-08-22 17:28:53 -04:00
|
|
|
<indexterm zone="ref_guide_pc_enhance">
|
2006-08-24 16:41:12 -04:00
|
|
|
<primary>
|
|
|
|
enhancer
|
|
|
|
</primary>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<indexterm>
|
2006-08-24 16:41:12 -04:00
|
|
|
<primary>
|
|
|
|
openjpac
|
|
|
|
</primary>
|
|
|
|
<see>
|
|
|
|
enhancer
|
|
|
|
</see>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
<mediaobject>
|
2006-08-24 16:41:12 -04:00
|
|
|
<imageobject>
|
|
|
|
<!-- PNG image data, 509 x 133 (see README) -->
|
2006-09-05 15:28:36 -04:00
|
|
|
<imagedata fileref="img/enhancement.png" width="339px"/>
|
|
|
|
|
2006-08-24 16:41:12 -04:00
|
|
|
</imageobject>
|
2006-08-22 17:28:53 -04:00
|
|
|
</mediaobject>
|
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
The diagram above illustrates the compilation of a persistent class.
|
|
|
|
</para>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
<section id="ref_guide_pc_enhance_build">
|
2006-08-24 16:41:12 -04:00
|
|
|
<title>
|
|
|
|
Enhancing at Build Time
|
|
|
|
</title>
|
|
|
|
<indexterm zone="ref_guide_pc_enhance_build">
|
|
|
|
<primary>
|
|
|
|
enhancer
|
|
|
|
</primary>
|
|
|
|
<secondary>
|
|
|
|
build time
|
|
|
|
</secondary>
|
|
|
|
</indexterm>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-09-05 15:28:36 -04:00
|
|
|
You can also enhance via Ant; see <xref linkend="ref_guide_integration_enhance"/>
|
|
|
|
.
|
2006-08-24 16:41:12 -04:00
|
|
|
</para>
|
|
|
|
</note>
|
|
|
|
<example id="ref_guide_pc_enhance_enhancer">
|
|
|
|
<title>
|
|
|
|
Using the OpenJPA Enhancer
|
|
|
|
</title>
|
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
openjpac Magazine.java
|
|
|
|
</programlisting>
|
2006-08-24 16:41:12 -04:00
|
|
|
</example>
|
|
|
|
<para>
|
|
|
|
The enhancer accepts the standard set of command-line arguments defined by the
|
2006-09-05 15:28:36 -04:00
|
|
|
configuration framework (see <xref linkend="ref_guide_conf_devtools"/> ),
|
2006-08-24 16:41:12 -04:00
|
|
|
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
|
2006-09-05 15:28:36 -04:00
|
|
|
in your persistent class list (see <xref linkend="ref_guide_pc_pcclasses"/>
|
|
|
|
).
|
2006-08-24 16:41:12 -04:00
|
|
|
</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>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_pc_enhance_runtime_container">
|
2006-08-24 16:41:12 -04:00
|
|
|
<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>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_pc_enhance_runtime">
|
2006-08-24 16:41:12 -04:00
|
|
|
<title>
|
|
|
|
Enhancing at Runtime
|
|
|
|
</title>
|
|
|
|
<indexterm zone="ref_guide_pc_enhance_runtime">
|
|
|
|
<primary>
|
|
|
|
enhancer
|
|
|
|
</primary>
|
|
|
|
<secondary>
|
|
|
|
runtime
|
|
|
|
</secondary>
|
|
|
|
<tertiary>
|
|
|
|
outside a container
|
|
|
|
</tertiary>
|
|
|
|
</indexterm>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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
|
2006-09-05 15:28:36 -04:00
|
|
|
persistent class list described in <xref linkend="ref_guide_pc_pcclasses"/>
|
|
|
|
. If you declare a persistent class list, OpenJPA will only search for
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
java -javaagent:/home/dev/openjpa/lib/org.apache.openjpa.jar com.xyz.Main
|
|
|
|
</programlisting>
|
2006-08-24 16:41:12 -04:00
|
|
|
</example>
|
|
|
|
<para>
|
|
|
|
You can pass settings to the agent using OpenJPA's plugin syntax (see
|
2006-09-05 15:28:36 -04:00
|
|
|
<xref linkend="ref_guide_conf_plugins"/> ). The agent accepts the long
|
2006-08-24 16:41:12 -04:00
|
|
|
form of any of the standard configuration options (
|
2006-09-05 15:28:36 -04:00
|
|
|
<xref linkend="ref_guide_conf_devtools"/> ). It also accepts the following
|
2006-08-24 16:41:12 -04:00
|
|
|
options, the first three of which correspond exactly to to the same-named
|
|
|
|
options of the enhancer tool described in
|
2006-09-05 15:28:36 -04:00
|
|
|
<xref linkend="ref_guide_pc_enhance_build"/>:
|
2006-08-24 16:41:12 -04:00
|
|
|
</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>
|
2006-08-22 17:28:53 -04:00
|
|
|
java -javaagent:/home/dev/openjpa/lib/org.apache.openjpa.jar=jdoEnhance=true,addDefaultConstructor=false com.xyz.Main
|
|
|
|
</programlisting>
|
2006-08-24 16:41:12 -04:00
|
|
|
</example>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_pc_enhance_sercompat">
|
2006-08-24 16:41:12 -04:00
|
|
|
<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
|
2006-09-05 15:28:36 -04:00
|
|
|
serialization compatibility. See <xref linkend="ref_guide_detach_graph"/>
|
2006-08-24 16:41:12 -04:00
|
|
|
for details.
|
|
|
|
</para>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
|
|
|
</section>
|
2006-08-24 16:41:12 -04:00
|
|
|
<section id="ref_guide_pc_oid">
|
|
|
|
<title>
|
|
|
|
Object Identity
|
|
|
|
</title>
|
2006-08-22 17:28:53 -04:00
|
|
|
<indexterm zone="ref_guide_pc_oid">
|
2006-08-24 16:41:12 -04:00
|
|
|
<primary>
|
|
|
|
identity
|
|
|
|
</primary>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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
|
2006-09-05 15:28:36 -04:00
|
|
|
described in <xref linkend="jpa_overview_meta_id"/> of the JPA Overview.
|
2006-08-24 16:41:12 -04:00
|
|
|
</para>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
To retrieve the identity value of a datastore identity entity, use the
|
|
|
|
<methodname>OpenJPAEntityManager.getObjectId (Object entity)</methodname>
|
2006-09-05 15:28:36 -04:00
|
|
|
method. See <xref linkend="ref_guide_runtime_em"/> for more information on
|
2006-08-24 16:41:12 -04:00
|
|
|
the <classname>OpenJPAEntityManager</classname>.
|
|
|
|
</para>
|
2006-08-22 17:28:53 -04:00
|
|
|
<example id="ref_guide_pc_oid_datastoreentityex">
|
2006-08-24 16:41:12 -04:00
|
|
|
<title>
|
|
|
|
JPA Datastore Identity Metadata
|
|
|
|
</title>
|
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
import org.apache.openjpa.persistence.*;
|
|
|
|
|
|
|
|
@Entity
|
|
|
|
@DataStoreId
|
|
|
|
public class LineItem
|
|
|
|
{
|
|
|
|
... no @Id fields declared ...
|
|
|
|
}
|
|
|
|
</programlisting>
|
|
|
|
</example>
|
|
|
|
<section id="ref_guide_pc_oid_datastore">
|
2006-08-24 16:41:12 -04:00
|
|
|
<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>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_pc_oid_application">
|
2006-08-24 16:41:12 -04:00
|
|
|
<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>
|
2006-09-05 15:28:36 -04:00
|
|
|
<xref linkend="ref_guide_integration_appidtool"/> describes the
|
2006-08-24 16:41:12 -04:00
|
|
|
application identity tool's Ant task.
|
|
|
|
</para>
|
|
|
|
</note>
|
|
|
|
<example id="ref_guide_pc_appid_appidtool">
|
|
|
|
<title>
|
|
|
|
Using the Application Identity Tool
|
|
|
|
</title>
|
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
appidtool -s Id Magazine.java
|
|
|
|
</programlisting>
|
2006-08-24 16:41:12 -04:00
|
|
|
</example>
|
|
|
|
<para>
|
|
|
|
The application identity tool accepts the standard set of command-line arguments
|
|
|
|
defined by the configuration framework (see
|
2006-09-05 15:28:36 -04:00
|
|
|
<xref linkend="ref_guide_conf_devtools"/> ), including code formatting
|
|
|
|
flags described in <xref linkend="ref_guide_conf_devtools_format"/>. It
|
2006-08-24 16:41:12 -04:00
|
|
|
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
|
2006-09-05 15:28:36 -04:00
|
|
|
your persistent classes list (see <xref linkend="ref_guide_pc_pcclasses"/>
|
2006-08-24 16:41:12 -04:00
|
|
|
).
|
|
|
|
</para>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_pc_oid_pkgen_autoinc">
|
2006-08-24 16:41:12 -04:00
|
|
|
<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>
|
2006-09-05 15:28:36 -04:00
|
|
|
<xref linkend="jpa_overview_meta_gen"/> explains how to use JPA's
|
2006-08-24 16:41:12 -04:00
|
|
|
<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
|
2006-09-05 15:28:36 -04:00
|
|
|
(see <xref linkend="ref_guide_dbsetup_dbsupport_oracle"/> for how to
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
2006-08-24 16:41:12 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_inverses">
|
|
|
|
<title>
|
|
|
|
Managed Inverses
|
|
|
|
</title>
|
2006-08-22 17:28:53 -04:00
|
|
|
<indexterm zone="ref_guide_inverses">
|
2006-08-24 16:41:12 -04:00
|
|
|
<primary>
|
|
|
|
bidirectional relations
|
|
|
|
</primary>
|
|
|
|
<secondary>
|
|
|
|
automatic management
|
|
|
|
</secondary>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
Bidirectional relations are an essential part of data modeling.
|
2006-09-05 15:28:36 -04:00
|
|
|
<xref linkend="jpa_overview_mapping"/> in the JPA Overview explains how to
|
2006-08-24 16:41:12 -04:00
|
|
|
use the <literal>mappedBy</literal> annotation attribute to form bidirectional
|
|
|
|
relations that also share datastore storage in JPA.
|
|
|
|
</para>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
<example id="ref_guide_inverses_logicalex">
|
2006-08-24 16:41:12 -04:00
|
|
|
<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>
|
2006-08-22 17:28:53 -04:00
|
|
|
import org.apache.openjpa.persistence.*;
|
|
|
|
|
|
|
|
@Entity
|
|
|
|
public class Magazine
|
|
|
|
{
|
|
|
|
@OneToOne
|
|
|
|
private Photograph coverPhoto;
|
|
|
|
|
|
|
|
...
|
|
|
|
}
|
|
|
|
|
|
|
|
@Entity
|
|
|
|
public class Photograph
|
|
|
|
{
|
|
|
|
@OneToOne
|
|
|
|
@InverseLogical("coverPhoto")
|
|
|
|
private Magazine mag;
|
|
|
|
|
|
|
|
...
|
|
|
|
}
|
|
|
|
</programlisting>
|
2006-08-24 16:41:12 -04:00
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
<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>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
<example id="ref_guide_inversesex">
|
2006-08-24 16:41:12 -04:00
|
|
|
<title>
|
|
|
|
Enabling Managed Inverses
|
|
|
|
</title>
|
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
<property name="openjpa.InverseManager" value="true"/>
|
|
|
|
</programlisting>
|
|
|
|
</example>
|
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
<example id="ref_guide_inverses_logex">
|
2006-08-24 16:41:12 -04:00
|
|
|
<title>
|
|
|
|
Log Inconsistencies
|
|
|
|
</title>
|
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
<property name="openjpa.InverseManager" value="true(Action=warn)"/>
|
|
|
|
</programlisting>
|
|
|
|
</example>
|
2006-08-24 16:41:12 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_pc_scos">
|
|
|
|
<title>
|
|
|
|
Persistent Fields
|
|
|
|
</title>
|
2006-08-22 17:28:53 -04:00
|
|
|
<indexterm zone="ref_guide_pc_scos">
|
2006-08-24 16:41:12 -04:00
|
|
|
<primary>
|
|
|
|
persistent fields
|
|
|
|
</primary>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
<section id="ref_guide_pc_scos_restore">
|
2006-08-24 16:41:12 -04:00
|
|
|
<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>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_pc_scos_order">
|
2006-08-24 16:41:12 -04:00
|
|
|
<title>
|
|
|
|
Typing and Ordering
|
|
|
|
</title>
|
|
|
|
<indexterm zone="ref_guide_pc_scos_order">
|
|
|
|
<primary>
|
|
|
|
persistent fields
|
|
|
|
</primary>
|
|
|
|
<secondary>
|
|
|
|
comparators
|
|
|
|
</secondary>
|
|
|
|
</indexterm>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
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>
|
2006-08-24 16:41:12 -04:00
|
|
|
</example>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_pc_calendar_timezone">
|
2006-08-24 16:41:12 -04:00
|
|
|
<title>
|
|
|
|
Calendar Fields and TimeZones
|
|
|
|
</title>
|
|
|
|
<indexterm zone="ref_guide_pc_calendar_timezone">
|
|
|
|
<primary>
|
|
|
|
persistent fields
|
|
|
|
</primary>
|
|
|
|
<secondary>
|
|
|
|
calendar
|
|
|
|
</secondary>
|
|
|
|
</indexterm>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_pc_scos_proxy">
|
2006-08-24 16:41:12 -04:00
|
|
|
<title>
|
|
|
|
Proxies
|
|
|
|
</title>
|
|
|
|
<indexterm zone="ref_guide_pc_scos_proxy">
|
|
|
|
<primary>
|
|
|
|
proxies
|
|
|
|
</primary>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
2006-08-24 16:41:12 -04:00
|
|
|
<indexterm>
|
|
|
|
<primary>
|
|
|
|
persistent fields
|
|
|
|
</primary>
|
|
|
|
<secondary>
|
|
|
|
proxies
|
|
|
|
</secondary>
|
|
|
|
<see>
|
|
|
|
proxies
|
|
|
|
</see>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
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>
|
2006-08-24 16:41:12 -04:00
|
|
|
</example>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
<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>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-09-05 15:28:36 -04:00
|
|
|
The field cannot have an externalizer (see <xref linkend="ref_guide_pc_extern"/>
|
|
|
|
).
|
2006-08-24 16:41:12 -04:00
|
|
|
</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>
|
2006-08-22 17:28:53 -04:00
|
|
|
Collection employees = company.getEmployees () // employees is a lrs collection
|
|
|
|
company.setEmployees (null);
|
|
|
|
anotherCompany.setEmployees (employees);
|
|
|
|
</programlisting>
|
2006-08-24 16:41:12 -04:00
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<example id="ref_guide_pc_scos_proxy_lrs_extension">
|
|
|
|
<title>
|
|
|
|
Marking a Large Result Set Field
|
|
|
|
</title>
|
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
import org.apache.openjpa.persistence.*;
|
|
|
|
|
|
|
|
@Entity
|
|
|
|
public class Company
|
|
|
|
{
|
|
|
|
@ManyToMany
|
|
|
|
@LRS private Collection<Employee> employees;
|
|
|
|
|
|
|
|
...
|
|
|
|
}
|
|
|
|
</programlisting>
|
2006-08-24 16:41:12 -04:00
|
|
|
</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>
|
|
|
|
<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>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
2006-08-24 16:41:12 -04:00
|
|
|
<indexterm>
|
|
|
|
<primary>
|
|
|
|
persistent fields
|
|
|
|
</primary>
|
|
|
|
<secondary>
|
|
|
|
externalization
|
|
|
|
</secondary>
|
|
|
|
<see>
|
|
|
|
externalization
|
|
|
|
</see>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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.
|
2006-08-22 17:28:53 -04:00
|
|
|
</para>
|
2006-08-24 16:41:12 -04:00
|
|
|
<note>
|
|
|
|
<para>
|
|
|
|
Fields of embeddable classes used for <literal>@EmbeddedId</literal> values in
|
|
|
|
JPA cannot have externalizers.
|
|
|
|
</para>
|
|
|
|
</note>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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">
|
2006-09-05 15:28:36 -04:00
|
|
|
<colspec colname="method"/>
|
|
|
|
|
|
|
|
<colspec colname="extension"/>
|
|
|
|
|
2006-08-24 16:41:12 -04:00
|
|
|
<thead>
|
|
|
|
<row>
|
|
|
|
<entry colname="method">
|
|
|
|
Method
|
|
|
|
</entry>
|
|
|
|
<entry colname="extension">
|
|
|
|
Extension
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
|
|
|
<row>
|
|
|
|
<entry colname="method">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
public String CustomType.toString()
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
<entry colname="extension">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
@Externalizer("toString")
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
|
|
|
<entry colname="method">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
public String CustomType.toString(StoreContext ctx)
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
<entry colname="extension">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
@Externalizer("toString")
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
|
|
|
<entry colname="method">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
public static String AnyClass.toString(CustomType ct)
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
<entry colname="extension">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
@Externalizer("AnyClass.toString")
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
|
|
|
<entry colname="method">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
public static String AnyClass.toString(CustomType ct, StoreContext ctx)
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
<entry colname="extension">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
@Externalizer("AnyClass.toString")
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</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">
|
2006-09-05 15:28:36 -04:00
|
|
|
<colspec colname="method"/>
|
|
|
|
|
|
|
|
<colspec colname="extension"/>
|
|
|
|
|
2006-08-24 16:41:12 -04:00
|
|
|
<thead>
|
|
|
|
<row>
|
|
|
|
<entry colname="method">
|
|
|
|
Method
|
|
|
|
</entry>
|
|
|
|
<entry colname="extension">
|
|
|
|
Extension
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
|
|
|
<row>
|
|
|
|
<entry colname="method">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
public CustomType(String str)
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
<entry colname="extension">
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
none
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
|
|
|
<entry colname="method">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
public static CustomType CustomType.fromString(String str)
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
<entry colname="extension">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
@Factory("fromString")
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
|
|
|
<entry colname="method">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
public static CustomType CustomType.fromString(String str, StoreContext ctx)
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
<entry colname="extension">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
@Factory("fromString")
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
|
|
|
<entry colname="method">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
public static CustomType AnyClass.fromString(String str)
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
<entry colname="extension">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
@Factory("AnyClass.fromString")
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
<row>
|
|
|
|
<entry colname="method">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
public static CustomType AnyClass.fromString(String str, StoreContext ctx)
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
<entry colname="extension">
|
|
|
|
<literal>
|
|
|
|
|
2006-08-22 17:28:53 -04:00
|
|
|
@Factory("AnyClass.fromString")
|
2006-08-24 16:41:12 -04:00
|
|
|
|
|
|
|
</literal>
|
|
|
|
</entry>
|
|
|
|
</row>
|
|
|
|
</tbody>
|
|
|
|
</tgroup>
|
|
|
|
</table>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-09-05 15:28:36 -04:00
|
|
|
See <xref linkend="ref_guide_pc_scos_proxy"/> for a discussion of proxies.
|
2006-08-24 16:41:12 -04:00
|
|
|
</para>
|
|
|
|
</note>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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
|
2006-09-05 15:28:36 -04:00
|
|
|
externalized form of your fields - see <xref linkend="type"/>. If the
|
2006-08-24 16:41:12 -04:00
|
|
|
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.
|
2006-08-22 17:28:53 -04:00
|
|
|
</para>
|
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
The example below demonstrates a few forms of externalization.
|
|
|
|
</para>
|
|
|
|
<example id="ref_guide_pc_externex">
|
|
|
|
<title>
|
|
|
|
Using Externalization
|
|
|
|
</title>
|
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
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>
|
2006-08-24 16:41:12 -04:00
|
|
|
</example>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
<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>
|
2006-08-22 17:28:53 -04:00
|
|
|
// 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>
|
2006-08-24 16:41:12 -04:00
|
|
|
</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>
|
2006-08-22 17:28:53 -04:00
|
|
|
public class Magazine
|
|
|
|
{
|
|
|
|
@ExternalValues({"SMALL=5", "MEDIUM=8", "LARGE=10"})
|
|
|
|
@Type(int.class)
|
|
|
|
private String sizeWidth;
|
|
|
|
|
|
|
|
...
|
|
|
|
}
|
|
|
|
</programlisting>
|
2006-08-24 16:41:12 -04:00
|
|
|
</example>
|
|
|
|
</section>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
2006-08-24 16:41:12 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_fetch">
|
|
|
|
<title>
|
|
|
|
Fetch Groups
|
|
|
|
</title>
|
2006-08-22 17:28:53 -04:00
|
|
|
<indexterm zone="ref_guide_fetch">
|
2006-08-24 16:41:12 -04:00
|
|
|
<primary>
|
|
|
|
fetch groups
|
|
|
|
</primary>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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.
|
2006-08-22 17:28:53 -04:00
|
|
|
</para>
|
|
|
|
<para>
|
2006-09-05 15:28:36 -04:00
|
|
|
The JPA Overview's <xref linkend="jpa_overview_meta_fetch"/> describes how
|
2006-08-24 16:41:12 -04:00
|
|
|
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.
|
2006-08-22 17:28:53 -04:00
|
|
|
</para>
|
2006-08-24 16:41:12 -04:00
|
|
|
<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
|
2006-09-08 14:44:11 -04:00
|
|
|
rules into the built-in <emphasis>default</emphasis> fetch group. As its name
|
|
|
|
implies, the default fetch group is active by default. You may also
|
|
|
|
define your own named fetch groups and activate or deactivate them at runtime,
|
|
|
|
as described later in this chapter. OpenJPA will eagerly-load the fields in all
|
|
|
|
active fetch groups when loading objects from the datastore.
|
2006-08-24 16:41:12 -04:00
|
|
|
</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>jpa</literal>, or
|
|
|
|
<literal>openjpa</literal>.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
<literal>FetchAttribute[] attributes</literal>: The set of persistent fields or
|
|
|
|
properties in the fetch group.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<para>
|
|
|
|
<literal>String[] fetchGroups</literal>: Other fetch groups whose fields to
|
|
|
|
include in this 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>
|
2006-09-08 14:44:11 -04:00
|
|
|
<literal>recursionDepth</literal>: If the attribute represents a relation, the
|
|
|
|
maximum number of same-typed relations to eager-fetch from this field. Defaults
|
|
|
|
to 1. For example, consider an <classname>Employee</classname> class with a
|
|
|
|
<literal>manager</literal> field, also of type <classname>Employee</classname>.
|
|
|
|
When we load an <classname>Employee</classname> and the <literal>
|
|
|
|
manager</literal> field is in an active fetch group, the recursion depth (along
|
|
|
|
with the max fetch depth setting, described below) determines whether we only
|
|
|
|
retrieve the target <classname>Employee</classname> and his manager (depth 1),
|
|
|
|
or whether we also retrieve the manager's manager (depth 2), or the manager's
|
|
|
|
manager's manager (depth 3), etc. Use -1 for unlimited depth.
|
2006-08-24 16:41:12 -04:00
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
<example id="ref_guide_fetch_customgroups">
|
|
|
|
<title>
|
|
|
|
Custom Fetch Group Metadata
|
|
|
|
</title>
|
2006-09-08 14:44:11 -04:00
|
|
|
<para>
|
|
|
|
Creates a <emphasis>detail</emphasis> fetch group consisting of the
|
|
|
|
<literal>publisher</literal> and <literal>articles</literal> relations, use:
|
|
|
|
</para>
|
2006-08-24 16:41:12 -04:00
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
import org.apache.openjpa.persistence.*;
|
|
|
|
|
|
|
|
@Entity
|
|
|
|
@FetchGroups({
|
|
|
|
@FetchGroup(name="detail", attributes={
|
2006-09-08 14:44:11 -04:00
|
|
|
@FetchAttribute(name="publisher"),
|
|
|
|
@FetchAttribute(name="articles")
|
2006-08-22 17:28:53 -04:00
|
|
|
}),
|
|
|
|
...
|
|
|
|
})
|
|
|
|
public class Magazine
|
|
|
|
{
|
|
|
|
...
|
|
|
|
}
|
|
|
|
</programlisting>
|
2006-08-24 16:41:12 -04:00
|
|
|
</example>
|
2006-09-08 14:44:11 -04:00
|
|
|
<para>
|
|
|
|
A field can be a member of any number of fetch groups. A field can also
|
|
|
|
declare a <emphasis>load fetch group</emphasis>.
|
|
|
|
When you access a lazy-loaded field for the first time, OpenJPA makes a
|
|
|
|
datastore trip to fetch that field's data. Sometimes, however, you know
|
|
|
|
that whenever you access a lazy field A, you're likely to access lazy fields B
|
|
|
|
and C as well. Therefore, it would be more efficient to fetch the data for A,
|
|
|
|
B, and C in the same datastore trip. By setting A's load fetch group to the
|
|
|
|
name of a <link linkend="ref_guide_fetch">fetch group</link> containing B and
|
|
|
|
C, you can tell OpenJPA to load all of these fields together when A is first
|
|
|
|
accessed.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
Use OpenJPA's
|
|
|
|
<ulink url="../apidocs/org/apache/openjpa/persistence/LoadFetchGroup.html">
|
|
|
|
<classname>org.apache.openjpa.persistence.LoadFetchGroup</classname></ulink>
|
|
|
|
annotation to specify the load fetch group of any persistent field. The value of
|
|
|
|
the annotation is the name of a declared fetch group whose members should be
|
|
|
|
loaded along with the annotated field.
|
|
|
|
</para>
|
|
|
|
<example id="ref_guide_fetch_loadgroup">
|
|
|
|
<title>
|
|
|
|
Load Fetch Group Metadata
|
|
|
|
</title>
|
|
|
|
<programlisting>
|
|
|
|
import org.apache.openjpa.persistence.*;
|
|
|
|
|
|
|
|
@Entity
|
|
|
|
@FetchGroups({
|
|
|
|
@FetchGroup(name="detail", attributes={
|
|
|
|
@FetchAttribute(name="publisher"),
|
|
|
|
@FetchAttribute(name="articles")
|
|
|
|
}),
|
|
|
|
...
|
|
|
|
})
|
|
|
|
public class Magazine
|
|
|
|
{
|
|
|
|
@ManyToOne(fetch=FetchType.LAZY)
|
|
|
|
@LoadFetchGroup("detail")
|
|
|
|
private Publisher publisher;
|
|
|
|
|
|
|
|
...
|
|
|
|
}
|
|
|
|
</programlisting>
|
|
|
|
</example>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_fetch_conf">
|
2006-08-24 16:41:12 -04:00
|
|
|
<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>
|
2006-09-08 14:44:11 -04:00
|
|
|
You can also set the system's default maximum fetch depth with the
|
|
|
|
<link linkend="openjpa.MaxFetchDepth"><literal>openjpa.MaxFetchDepth</literal>
|
|
|
|
</link> configuration property. The maximum fetch depth determines how "deep"
|
|
|
|
into the object graph to traverse when loading an instance. The default maximum
|
|
|
|
depth is 1, meaning that OpenJPA will load at most the target instance and its
|
|
|
|
immediate relations. By increasing the depth, you can allow OpenJPA to also
|
|
|
|
load relations of relations, to arbitrary depth. A value of -1 symbolizes an
|
|
|
|
infinite maximum, telling OpenJPA to fetch configured relations until it reaches
|
|
|
|
the edges of the object graph. Of course, which relation fields are loaded
|
|
|
|
depends on whether the fields are eager or lazy, and on the active fetch groups.
|
|
|
|
A fetch group member's recursion depth may also limit the fetch depth to
|
|
|
|
something less than the configured maximum.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
OpenJPA's <classname>OpenJPAEntityManager</classname> and <classname>
|
2006-08-24 16:41:12 -04:00
|
|
|
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
|
2006-09-08 14:44:11 -04:00
|
|
|
<classname>FetchPlan</classname> maintains the set of active fetch groups and
|
|
|
|
the maximum fetch depth. It begins with the groups and depth defined in the
|
|
|
|
<literal>openjpa.FetchGroups</literal> and <literal>openjpa.MaxFetchDepth
|
|
|
|
</literal> properties, but allows you to add or remove groups and change the
|
|
|
|
maximum fetch depth for an individual <classname>EntityManager</classname> or
|
|
|
|
<classname>Query</classname> through the methods below.
|
2006-08-24 16:41:12 -04:00
|
|
|
</para>
|
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
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 ();
|
2006-09-08 14:44:11 -04:00
|
|
|
public FetchPlan setMaxFetchDepth(int depth);
|
|
|
|
public int getMaxFetchDepth();
|
2006-08-22 17:28:53 -04:00
|
|
|
</programlisting>
|
2006-08-24 16:41:12 -04:00
|
|
|
<para>
|
2006-09-05 15:28:36 -04:00
|
|
|
<xref linkend="ref_guide_runtime"/> details the <classname>
|
2006-08-24 16:41:12 -04:00
|
|
|
OpenJPAEntityManager</classname>, <classname>OpenJPAQuery</classname>, and
|
|
|
|
<classname>FetchPlan</classname> interfaces.
|
|
|
|
</para>
|
|
|
|
<example id="ref_guide_fetch_conf_query">
|
|
|
|
<title>
|
|
|
|
Using the FetchPlan
|
|
|
|
</title>
|
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
import org.apache.openjpa.persistence.*;
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
OpenJPAQuery kq = OpenJPAPersistence.cast (em.createQuery (...));
|
2006-09-08 14:44:11 -04:00
|
|
|
kq.getFetchPlan ().setMaxFetchDepth(3).addFetchGroup ("detail");
|
2006-08-22 17:28:53 -04:00
|
|
|
List results = kq.getResultList ();
|
|
|
|
</programlisting>
|
2006-08-24 16:41:12 -04:00
|
|
|
</example>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_fetch_single_field">
|
2006-08-24 16:41:12 -04:00
|
|
|
<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
|
2006-09-08 14:44:11 -04:00
|
|
|
plan. This allows you to add individual fields that are not in the
|
|
|
|
default fetch group or in any other active fetch groups to the set of
|
2006-08-24 16:41:12 -04:00
|
|
|
fields that will be eagerly loaded from the database.
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
JPA <classname>FetchPlan</classname> methods:
|
|
|
|
</para>
|
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
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>
|
2006-08-24 16:41:12 -04:00
|
|
|
<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>
|
2006-08-22 17:28:53 -04:00
|
|
|
import org.apache.openjpa.persistence.*;
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
OpenJPAEntityManager kem = OpenJPAPersistence.cast (em);
|
|
|
|
kem.getFetchPlan ().addField (Magazine.class, "publisher");
|
|
|
|
Magazine mag = em.find (Magazine.class, magId);
|
|
|
|
</programlisting>
|
2006-08-24 16:41:12 -04:00
|
|
|
</example>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_fetch_impl">
|
2006-08-24 16:41:12 -04:00
|
|
|
<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>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
2006-08-24 16:41:12 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_perfpack_eager">
|
|
|
|
<title>
|
|
|
|
Eager Fetching
|
|
|
|
</title>
|
2006-08-22 17:28:53 -04:00
|
|
|
<indexterm zone="ref_guide_perfpack_eager">
|
2006-08-24 16:41:12 -04:00
|
|
|
<primary>
|
|
|
|
eager fetching
|
|
|
|
</primary>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<indexterm>
|
2006-08-24 16:41:12 -04:00
|
|
|
<primary>
|
|
|
|
persistent fields
|
|
|
|
</primary>
|
|
|
|
<see>
|
|
|
|
eager fetching
|
|
|
|
</see>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<indexterm zone="ref_guide_perfpack_eager">
|
2006-08-24 16:41:12 -04:00
|
|
|
<primary>
|
|
|
|
fetch groups
|
|
|
|
</primary>
|
|
|
|
<secondary>
|
|
|
|
eager fetching
|
|
|
|
</secondary>
|
|
|
|
<seealso>
|
|
|
|
eager fetching
|
|
|
|
</seealso>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<indexterm>
|
2006-08-24 16:41:12 -04:00
|
|
|
<primary>
|
|
|
|
lazy loading
|
|
|
|
</primary>
|
|
|
|
<seealso>
|
|
|
|
eager fetching
|
|
|
|
</seealso>
|
|
|
|
<seealso>
|
|
|
|
fetch groups
|
|
|
|
</seealso>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-09-08 14:44:11 -04:00
|
|
|
Person</classname> instances turn out to be <classname>Employee</classname>s,
|
2006-08-24 16:41:12 -04:00
|
|
|
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.
|
2006-08-22 17:28:53 -04:00
|
|
|
</para>
|
2006-08-24 16:41:12 -04:00
|
|
|
<para>
|
2006-09-08 14:44:11 -04:00
|
|
|
Eager fetching only affects relations in the active fetch groups, and is limited
|
|
|
|
by the declared maximum fetch depth and field recursion depth (see
|
|
|
|
<xref linkend="ref_guide_fetch"/>). In other words, relations that would
|
2006-08-24 16:41:12 -04:00
|
|
|
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.
|
2006-08-22 17:28:53 -04:00
|
|
|
</para>
|
2006-08-24 16:41:12 -04:00
|
|
|
<para>
|
|
|
|
Eager fetching has three modes:
|
2006-08-22 17:28:53 -04:00
|
|
|
</para>
|
2006-08-24 16:41:12 -04:00
|
|
|
<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
|
2006-09-05 15:28:36 -04:00
|
|
|
<xref linkend="eager-fetch-mode"/>.
|
2006-08-24 16:41:12 -04:00
|
|
|
</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
|
2006-09-08 14:44:11 -04:00
|
|
|
<literal>traditional</literal>. See <xref linkend="ref_guide_dbsetup_sql92"/>.
|
2006-08-24 16:41:12 -04:00
|
|
|
</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
|
2006-09-05 15:28:36 -04:00
|
|
|
metadata extension described in <xref linkend="eager-fetch-mode"/>.
|
2006-08-24 16:41:12 -04:00
|
|
|
</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>
|
2006-08-22 17:28:53 -04:00
|
|
|
</itemizedlist>
|
|
|
|
<section id="ref_guide_perfpack_eager_conf">
|
2006-08-24 16:41:12 -04:00
|
|
|
<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
|
2006-09-05 15:28:36 -04:00
|
|
|
<xref linkend="ref_guide_runtime"/> for details.
|
2006-08-24 16:41:12 -04:00
|
|
|
</para>
|
|
|
|
<example id="ref_guide_perfpack_eager_def">
|
|
|
|
<title>
|
|
|
|
Setting the Default Eager Fetch Mode
|
|
|
|
</title>
|
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
<property name="openjpa.jdbc.EagerFetchMode" value="parallel"/>
|
|
|
|
<property name="openjpa.jdbc.SubclassFetchMode" value="join"/>
|
|
|
|
</programlisting>
|
2006-08-24 16:41:12 -04:00
|
|
|
</example>
|
|
|
|
<example id="ref_guide_perfpack_eager_runtime">
|
|
|
|
<title>
|
|
|
|
Setting the Eager Fetch Mode at Runtime
|
|
|
|
</title>
|
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
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>
|
2006-08-24 16:41:12 -04:00
|
|
|
</example>
|
|
|
|
<para>
|
|
|
|
You can specify a default subclass fetch mode for an individual class with the
|
2006-09-05 15:28:36 -04:00
|
|
|
metadata extension described in <xref linkend="subclass-fetch-mode"/>.
|
2006-08-24 16:41:12 -04:00
|
|
|
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
|
2006-09-05 15:28:36 -04:00
|
|
|
<xref linkend="eager-fetch-mode"/> ). You can use this extension to
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_perfpack_eager_consider">
|
2006-08-24 16:41:12 -04:00
|
|
|
<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
|
2006-09-05 15:28:36 -04:00
|
|
|
large result sets enabled (see <xref linkend="ref_guide_dbsetup_lrs"/>)
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
|
|
|
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
|
2006-09-08 14:44:11 -04:00
|
|
|
using the mapping extensions described in <xref linkend="nonpolymorphic"/>.
|
2006-08-24 16:41:12 -04:00
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
2006-08-24 16:41:12 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_lock_groups">
|
|
|
|
<title>
|
|
|
|
Lock Groups
|
|
|
|
</title>
|
2006-08-22 17:28:53 -04:00
|
|
|
<indexterm zone="ref_guide_lock_groups">
|
2006-08-24 16:41:12 -04:00
|
|
|
<primary>
|
|
|
|
locking
|
|
|
|
</primary>
|
|
|
|
<secondary>
|
|
|
|
lock groups
|
|
|
|
</secondary>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<indexterm zone="ref_guide_lock_groups">
|
2006-08-24 16:41:12 -04:00
|
|
|
<primary>
|
|
|
|
lock groups
|
|
|
|
</primary>
|
|
|
|
<seealso>
|
|
|
|
locking
|
|
|
|
</seealso>
|
2006-08-22 17:28:53 -04:00
|
|
|
</indexterm>
|
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
<para>
|
2006-08-24 16:41:12 -04:00
|
|
|
<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>
|
2006-09-05 15:28:36 -04:00
|
|
|
annotation.</phrase> See <xref linkend="lock-group"/> for details on lock
|
2006-08-24 16:41:12 -04:00
|
|
|
group metadata.
|
|
|
|
</para>
|
2006-08-22 17:28:53 -04:00
|
|
|
<example id="ref_guide_lock_groups_metadata">
|
2006-08-24 16:41:12 -04:00
|
|
|
<title>
|
|
|
|
Lock Group Metadata
|
|
|
|
</title>
|
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
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>
|
2006-08-24 16:41:12 -04:00
|
|
|
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>
|
2006-08-22 17:28:53 -04:00
|
|
|
<section id="ref_guide_lock_groups_and_subclasses">
|
2006-08-24 16:41:12 -04:00
|
|
|
<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>
|
|
|
|
<!-- ### -->
|
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
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>
|
2006-08-24 16:41:12 -04:00
|
|
|
<programlisting>
|
2006-08-22 17:28:53 -04:00
|
|
|
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>
|
2006-08-24 16:41:12 -04:00
|
|
|
</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>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
|
|
|
<section id="ref_guide_lock_group_mapping">
|
2006-08-24 16:41:12 -04:00
|
|
|
<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>
|
2006-08-22 17:28:53 -04:00
|
|
|
import org.apache.openjpa.persistence.jdbc.*;
|
|
|
|
|
|
|
|
@Entity
|
|
|
|
@Table(name="EMP")
|
|
|
|
@VersionColumns({
|
|
|
|
@VersionColumn(name="VERS_CORP" lockGroup="corporate"),
|
|
|
|
@VersionColumn(name="VERS")
|
|
|
|
})
|
|
|
|
public class Employee
|
|
|
|
{
|
|
|
|
...
|
|
|
|
}
|
|
|
|
</programlisting>
|
2006-08-24 16:41:12 -04:00
|
|
|
</example>
|
2006-08-22 17:28:53 -04:00
|
|
|
</section>
|
2006-08-24 16:41:12 -04:00
|
|
|
</section>
|
|
|
|
</chapter>
|