mirror of https://github.com/apache/openjpa.git
2546 lines
106 KiB
XML
2546 lines
106 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!--
|
|
Licensed to the Apache Software Foundation (ASF) under one
|
|
or more contributor license agreements. See the NOTICE file
|
|
distributed with this work for additional information
|
|
regarding copyright ownership. The ASF licenses this file
|
|
to you under the Apache License, Version 2.0 (the
|
|
"License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing,
|
|
software distributed under the License is distributed on an
|
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
KIND, either express or implied. See the License for the
|
|
specific language governing permissions and limitations
|
|
under the License.
|
|
-->
|
|
<chapter id="ref_guide_pc">
|
|
<title>
|
|
Persistent Classes
|
|
</title>
|
|
<indexterm zone="ref_guide_pc">
|
|
<primary>
|
|
persistent classes
|
|
</primary>
|
|
</indexterm>
|
|
<para>
|
|
Persistent class basics are covered in <xref linkend="jpa_overview_pc"/>
|
|
of the JPA Overview. This chapter details the persistent class features OpenJPA
|
|
offers beyond the core JPA specification.
|
|
</para>
|
|
<section id="ref_guide_pc_pcclasses">
|
|
<title>
|
|
Persistent Class List
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_pcclasses">
|
|
<primary>
|
|
persistent classes
|
|
</primary>
|
|
<secondary>
|
|
list
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm zone="ref_guide_pc_pcclasses">
|
|
<primary>
|
|
PCClasses
|
|
</primary>
|
|
</indexterm>
|
|
<para>
|
|
Unlike many ORM products, OpenJPA does not need to know about all of your
|
|
persistent classes at startup. OpenJPA discovers new persistent classes
|
|
automatically as they are loaded into the JVM; in fact you can introduce new
|
|
persistent classes into running applications under OpenJPA. However, there are
|
|
certain situations in which providing OpenJPA with a persistent class list is
|
|
helpful:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
OpenJPA must be able to match entity names in JPQL queries to persistent
|
|
classes. OpenJPA automatically knows the entity names of any persistent classes
|
|
already loaded into the JVM. To match entity names to classes that have not been
|
|
loaded, however, you must supply a persistent class list.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
When OpenJPA manipulates classes in a persistent inheritance hierarchy, OpenJPA
|
|
must be aware of all the classes in the hierarchy. If some of the classes have
|
|
not been loaded into the JVM yet, OpenJPA may not know about them, and queries
|
|
may return incorrect results.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
If you configure OpenJPA to create the needed database schema on startup (see
|
|
<xref linkend="ref_guide_mapping_synch"/>), OpenJPA must know all of your
|
|
persistent classes up-front.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
When any of these conditions are a factor in your JPA application, use the
|
|
<literal>class</literal>, <literal>mapping-file</literal>, and <literal>
|
|
jar-file</literal> elements of JPA's standard XML format to list your persistent
|
|
classes. See <xref linkend="jpa_overview_persistence_xml"/> for details.
|
|
</para>
|
|
<para>
|
|
Alternately, you can tell OpenJPA to search through your classpath for
|
|
persistent types. This is described in more detail in
|
|
<xref linkend="ref_guide_meta_factory"/>.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
Listing persistent classes (or their metadata or jar files) is an all-or-nothing
|
|
endeavor. If your persistent class list is non-empty, OpenJPA will assume that
|
|
any unlisted class is not persistent.
|
|
</para>
|
|
</note>
|
|
</section>
|
|
<section id="ref_guide_pc_enhance">
|
|
<title>
|
|
Enhancement
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_enhance">
|
|
<primary>
|
|
enhancer
|
|
</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
openjpac
|
|
</primary>
|
|
<see>
|
|
enhancer
|
|
</see>
|
|
</indexterm>
|
|
<para>
|
|
In order to provide optimal runtime performance, flexible lazy loading, and
|
|
efficient, immediate dirty tracking, OpenJPA can use 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. 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.
|
|
</para>
|
|
<mediaobject>
|
|
<imageobject>
|
|
<!-- PNG image data, 509 x 133 (see README) -->
|
|
<imagedata fileref="img/enhancement.png" width="339px"/>
|
|
</imageobject>
|
|
</mediaobject>
|
|
<para>
|
|
The diagram above illustrates the compilation of a persistent class.
|
|
</para>
|
|
<para>
|
|
You can add the OpenJPA enhancer to your build process, or use Java 1.5's
|
|
instrumentation features to transparently enhance persistent classes when they
|
|
are loaded into the JVM. The following sections describe each option.
|
|
</para>
|
|
<section id="ref_guide_pc_enhance_build">
|
|
<title>
|
|
Enhancing at Build Time
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_enhance_build">
|
|
<primary>
|
|
enhancer
|
|
</primary>
|
|
<secondary>
|
|
build time
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
The enhancer can be invoked at build time
|
|
via its Java class, <classname>
|
|
org.apache.openjpa.enhance.PCEnhancer</classname>.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
You can also enhance via Ant; see
|
|
<xref linkend="ref_guide_integration_enhance"/>.
|
|
</para>
|
|
</note>
|
|
<example id="ref_guide_pc_enhance_enhancer">
|
|
<title>
|
|
Using the OpenJPA Enhancer
|
|
</title>
|
|
<programlisting>
|
|
java org.apache.openjpa.enhance.PCEnhancer Magazine.java
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
The enhancer accepts the standard set of command-line arguments defined by the
|
|
configuration framework (see <xref linkend="ref_guide_conf_devtools"/> ),
|
|
along with the following flags:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<literal>-directory/-d <output directory></literal>: Path to the output
|
|
directory. If the directory does not match the enhanced class' package, the
|
|
package structure will be created beneath the directory. By default, the
|
|
enhancer overwrites the original <filename>.class</filename> file.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>-enforcePropertyRestrictions/-epr <true/t | false/f></literal>:
|
|
Whether to throw an exception when it appears that a property access entity is
|
|
not obeying the restrictions placed on property access. Defaults to false.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>-addDefaultConstructor/-adc <true/t | false/f></literal>: The
|
|
spec requires that all persistent classes define a no-arg constructor. This flag
|
|
tells the enhancer whether to add a protected no-arg constructor to any
|
|
persistent classes that don't already have one. Defaults to <literal>
|
|
true</literal>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>-tmpClassLoader/-tcl <true/t | false/f></literal>: Whether to
|
|
load persistent classes with a temporary class loader. This allows other code to
|
|
then load the enhanced version of the class within the same JVM. Defaults to
|
|
<literal>true</literal>. Try setting this flag to <literal>false</literal> as a
|
|
debugging step if you run into class loading problems when running the enhancer.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
Each additional argument to the enhancer must be one of the following:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
The full name of a class.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The .java file for a class.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The <filename>.class</filename> file of a class.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
If you do not supply any arguments to the enhancer, it will run on the classes
|
|
in your persistent class list (see <xref linkend="ref_guide_pc_pcclasses"/>).
|
|
</para>
|
|
<para>
|
|
You can run the enhancer over classes that have already been enhanced, in which
|
|
case it will not further modify the class. You can also run it over classes that
|
|
are not persistence-capable, in which case it will treat the class as
|
|
persistence-aware. Persistence-aware classes can directly manipulate the
|
|
persistent fields of persistence-capable classes.
|
|
</para>
|
|
<para>
|
|
Note that the enhancement process for subclasses introduces dependencies on the
|
|
persistent parent class being enhanced. This is normally not problematic;
|
|
however, when running the enhancer multiple times over a subclass whose parent
|
|
class is not yet enhanced, class loading errors can occur. In the event of a
|
|
class load error, simply re-compile and re-enhance the offending classes.
|
|
</para>
|
|
</section>
|
|
<section id="ref_guide_pc_enhance_runtime_container">
|
|
<title>
|
|
Enhancing JPA Entities on Deployment
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_enhance_runtime_container">
|
|
<primary>
|
|
enhancer
|
|
</primary>
|
|
<secondary>
|
|
runtime
|
|
</secondary>
|
|
<tertiary>
|
|
in an EJB container
|
|
</tertiary>
|
|
</indexterm>
|
|
<para>
|
|
The Java EE 5 specification includes hooks to automatically enhance JPA entities
|
|
when they are deployed into a container. Thus, if you are using a Java EE
|
|
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 Java EE 5 enhancement hooks,
|
|
consider using the build-time enhancement described above, or the more general
|
|
runtime enhancement described in the next section.
|
|
</para>
|
|
</section>
|
|
<section id="ref_guide_pc_enhance_runtime">
|
|
<title>
|
|
Enhancing at Runtime
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_enhance_runtime">
|
|
<primary>
|
|
enhancer
|
|
</primary>
|
|
<secondary>
|
|
runtime
|
|
</secondary>
|
|
<tertiary>
|
|
outside a container
|
|
</tertiary>
|
|
</indexterm>
|
|
<para>
|
|
OpenJPA includes a <emphasis>Java agent</emphasis> for automatically enhancing
|
|
persistent classes as they are loaded into the JVM. Java agents are classes that
|
|
are invoked prior to your application's <methodname>main</methodname> method.
|
|
OpenJPA's agent uses JVM hooks to intercept all class loading to enhance classes
|
|
that have persistence metadata before the JVM loads them.
|
|
</para>
|
|
<para>
|
|
Searching for metadata for every class loaded by the JVM can slow application
|
|
initialization. One way to speed things up is to take advantage of the optional
|
|
persistent class list described in <xref linkend="ref_guide_pc_pcclasses"/>. If
|
|
you declare a persistent class list, OpenJPA will only search for
|
|
metadata for classes in that list.
|
|
</para>
|
|
<para>
|
|
To employ the OpenJPA agent, invoke <literal>java</literal> with the <literal>
|
|
-javaagent</literal> set to the path to your OpenJPA jar file.
|
|
</para>
|
|
<example id="ref_guide_pc_enhance_runtime_ex">
|
|
<title>
|
|
Using the OpenJPA Agent for Runtime Enhancement
|
|
</title>
|
|
<programlisting>
|
|
java -javaagent:/home/dev/openjpa/lib/openjpa.jar com.xyz.Main
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
You can pass settings to the agent using OpenJPA's plugin syntax (see
|
|
<xref linkend="ref_guide_conf_plugins"/>). The agent accepts the long
|
|
form of any of the standard configuration options
|
|
(<xref linkend="ref_guide_conf_devtools"/> ). It also accepts the following
|
|
options, the first three of which correspond exactly to to the same-named
|
|
options of the enhancer tool described in
|
|
<xref linkend="ref_guide_pc_enhance_build"/>:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<literal>addDefaultConstructor</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>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>
|
|
<listitem>
|
|
<para>
|
|
<literal>classLoadEnhancement</literal>: Boolean controlling whether OpenJPA
|
|
load-time class enhancement should be available in this JVM execution. Default:
|
|
<literal>true</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>runtimeRedefinition</literal>: Boolean controlling whether OpenJPA
|
|
class redefinition should be available in this JVM execution. Default:
|
|
<literal>true</literal>
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<example id="ref_guide_pc_enhance_runtime_opt_ex">
|
|
<title>
|
|
Passing Options to the OpenJPA Agent
|
|
</title>
|
|
<programlisting>
|
|
java -javaagent:/home/dev/openjpa/lib/openjpa.jar=addDefaultConstructor=false com.xyz.Main
|
|
</programlisting>
|
|
</example>
|
|
</section>
|
|
<section id="ref_guide_pc_enhance_unenhanced_types">
|
|
<title>
|
|
Omitting the OpenJPA enhancer
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_enhance_unenhanced_types">
|
|
<primary>
|
|
enhancer
|
|
</primary>
|
|
<secondary>
|
|
omitting
|
|
</secondary>
|
|
<tertiary>
|
|
outside a container
|
|
</tertiary>
|
|
</indexterm>
|
|
<para>
|
|
OpenJPA does not require that the enhancer be run. If you do not run the
|
|
enhancer, OpenJPA will fall back to one of several possible alternatives for
|
|
state tracking, depending on the execution environment.
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
<emphasis>Deploy-time enhancement</emphasis>: if you are running your
|
|
application inside a Java EE 5 container, or another environment that supports
|
|
the JPA container contract, then OpenJPA will automatically perform class
|
|
transformation at deploy time.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<emphasis>Java 6 class retransformation</emphasis>: if you are running your
|
|
application in a Java 6 environment, OpenJPA will attempt to dynamically
|
|
register a <literal>ClassTransformer</literal> that will redefine your
|
|
persistent classes on the fly to track access to persistent data. Additionally,
|
|
OpenJPA will create a subclass for each of your persistent classes. When
|
|
you execute a query or traverse a relation, OpenJPA will return an instance
|
|
of the subclass. This means that the <literal>instanceof</literal> operator
|
|
will work as expected, but <literal>o.getClass()</literal> will return the
|
|
subclass instead of the class that you wrote.
|
|
</para>
|
|
<para>
|
|
You do not need to do anything at all to get this behavior. OpenJPA will
|
|
automatically detect whether or not the execution environment is capable of
|
|
Java 6 class retransformation.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<emphasis>Java 5 class redefinition</emphasis>: if you are running your
|
|
application in a Java 5 environment, and you specify the OpenJPA javaagent,
|
|
OpenJPA will use Java 5 class redefinition to redefine any persistent classes
|
|
that are not enhanced by the OpenJPA javaagent. Aside from the requirement
|
|
that you specify a javaagent on the command line, this behavior is exactly the
|
|
same as the Java 6 class retransformation behavior. Of course, since the
|
|
OpenJPA javaagent performs enhancement by default, this will only be available
|
|
if you set the <literal>classLoadEnhancement</literal> javaagent flag to
|
|
<literal>false</literal>, or on any classes that are skipped by the OpenJPA
|
|
runtime enhancement process for some reason.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<emphasis>state comparison and subclassing</emphasis>: if you are running
|
|
in a Java 5 environment without a javaagent, or in a Java 6 environment that
|
|
does not support class retransformation, OpenJPA will still create subclasses
|
|
as outlined above. However, in some cases, OpenJPA may not be able to receive
|
|
notifications when you read or write persistent data.
|
|
</para>
|
|
<para>
|
|
If you are using <emphasis>property access</emphasis> for your persistent data,
|
|
then OpenJPA will be able to track all accesses for instances that you load
|
|
from the database, but not for instances that you create. This is because
|
|
OpenJPA will create new instances of its dynamically-generated subclass when
|
|
it loads data from the database. The dynamically-generated subclass has
|
|
code in the setters and getters that notify OpenJPA about persistent data
|
|
access. This means that new instances that you create will be subject to
|
|
state-comparison checks (see discussion below) to compute which fields to
|
|
write to the database, and that OpenJPA will ignore requests to evict
|
|
persistent data from such instances. In practice, this is not a particularly
|
|
bad limitation, since OpenJPA already knows that it must insert all field
|
|
values for new instances. So, this is only really an issue if you flush
|
|
changes to the database while inserting new records; after such a flush,
|
|
OpenJPA will need to hold potentially-unneeded hard references to the
|
|
new-flushed instances.
|
|
</para>
|
|
<para>
|
|
If you are using <emphasis>field access</emphasis> for your persistent data,
|
|
then OpenJPA will not be able to track accesses for any instances, including
|
|
ones that you load from the database. So, OpenJPA will perform state-comparison
|
|
checks to determine which fields are dirty. These state comparison checks are
|
|
costly in two ways. First, there is a performance penalty at flush / commit
|
|
time, since OpenJPA must walk through every field of every instance to determine
|
|
which fields of which records are dirty. Second, there is a memory penalty,
|
|
since OpenJPA must hold hard references to all instances that were loaded at
|
|
any time in a given transaction, and since OpenJPA must keep a copy of all
|
|
the initial values of the loaded data for later comparison. Additionally,
|
|
OpenJPA will ignore requests to evict persistent state for these types of
|
|
instances. Finally, the default lazy loading configuration will be ignored for
|
|
single-valued fields (one-to-one, many-to-one, and any other non-collection
|
|
or non-map field that has a lazy loading configuration). If you use fetch
|
|
groups or programmatically configure your fetch plan, OpenJPA will obey these
|
|
directives, but will be unable to lazily load any data that you exclude from
|
|
loading. As a result of these limitations, it is not recommended that you use
|
|
field access if you are not either running the enhancer or using OpenJPA with
|
|
a javaagent or in a Java 6 environment.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
</section>
|
|
<section id="ref_guide_pc_interfaces">
|
|
<title>Managed Interfaces</title>
|
|
<indexterm zone="ref_guide_pc_interfaces">
|
|
<primary>interfaces</primary>
|
|
<secondary>managed</secondary>
|
|
</indexterm>
|
|
<para>
|
|
OpenJPA's managed interface feature allows you to define your object model
|
|
entirely in terms of interfaces, instead of concrete classes. To use this
|
|
feature, you must annotate your managed interfaces with the
|
|
<classname>ManagedInterface</classname> annotation, and use the
|
|
<literal>OpenJPAEntityManager.createInstance(Class)</literal> method to
|
|
create new records. Note that <literal>createInstance()</literal> returns
|
|
unmanaged instances; you must pass them to
|
|
<literal>EntityManager.persist()</literal> to store them in the database.
|
|
</para>
|
|
<programlisting>
|
|
@ManagedInterface
|
|
public interface PersonIface {
|
|
@Id @GeneratedValue
|
|
int getId();
|
|
void setId(int id);
|
|
|
|
// implicitly persistent per JPA property rules
|
|
String getName();
|
|
void setName(String name);
|
|
}
|
|
</programlisting>
|
|
<programlisting>
|
|
OpenJPAEntityManager em = ...;
|
|
PersonIface person = em.createInstance(PersonIface.class);
|
|
person.setName("Homer Simpson");
|
|
em.getTransaction().begin();
|
|
em.persist(person);
|
|
em.getTransaction().commit();
|
|
</programlisting>
|
|
</section>
|
|
<section id="ref_guide_pc_oid">
|
|
<title>
|
|
Object Identity
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_oid">
|
|
<primary>
|
|
identity
|
|
</primary>
|
|
</indexterm>
|
|
<para>
|
|
OpenJPA makes several enhancements to JPA's standard entity identity.
|
|
</para>
|
|
<section id="ref_guide_pc_oid_datastore">
|
|
<title>
|
|
Datastore Identity
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_oid_datastore">
|
|
<primary>
|
|
identity
|
|
</primary>
|
|
<secondary>
|
|
datastore
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
The JPA specification requires you to declare one or more identity fields in
|
|
your persistent classes. OpenJPA fully supports this form of object identity,
|
|
called <emphasis>application</emphasis> identity. OpenJPA, however, also
|
|
supports <emphasis>datastore</emphasis> identity. In datastore identity, you do
|
|
not declare any primary key fields. OpenJPA manages the identity of your
|
|
persistent objects for you through a surrogate key in the database.
|
|
</para>
|
|
<para>
|
|
You can control how your JPA datastore identity value is generated through
|
|
OpenJPA's
|
|
<ulink url="../javadoc/org/apache/openjpa/persistence/DataStoreId.html">
|
|
<classname>org.apache.openjpa.persistence.DataStoreId</classname></ulink> class
|
|
annotation. This annotation has <literal>strategy</literal> and <literal>
|
|
generator</literal> properties that mirror the same-named properties on the
|
|
standard <classname>javax.persistence.GeneratedValue</classname> annotation
|
|
described in <xref linkend="jpa_overview_meta_id"/> of the JPA Overview.
|
|
</para>
|
|
<para>
|
|
To retrieve the identity value of a datastore identity entity, use the
|
|
<methodname>OpenJPAEntityManager.getObjectId(Object entity)</methodname>
|
|
method. See <xref linkend="ref_guide_runtime_em"/> for more information on
|
|
the <classname>OpenJPAEntityManager</classname>.
|
|
</para>
|
|
<example id="ref_guide_pc_oid_datastoreentityex">
|
|
<title>
|
|
JPA Datastore Identity Metadata
|
|
</title>
|
|
<programlisting>
|
|
import org.apache.openjpa.persistence.*;
|
|
|
|
@Entity
|
|
@DataStoreId
|
|
public class LineItem {
|
|
|
|
... no @Id fields declared ...
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
Internally, OpenJPA uses the public
|
|
<ulink url="../javadoc/org/apache/openjpa/util/Id.html"><classname>
|
|
org.apache.openjpa.util.Id</classname></ulink> class for datastore identity
|
|
objects. When writing OpenJPA plugins, you can manipulate datastore identity
|
|
objects by casting them to this class. You can also create your own <classname>
|
|
Id</classname> instances and pass them to any internal OpenJPA method that
|
|
expects an identity object.
|
|
</para>
|
|
<para>
|
|
In JPA, you will never see <classname>Id</classname> instances directly.
|
|
Instead, calling <classname>OpenJPAEntityManager.getObjectId</classname> on a
|
|
datastore identity object will return the <classname>Long</classname> surrogate
|
|
primary key value for that object. You can then use this value in calls to
|
|
<classname>EntityManager.find</classname> for subsequent lookups of the same
|
|
record.
|
|
</para>
|
|
</section>
|
|
<section id="ref_guide_pc_oid_entitypk">
|
|
<title>
|
|
Entities as Identity Fields
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_oid_entitypk">
|
|
<primary>
|
|
identity
|
|
</primary>
|
|
<secondary>
|
|
application
|
|
</secondary>
|
|
<tertiary>
|
|
entity id fields
|
|
</tertiary>
|
|
</indexterm>
|
|
<para>
|
|
The JPA specification limits identity fields to simple types. OpenJPA, however,
|
|
also allows <literal>ManyToOne</literal> and <literal>OneToOne</literal>
|
|
relations to be identity fields. To identify a relation field as an identity
|
|
field, simply annotate it with both the <literal>@ManyToOne</literal> or
|
|
<literal>@OneToOne</literal> relation annotation and the <literal>@Id</literal>
|
|
identity annotation.
|
|
</para>
|
|
<para>
|
|
When finding an entity identified by a relation, pass the id of the
|
|
<emphasis>relation</emphasis> to the <methodname>EntityManager.find</methodname>
|
|
method:
|
|
</para>
|
|
<example id="ref_guide_pc_oid_entitypk_simplefind">
|
|
<title>
|
|
Finding an Entity with an Entity Identity Field
|
|
</title>
|
|
<programlisting>
|
|
public Delivery createDelivery(EntityManager em, Order order) {
|
|
Delivery delivery = new Delivery();
|
|
delivery.setId(o);
|
|
delivery.setDelivered(new Date());
|
|
return delivery;
|
|
}
|
|
|
|
public Delivery findDelivery(EntityManager em, Order order) {
|
|
// use the identity of the related instance
|
|
return em.find(Delivery.class, order.getId());
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
When your entity has multiple identity fields, at least one of which is a
|
|
relation to another entity, you must use an identity class (see
|
|
<xref linkend="jpa_overview_pc_identitycls"/> in the JPA Overview). You cannot
|
|
use an embedded identity object. Identity class fields corresponding to
|
|
entity identity fields should be of the same type as the related entity's
|
|
identity.
|
|
</para>
|
|
<example id="ref_guide_pc_oid_entitypk_idcls">
|
|
<title>
|
|
Id Class for Entity Identity Fields
|
|
</title>
|
|
<programlisting>
|
|
@Entity
|
|
public class Order {
|
|
|
|
@Id
|
|
private long id;
|
|
|
|
...
|
|
}
|
|
|
|
@Entity
|
|
@IdClass(LineItemId.class)
|
|
public class LineItem {
|
|
|
|
@Id
|
|
private int index;
|
|
|
|
@Id
|
|
@ManyToOne
|
|
private Order order;
|
|
|
|
...
|
|
}
|
|
|
|
public class LineItemId {
|
|
|
|
public int index;
|
|
public long order; // same type as order's identity
|
|
|
|
...
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
In the example above, if <classname>Order</classname> had used an identity
|
|
class <classname>OrderId</classname> in place of a simple <classname>long
|
|
</classname> value, then the <literal>LineItemId.order</literal> field would
|
|
have been of type <classname>OrderId</classname>.
|
|
</para>
|
|
</section>
|
|
<section id="ref_guide_pc_oid_application">
|
|
<title>
|
|
Application Identity Tool
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_oid_application">
|
|
<primary>
|
|
identity
|
|
</primary>
|
|
<secondary>
|
|
application
|
|
</secondary>
|
|
<tertiary>
|
|
application identity tool
|
|
</tertiary>
|
|
</indexterm>
|
|
<indexterm zone="ref_guide_pc_oid_application">
|
|
<primary>
|
|
application identity tool
|
|
</primary>
|
|
</indexterm>
|
|
<para>
|
|
If you choose to use application identity, you may want to take advantage of
|
|
OpenJPA'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 its Java class,
|
|
<ulink url="../javadoc/org/apache/openjpa/enhance/ApplicationIdTool">
|
|
<classname>org.apache.openjpa.enhance.ApplicationIdTool</classname></ulink>.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
<xref linkend="ref_guide_integration_appidtool"/> describes the
|
|
application identity tool's Ant task.
|
|
</para>
|
|
</note>
|
|
<example id="ref_guide_pc_appid_appidtool">
|
|
<title>
|
|
Using the Application Identity Tool
|
|
</title>
|
|
<programlisting>
|
|
java org.apache.openjpa.enhance.ApplicationIdTool -s Id Magazine.java
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
The application identity tool accepts the standard set of command-line arguments
|
|
defined by the configuration framework (see
|
|
<xref linkend="ref_guide_conf_devtools"/>), including code formatting
|
|
flags described in <xref linkend="ref_guide_conf_devtools_format"/>. It
|
|
also accepts the following arguments:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<literal>-directory/-d <output directory></literal>: Path to the output
|
|
directory. If the directory does not match the generated oid class' package, the
|
|
package structure will be created beneath the directory. If not specified, the
|
|
tool will first try to find the directory of the <filename>.java</filename> file
|
|
for the persistence-capable class, and failing that will use the current
|
|
directory.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>-ignoreErrors/-i <true/t | false/f></literal>: If <literal>false
|
|
</literal>, an exception will be thrown if the tool is run on any class that
|
|
does not use application identity, or is not the base class in the inheritance
|
|
hierarchy (recall that subclasses never define the application identity class;
|
|
they inherit it from their persistent superclass).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>-token/-t <token></literal>: The token to use to separate
|
|
stringified primary key values in the string form of the object id. This option
|
|
is only used if you have multiple primary key fields. It defaults to "::".
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>-name/-n <id class name></literal>: The name of the identity
|
|
class to generate. If this option is specified, you must run the tool on exactly
|
|
one class. If the class metadata already names an object id class, this option
|
|
is ignored. If the name is not fully qualified, the persistent class' package is
|
|
prepended to form the qualified name.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>-suffix/-s <id class suffix></literal>: A string to suffix each
|
|
persistent class name with to form the identity class name. This option is
|
|
overridden by <literal>-name</literal> or by any object id class specified in
|
|
metadata.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
Each additional argument to the tool must be one of the following:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
The full name of a persistent class.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The .java file for a persistent class.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The <filename>.class</filename> file of a persistent class.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
If you do not supply any arguments to the tool, it will act on the classes in
|
|
your persistent classes list (see <xref linkend="ref_guide_pc_pcclasses"/>).
|
|
</para>
|
|
</section>
|
|
<section id="ref_guide_pc_oid_pkgen_autoinc">
|
|
<title>
|
|
Autoassign / Identity Strategy Caveats
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_oid_pkgen_autoinc">
|
|
<primary>
|
|
datastore identity
|
|
</primary>
|
|
<secondary>
|
|
autoassign strategy
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm zone="ref_guide_pc_oid_pkgen_autoinc">
|
|
<primary>
|
|
datastore identity
|
|
</primary>
|
|
<secondary>
|
|
autoassign strategy
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm zone="ref_guide_pc_oid_pkgen_autoinc">
|
|
<primary>
|
|
persistent fields
|
|
</primary>
|
|
<secondary>
|
|
autoassign strategy
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
<xref linkend="jpa_overview_meta_gen"/> explains how to use JPA's
|
|
<literal>IDENTITY</literal> generation type to automatically assign field
|
|
values. However, here are some additional caveats you should be aware of when
|
|
using <literal>IDENTITY</literal> generation:
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
Your database must support auto-increment / identity columns, or some equivalent
|
|
(see <xref linkend="ref_guide_dbsetup_dbsupport_oracle"/> for how to
|
|
configure a combination of triggers and sequences to fake auto-increment support
|
|
in Oracle).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Auto-increment / identity columns must be an integer or long integer type.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Databases support auto-increment / identity columns to varying degrees. Some do
|
|
not support them at all. Others only allow a single such column per table, and
|
|
require that it be the primary key column. More lenient databases may allow
|
|
non-primary key auto-increment columns, and may allow more than one per table.
|
|
See your database documentation for details.
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</section>
|
|
</section>
|
|
<section id="ref_guide_inverses">
|
|
<title>
|
|
Managed Inverses
|
|
</title>
|
|
<indexterm zone="ref_guide_inverses">
|
|
<primary>
|
|
bidirectional relations
|
|
</primary>
|
|
<secondary>
|
|
automatic management
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
Bidirectional relations are an essential part of data modeling.
|
|
<xref linkend="jpa_overview_mapping"/> in the JPA Overview explains how to
|
|
use the <literal>mappedBy</literal> annotation attribute to form bidirectional
|
|
relations that also share datastore storage in JPA.
|
|
</para>
|
|
<para>
|
|
OpenJPA also allows you to define purely logical bidirectional relations. The
|
|
<ulink url="../javadoc/org/apache/openjpa/persistence/InverseLogical.html">
|
|
<classname>org.apache.openjpa.persistence.InverseLogical</classname></ulink>
|
|
annotation names a logical inverse in JPA metadata.
|
|
</para>
|
|
<example id="ref_guide_inverses_logicalex">
|
|
<title>
|
|
Specifying Logical Inverses
|
|
</title>
|
|
<para>
|
|
<literal>Magazine.coverPhoto</literal> and <literal>Photograph.mag</literal> are
|
|
each mapped to different foreign keys in their respective tables, but form a
|
|
logical bidirectional relation. Only one of the fields needs to declare the
|
|
other as its logical inverse, though it is not an error to set the logical
|
|
inverse of both fields.
|
|
</para>
|
|
<programlisting>
|
|
import org.apache.openjpa.persistence.*;
|
|
|
|
@Entity
|
|
public class Magazine {
|
|
|
|
@OneToOne
|
|
private Photograph coverPhoto;
|
|
|
|
...
|
|
}
|
|
|
|
@Entity
|
|
public class Photograph {
|
|
|
|
@OneToOne
|
|
@InverseLogical("coverPhoto")
|
|
private Magazine mag;
|
|
|
|
...
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
Java does not provide any native facilities to ensure that both sides of a
|
|
bidirectional relation remain consistent. Whenever you set one side of the
|
|
relation, you must manually set the other side as well.
|
|
</para>
|
|
<para>
|
|
By default, OpenJPA behaves the same way. OpenJPA does not automatically
|
|
propagate changes from one field in bidirectional relation to the other field.
|
|
This is in keeping with the philosophy of transparency, and also provides higher
|
|
performance, as OpenJPA does not need to analyze your object graph to correct
|
|
inconsistent relations.
|
|
</para>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
InverseManager
|
|
</primary>
|
|
</indexterm>
|
|
If convenience is more important to you than strict transparency, however, you
|
|
can enable inverse relation management in OpenJPA. Set the
|
|
<link linkend="openjpa.InverseManager"><classname>openjpa.InverseManager
|
|
</classname></link> plugin property to <literal>true</literal> for standard
|
|
management. Under this setting, OpenJPA detects changes to either side of a
|
|
bidirectional relation (logical or physical), and automatically sets the other
|
|
side appropriately on flush.
|
|
</para>
|
|
<example id="ref_guide_inversesex">
|
|
<title>
|
|
Enabling Managed Inverses
|
|
</title>
|
|
<programlisting>
|
|
<property name="openjpa.InverseManager" value="true"/>
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
The inverse manager has options to log a warning or throw an exception when it
|
|
detects an inconsistent bidirectional relation, rather than correcting it. To
|
|
use these modes, set the manager's <literal>Action</literal> property to
|
|
<literal>warn</literal> or <literal>exception</literal>, respectively.
|
|
</para>
|
|
<para>
|
|
By default, OpenJPA excludes <link linkend="ref_guide_pc_scos_proxy_lrs"> large
|
|
result set fields</link> from management. You can force large result set fields
|
|
to be included by setting the <literal>ManageLRS</literal> plugin property to
|
|
<literal>true</literal>.
|
|
</para>
|
|
<example id="ref_guide_inverses_logex">
|
|
<title>
|
|
Log Inconsistencies
|
|
</title>
|
|
<programlisting>
|
|
<property name="openjpa.InverseManager" value="true(Action=warn)"/>
|
|
</programlisting>
|
|
</example>
|
|
</section>
|
|
<section id="ref_guide_pc_scos">
|
|
<title>
|
|
Persistent Fields
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_scos">
|
|
<primary>
|
|
persistent fields
|
|
</primary>
|
|
</indexterm>
|
|
<para>
|
|
OpenJPA enhances the specification's support for persistent fields in many ways.
|
|
This section documents aspects of OpenJPA's persistent field handling that may
|
|
affect the way you design your persistent classes.
|
|
</para>
|
|
<section id="ref_guide_pc_scos_restore">
|
|
<title>
|
|
Restoring State
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_scos">
|
|
<primary>
|
|
persistent fields
|
|
</primary>
|
|
<secondary>
|
|
field rollback
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm zone="ref_guide_pc_scos_restore">
|
|
<primary>
|
|
RestoreState
|
|
</primary>
|
|
</indexterm>
|
|
<para>
|
|
While the JPA specification says that you should not use rolled back objects,
|
|
such objects are perfectly valid in OpenJPA. You can control whether the
|
|
objects' managed state is rolled back to its pre-transaction values with the
|
|
<link linkend="openjpa.RestoreState"><literal>openjpa.RestoreState</literal>
|
|
</link> configuration property. <literal>none</literal> does not roll back state
|
|
(the object becomes hollow, and will re-load its state the next time it is
|
|
accessed), <literal>immutable</literal> restores immutable values (primitives,
|
|
primitive wrappers, strings) and clears mutable values so that they are reloaded
|
|
on next access, and <literal>all</literal> restores all managed values to their
|
|
pre-transaction state.
|
|
</para>
|
|
</section>
|
|
<section id="ref_guide_pc_scos_order">
|
|
<title>
|
|
Typing and Ordering
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_scos_order">
|
|
<primary>
|
|
persistent fields
|
|
</primary>
|
|
<secondary>
|
|
comparators
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
When loading data into a field, OpenJPA examines the value you assign the field
|
|
in your declaration code or in your no-args constructor. If the field value's
|
|
type is more specific than the field's declared type, OpenJPA uses the value
|
|
type to hold the loaded data. OpenJPA also uses the comparator you've
|
|
initialized the field with, if any. Therefore, you can use custom comparators on
|
|
your persistent field simply by setting up the comparator and using it in your
|
|
field's initial value.
|
|
</para>
|
|
<example id="ref_guide_pc_scos_order_initialvals">
|
|
<title>
|
|
Using Initial Field Values
|
|
</title>
|
|
<para>
|
|
Though the annotations are left out for simplicity, assume <literal>
|
|
employeesBySal</literal> and <literal>departments</literal> are persistent
|
|
fields in the class below.
|
|
</para>
|
|
<programlisting>
|
|
public class Company {
|
|
|
|
// OpenJPA will detect the custom comparator in the initial field value
|
|
// and use it whenever loading data from the database into this field
|
|
private Collection employeesBySal = new TreeSet(new SalaryComparator());
|
|
private Map departments;
|
|
|
|
public Company {
|
|
// or we can initialize fields in our no-args constructor; even though
|
|
// this field is declared type Map, OpenJPA will detect that it's
|
|
// actually a TreeMap and use natural ordering for loaded data
|
|
departments = new TreeMap();
|
|
}
|
|
|
|
// rest of class definition...
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
</section>
|
|
<section id="ref_guide_pc_calendar_timezone">
|
|
<title>
|
|
Calendar Fields and TimeZones
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_calendar_timezone">
|
|
<primary>
|
|
persistent fields
|
|
</primary>
|
|
<secondary>
|
|
calendar
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
OpenJPA's support for the <classname>java.util.Calendar</classname> type will
|
|
store only the <classname>Date</classname> part of the field, not the
|
|
<classname>TimeZone</classname> associated with the field. When loading the date
|
|
into the <classname>Calendar</classname> field, OpenJPA will use the <classname>
|
|
TimeZone</classname> that was used to initialize the field.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
OpenJPA will automatically track changes made via modification methods in fields
|
|
of type <classname>Calendar</classname>, with one exception: when using Java
|
|
version 1.3, the <methodname>set()</methodname> method cannot be overridden, so
|
|
when altering the calendar using that method, the field must be explicitly
|
|
marked as dirty. This limitation does not apply when running with Java version
|
|
1.4 and higer.
|
|
</para>
|
|
</note>
|
|
</section>
|
|
<section id="ref_guide_pc_scos_proxy">
|
|
<title>
|
|
Proxies
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_scos_proxy">
|
|
<primary>
|
|
proxies
|
|
</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
persistent fields
|
|
</primary>
|
|
<secondary>
|
|
proxies
|
|
</secondary>
|
|
<see>
|
|
proxies
|
|
</see>
|
|
</indexterm>
|
|
<para>
|
|
At runtime, the values of all mutable second class object fields in persistent
|
|
and transactional objects are replaced with implementation-specific proxies. On
|
|
modification, these proxies notify their owning instance that they have been
|
|
changed, so that the appropriate updates can be made on the datastore.
|
|
</para>
|
|
<section id="ref_guide_pc_scos_proxy_smart">
|
|
<title>
|
|
Smart Proxies
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_scos_proxy_smart">
|
|
<primary>
|
|
proxies
|
|
</primary>
|
|
<secondary>
|
|
smart
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
Most proxies only track whether or not they have been modified. Smart proxies
|
|
for collection and map fields, however, keep a record of which elements have
|
|
been added, removed, and changed. This record enables the OpenJPA runtime to
|
|
make more efficient database updates on these fields.
|
|
</para>
|
|
<para>
|
|
When designing your persistent classes, keep in mind that you can optimize for
|
|
OpenJPA smart proxies by using fields of type <classname>java.util.Set
|
|
</classname>, <classname>java.util.TreeSet</classname>, and <classname>
|
|
java.util.HashSet</classname> for your collections whenever possible. Smart
|
|
proxies for these types are more efficient than proxies for <classname>
|
|
List</classname>s. You can also design your own smart proxies to further
|
|
optimize OpenJPA for your usage patterns. See the section on
|
|
<link linkend="ref_guide_pc_scos_proxy_custom">custom proxies</link> for
|
|
details.
|
|
</para>
|
|
</section>
|
|
<section id="ref_guide_pc_scos_proxy_lrs">
|
|
<title>
|
|
Large Result Set Proxies
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_scos_proxy_lrs">
|
|
<primary>
|
|
proxies
|
|
</primary>
|
|
<secondary>
|
|
large result set
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm zone="ref_guide_pc_scos_proxy_lrs">
|
|
<primary>
|
|
large result sets
|
|
</primary>
|
|
<secondary>
|
|
fields
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
Under standard ORM behavior, traversing a persistent collection or map field
|
|
brings the entire contents of that field into memory. Some persistent fields,
|
|
however, might represent huge amounts of data, to the point that attempting to
|
|
fully instantiate them can overwhelm the JVM or seriously degrade performance.
|
|
</para>
|
|
<para>
|
|
OpenJPA uses special proxy types to represent these "large result set" fields.
|
|
OpenJPA's large result set proxies do not cache any data in memory. Instead,
|
|
each operation on the proxy offloads the work to the database and returns the
|
|
proper result. For example, the <methodname>contains</methodname> method of a
|
|
large result set collection will perform a <literal> SELECT COUNT(*)</literal>
|
|
query with the proper <literal>WHERE</literal> conditions to find out if the
|
|
given element exists in the database's record of the collection. Similarly, each
|
|
time you obtain an iterator OpenJPA performs the proper query using the current
|
|
<link linkend="ref_guide_dbsetup_lrs">large result set settings</link>, as
|
|
discussed in the <link linkend="ref_guide_dbsetup">JDBC</link> chapter. As you
|
|
invoke <methodname>Iterator.next</methodname>, OpenJPA instantiates the result
|
|
objects on-demand.
|
|
</para>
|
|
<para>
|
|
You can free the resources used by a large result set iterator by passing it to
|
|
the static <link linkend="ref_guide_runtime_openjpapersistence"><methodname>
|
|
OpenJPAPersistence.close</methodname></link> method.
|
|
</para>
|
|
<example id="ref_guide_pc_scos_proxy_lrs_itr">
|
|
<title>
|
|
Using a Large Result Set Iterator
|
|
</title>
|
|
<programlisting>
|
|
import org.apache.openjpa.persistence.*;
|
|
|
|
...
|
|
|
|
Collection employees = company.getEmployees(); // employees is a lrs collection
|
|
Iterator itr = employees.iterator();
|
|
while (itr.hasNext())
|
|
process((Employee) itr.next());
|
|
OpenJPAPersistence.close(itr);
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
You can also add and remove from large result set proxies, just as with standard
|
|
fields. OpenJPA keeps a record of all changes to the elements of the proxy,
|
|
which it uses to make sure the proper results are always returned from
|
|
collection and map methods, and to update the field's database record on commit.
|
|
</para>
|
|
<para>
|
|
In order to use large result set proxies in JPA, add the
|
|
<ulink url="../javadoc/org/apache/openjpa/persistence/LRS.html"><classname>
|
|
org.apache.openjpa.persistence.LRS</classname></ulink> annotation to the
|
|
persistent field.
|
|
</para>
|
|
<para>
|
|
The following restrictions apply to large result set fields:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
The field must be declared as either a <classname>java.util.Collection
|
|
</classname> or <classname>java.util.Map</classname>. It cannot be declared as
|
|
any other type, including any sub-interface of collection or map, or any
|
|
concrete collection or map class.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The field cannot have an externalizer (see
|
|
<xref linkend="ref_guide_pc_extern"/>).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Because they rely on their owning object for context, large result set proxies
|
|
cannot be transferred from one persistent field to another. The following code
|
|
would result in an error on commit:
|
|
</para>
|
|
<programlisting>
|
|
Collection employees = company.getEmployees() // employees is a lrs collection
|
|
company.setEmployees(null);
|
|
anotherCompany.setEmployees(employees);
|
|
</programlisting>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<example id="ref_guide_pc_scos_proxy_lrs_extension">
|
|
<title>
|
|
Marking a Large Result Set Field
|
|
</title>
|
|
<programlisting>
|
|
import org.apache.openjpa.persistence.*;
|
|
|
|
@Entity
|
|
public class Company {
|
|
|
|
@ManyToMany
|
|
@LRS private Collection<Employee> employees;
|
|
|
|
...
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
</section>
|
|
<section id="ref_guide_pc_scos_proxy_custom">
|
|
<title>
|
|
Custom Proxies
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_scos_proxy_custom">
|
|
<primary>
|
|
proxies
|
|
</primary>
|
|
<secondary>
|
|
custom
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm zone="ref_guide_pc_scos_proxy_custom">
|
|
<primary>
|
|
proxies
|
|
</primary>
|
|
<secondary>
|
|
ProxyManager
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
OpenJPA manages proxies through the
|
|
<ulink url="../javadoc/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>
|
|
<listitem>
|
|
<para>
|
|
<literal>AssertAllowedType</literal>: Whether to immediately throw an exception
|
|
if you attempt to add an element to a collection or map that is not assignable
|
|
to the element type declared in metadata. Defaults to <literal>false</literal>.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
The default proxy manager can proxy the standard methods of any
|
|
<classname>Collection</classname>, <classname>List</classname>,
|
|
<classname>Map</classname>, <classname>Queue</classname>,
|
|
<classname>Date</classname>, or <classname>Calendar</classname> class,
|
|
including custom implementations. It can also proxy custom classes whose
|
|
accessor and mutator methods follow JavaBean naming conventions. Your custom
|
|
types must, however, meet the following criteria:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
Custom container types must have a public no-arg constructor or a public
|
|
constructor that takes a single <classname>Comparator</classname> parameter.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Custom date types must have a public no-arg constructor or a public
|
|
constructor that takes a single <classname>long</classname> parameter
|
|
representing the current time.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Other custom types must have a public no-arg constructor or a public copy
|
|
constructor. If a custom types does not have a copy constructor, it must be
|
|
possible to fully copy an instance A by creating a new instance B and calling
|
|
each of B's setters with the value from the corresponding getter on A.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
If you have custom classes that must be proxied and do not meet these
|
|
requirements, OpenJPA allows you to define your own proxy classes and
|
|
your own proxy manager. See the <literal>openjpa.util</literal> package
|
|
<ulink url="../javadoc/">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>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
persistent fields
|
|
</primary>
|
|
<secondary>
|
|
externalization
|
|
</secondary>
|
|
<see>
|
|
externalization
|
|
</see>
|
|
</indexterm>
|
|
<para>
|
|
OpenJPA offers the ability to write
|
|
<link linkend="ref_guide_mapping_custom_field">custom field mappings</link> in
|
|
order to have complete control over the mechanism with which fields are stored,
|
|
queried, and loaded from the datastore. Often, however, a custom mapping is
|
|
overkill. There is often a simple transformation from a Java field value to its
|
|
database representation. Thus, OpenJPA provides the externalization service.
|
|
Externalization allows you to specify methods that will externalize a field
|
|
value to its database equivalent on store and then rebuild the value from its
|
|
externalized form on load.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
Fields of embeddable classes used for <literal>@EmbeddedId</literal> values in
|
|
JPA cannot have externalizers.
|
|
</para>
|
|
</note>
|
|
<para>
|
|
The OpenJPA
|
|
<ulink url="../javadoc/org/apache/openjpa/persistence/Externalizer.html">
|
|
<classname>org.apache.openjpa.persistence.Externalizer</classname></ulink>
|
|
annotation 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="../javadoc/org/apache/openjpa/kernel/StoreContext.html"><classname>
|
|
StoreContext</classname></ulink> parameter for access to a persistence context.
|
|
The return value of the method is the field's external form. By default, OpenJPA
|
|
assumes that all named methods belong to the field value's class (or its
|
|
superclasses). You can, however, specify static methods of other classes using
|
|
the format <literal><class-name>.<method-name></literal>.
|
|
</para>
|
|
<para>
|
|
Given a field of type <classname>CustomType</classname> that externalizes to a
|
|
string, the table below demonstrates several possible externalizer methods and
|
|
their corresponding metadata extensions.
|
|
</para>
|
|
<table tocentry="1">
|
|
<title>
|
|
Externalizer Options
|
|
</title>
|
|
<tgroup cols="2" align="left" colsep="1" rowsep="1">
|
|
<colspec colname="method"/>
|
|
|
|
<colspec colname="extension"/>
|
|
|
|
<thead>
|
|
<row>
|
|
<entry colname="method">
|
|
Method
|
|
</entry>
|
|
<entry colname="extension">
|
|
Extension
|
|
</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry colname="method">
|
|
<literal>
|
|
public String CustomType.toString()
|
|
</literal>
|
|
</entry>
|
|
<entry colname="extension">
|
|
<literal>
|
|
@Externalizer("toString")
|
|
</literal>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry colname="method">
|
|
<literal>
|
|
public String CustomType.toString(StoreContext ctx)
|
|
</literal>
|
|
</entry>
|
|
<entry colname="extension">
|
|
<literal>
|
|
@Externalizer("toString")
|
|
</literal>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry colname="method">
|
|
<literal>
|
|
public static String AnyClass.toString(CustomType ct)
|
|
</literal>
|
|
</entry>
|
|
<entry colname="extension">
|
|
<literal>
|
|
@Externalizer("AnyClass.toString")
|
|
</literal>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry colname="method">
|
|
<literal>
|
|
public static String AnyClass.toString(CustomType ct, StoreContext ctx)
|
|
</literal>
|
|
</entry>
|
|
<entry colname="extension">
|
|
<literal>
|
|
@Externalizer("AnyClass.toString")
|
|
</literal>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
<para>
|
|
The OpenJPA
|
|
<ulink url="../javadoc/org/apache/openjpa/persistence/Factory.html"><classname>
|
|
org.apache.openjpa.persistence.Factory</classname></ulink> annotation
|
|
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 be invoked with the externalized value and must return an
|
|
instance of the field type. The method can also take an optional
|
|
<ulink url="../javadoc/org/apache/openjpa/kernel/StoreContext.html"><classname>
|
|
StoreContext</classname></ulink> parameter for access to a persistence context.
|
|
If a factory is not specified, OpenJPA will use the constructor of the field
|
|
type that takes a single argument of the external type, or will throw an
|
|
exception if no constructor with that signature exists.
|
|
</para>
|
|
<para>
|
|
Given a field of type <classname>CustomType</classname> that externalizes to a
|
|
string, the table below demonstrates several possible factory methods and their
|
|
corresponding metadata extensions.
|
|
</para>
|
|
<table tocentry="1">
|
|
<title>
|
|
Factory Options
|
|
</title>
|
|
<tgroup cols="2" align="left" colsep="1" rowsep="1">
|
|
<colspec colname="method"/>
|
|
<colspec colname="extension"/>
|
|
<thead>
|
|
<row>
|
|
<entry colname="method">
|
|
Method
|
|
</entry>
|
|
<entry colname="extension">
|
|
Extension
|
|
</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry colname="method">
|
|
<literal>
|
|
public CustomType(String str)
|
|
</literal>
|
|
</entry>
|
|
<entry colname="extension">
|
|
none
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry colname="method">
|
|
<literal>
|
|
public static CustomType CustomType.fromString(String str)
|
|
</literal>
|
|
</entry>
|
|
<entry colname="extension">
|
|
<literal>
|
|
@Factory("fromString")
|
|
</literal>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry colname="method">
|
|
<literal>
|
|
public static CustomType CustomType.fromString(String str, StoreContext ctx)
|
|
</literal>
|
|
</entry>
|
|
<entry colname="extension">
|
|
<literal>
|
|
@Factory("fromString")
|
|
</literal>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry colname="method">
|
|
<literal>
|
|
public static CustomType AnyClass.fromString(String str)
|
|
</literal>
|
|
</entry>
|
|
<entry colname="extension">
|
|
<literal>
|
|
@Factory("AnyClass.fromString")
|
|
</literal>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry colname="method">
|
|
<literal>
|
|
public static CustomType AnyClass.fromString(String str, StoreContext ctx)
|
|
</literal>
|
|
</entry>
|
|
<entry colname="extension">
|
|
<literal>
|
|
@Factory("AnyClass.fromString")
|
|
</literal>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
<para>
|
|
If your externalized field is not a standard persistent type, you must
|
|
explicitly mark it persistent. In OpenJPA, 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.
|
|
</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 manually, or create a custom field proxy.
|
|
See
|
|
<ulink url="../javadoc/org/apache/openjpa/persistence/OpenJPAEntityManager.html">
|
|
<methodname>OpenJPAEntityManager.dirty</methodname></ulink> for how to mark a
|
|
field dirty manually in JPA.
|
|
See <xref linkend="ref_guide_pc_scos_proxy"/> for a discussion of proxies.
|
|
</para>
|
|
</note>
|
|
<para>
|
|
You can externalize a field to virtually any value that is supported by
|
|
OpenJPA's field mappings (embedded relations are the exception; you must declare
|
|
your field to be a persistence-capable type in order to embed it). This means
|
|
that a field can externalize to something as simple as a primitive, something as
|
|
complex as a collection or map of entities, or anything in
|
|
between. If you do choose to externalize to a collection or map, OpenJPA
|
|
recognizes a family of metadata extensions for specying type information for the
|
|
externalized form of your fields - see <xref linkend="type"/>. If the
|
|
external form of your field is an entity object or contains entities, OpenJPA
|
|
will correctly include the objects in its persistence-by-reachability
|
|
algorithms and its delete-dependent algorithms.
|
|
</para>
|
|
<para>
|
|
The example below demonstrates a few forms of externalization.
|
|
</para>
|
|
<example id="ref_guide_pc_externex">
|
|
<title>
|
|
Using Externalization
|
|
</title>
|
|
<programlisting>
|
|
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
|
|
@Persistent
|
|
@Externalizer("Magazine.authorsFromCustomType")
|
|
@Factory("Magazine.authorsToCustomType")
|
|
@ElementType(Author.class)
|
|
private CustomType customType;
|
|
|
|
public static Collection authorsFromCustomType(CustomType customType) {
|
|
... logic to pack custom type into a list of authors ...
|
|
}
|
|
|
|
public static CustomType authorsToCustomType (Collection authors) {
|
|
... logic to create custom type from a collection of authors ...
|
|
}
|
|
|
|
...
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
externalization
|
|
</primary>
|
|
<secondary>
|
|
queries
|
|
</secondary>
|
|
</indexterm>
|
|
You can query externalized fields using parameters. Pass in a value of the field
|
|
type when executing the query. OpenJPA will externalize the parameter using the
|
|
externalizer method named in your metadata, and compare the externalized
|
|
parameter with the value stored in the database. As a shortcut, OpenJPA also
|
|
allows you to use parameters or literals of the field's externalized type in
|
|
queries, as demonstrated in the example below.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
Currently, queries are limited to fields that externalize to a primitive,
|
|
primitive wrapper, string, or date types, due to constraints on query syntax.
|
|
</para>
|
|
</note>
|
|
<example id="ref_guide_pc_extern_queryex">
|
|
<title>
|
|
Querying Externalization Fields
|
|
</title>
|
|
<para>
|
|
Assume the <classname>Magazine</classname> class has the same fields as in the
|
|
previous example.
|
|
</para>
|
|
<programlisting>
|
|
// you can query using parameters
|
|
Query q = em.createQuery("select m from Magazine m where m.url = :u");
|
|
q.setParameter("u", new URL("http://www.solarmetric.com"));
|
|
List results = q.getResultList();
|
|
|
|
// or as a shortcut, you can use the externalized form directly
|
|
q = em.createQuery("select m from Magazine m where m.url = 'http://www.solarmetric.com'");
|
|
results = q.getResultList();
|
|
</programlisting>
|
|
</example>
|
|
<section id="ref_guide_pc_extern_values">
|
|
<title>
|
|
External Values
|
|
</title>
|
|
<indexterm zone="ref_guide_pc_extern_values">
|
|
<primary>
|
|
externalization
|
|
</primary>
|
|
<secondary>
|
|
external values
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
Externalization often takes simple constant values and transforms them to
|
|
constant values of a different type. An example would be storing a <classname>
|
|
boolean</classname> field as a <classname>char</classname>, where <literal>true
|
|
</literal> and <literal>false</literal> would be stored in the database as
|
|
<literal>'T'</literal> and <literal>'F'</literal> respectively.
|
|
</para>
|
|
<para>
|
|
OpenJPA allows you to define these simple translations in metadata, so that the
|
|
field behaves as in <link linkend="ref_guide_pc_extern">full-fledged
|
|
externalization</link> without requiring externalizer and factory methods.
|
|
External values supports translation of pre-defined simple types (primitives,
|
|
primitive wrappers, and Strings), to other pre-defined simple values.
|
|
</para>
|
|
<para>
|
|
Use the OpenJPA
|
|
<ulink url="../javadoc/org/apache/openjpa/persistence/ExternalValues.html">
|
|
<classname>org.apache.openjpa.persistence.ExternalValues</classname></ulink>
|
|
annotation 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
|
|
<ulink url="../javadoc/org/apache/openjpa/persistence/Type.html">
|
|
<classname>org.apache.openjpa.persistence.Type</classname></ulink> annotation
|
|
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>
|
|
public class Magazine {
|
|
|
|
@ExternalValues({"SMALL=5", "MEDIUM=8", "LARGE=10"})
|
|
@Type(int.class)
|
|
private String sizeWidth;
|
|
|
|
...
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
</section>
|
|
</section>
|
|
</section>
|
|
<section id="ref_guide_fetch">
|
|
<title>
|
|
Fetch Groups
|
|
</title>
|
|
<indexterm zone="ref_guide_fetch">
|
|
<primary>
|
|
fetch groups
|
|
</primary>
|
|
</indexterm>
|
|
<para>
|
|
Fetch groups are sets of fields that load together. They can be used to to pool
|
|
together associated fields in order to provide performance improvements over
|
|
standard data fetching. Specifying fetch groups allows for tuning of lazy
|
|
loading and eager fetching behavior.
|
|
</para>
|
|
<para>
|
|
The JPA Overview's <xref linkend="jpa_overview_meta_fetch"/> describes how
|
|
to use JPA metadata annotations to control whether a field is fetched eagerly or
|
|
lazily. Fetch groups add a dynamic aspect to this standard ability. As you will
|
|
see, OpenJPA's JPA extensions allow you can add and remove fetch groups at
|
|
runtime to vary the sets of fields that are eagerly loaded.
|
|
</para>
|
|
<section id="ref_guide_fetch_custom">
|
|
<title>
|
|
Custom Fetch Groups
|
|
</title>
|
|
<para>
|
|
OpenJPA places any field that is eagerly loaded according to the JPA metadata
|
|
rules into the built-in <emphasis>default</emphasis> fetch group. 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.
|
|
</para>
|
|
<para>
|
|
You create fetch groups with the
|
|
<ulink url="../javadoc/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="../javadoc/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="../javadoc/org/apache/openjpa/persistence/FetchAttribute.html">
|
|
<classname>org.apache.openjpa.persistence.FetchAttribute</classname></ulink>
|
|
within a <classname>FetchGroup</classname> includes the corresponding persistent
|
|
field or property in the fetch group. Each <classname>FetchAttribute</classname>
|
|
has the following properties:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<literal>String name</literal>: The name of the persistent field or property to
|
|
include in the fetch group.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>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.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<example id="ref_guide_fetch_customgroups">
|
|
<title>
|
|
Custom Fetch Group Metadata
|
|
</title>
|
|
<para>
|
|
Creates a <emphasis>detail</emphasis> fetch group consisting of the
|
|
<literal>publisher</literal> and <literal>articles</literal> relations.
|
|
</para>
|
|
<programlisting>
|
|
import org.apache.openjpa.persistence.*;
|
|
|
|
@Entity
|
|
@FetchGroups({
|
|
@FetchGroup(name="detail", attributes={
|
|
@FetchAttribute(name="publisher"),
|
|
@FetchAttribute(name="articles")
|
|
}),
|
|
...
|
|
})
|
|
public class Magazine {
|
|
...
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
<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="../javadoc/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>
|
|
</section>
|
|
<section id="ref_guide_fetch_conf">
|
|
<title>
|
|
Custom Fetch Group Configuration
|
|
</title>
|
|
<indexterm zone="ref_guide_fetch_conf">
|
|
<primary>
|
|
fetch groups
|
|
</primary>
|
|
<secondary>
|
|
custom configuration
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
fetch groups
|
|
</primary>
|
|
<secondary>
|
|
FetchGroups
|
|
</secondary>
|
|
</indexterm>
|
|
You can control the default set of fetch groups with the
|
|
<link linkend="openjpa.FetchGroups"><literal>openjpa.FetchGroups</literal>
|
|
</link> configuration property. Set this property to a comma-separated list of
|
|
fetch group names.
|
|
</para>
|
|
<para>
|
|
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. For example, with
|
|
a <literal>MaxFetchDepth</literal> of 1, OpenJPA will load at most the target
|
|
instance and its immediate relations. With a <literal>MaxFetchDepth</literal>
|
|
of 2, OpenJPA may load the target instance, its immediate relations, and
|
|
the relations of those relations. This works to arbitrary depth. In fact,
|
|
the default <literal>MaxFetchDepth</literal> value is -1, which symbolizes
|
|
infinite depth. Under this setting, OpenJPA will 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>
|
|
OpenJPAQuery</classname> extensions to the standard <classname>EntityManager
|
|
</classname> and <classname>Query</classname> interfaces provide access to a
|
|
<ulink url="../javadoc/org/apache/openjpa/persistence/FetchPlan.html">
|
|
<classname>org.apache.openjpa.persistence.FetchPlan</classname></ulink> object.
|
|
The <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.
|
|
</para>
|
|
<programlisting>
|
|
public FetchPlan addFetchGroup(String group);
|
|
public FetchPlan addFetchGroups(String... groups);
|
|
public FetchPlan addFetchGroups(Collection groups);
|
|
public FetchPlan removeFetchGrop(String group);
|
|
public FetchPlan removeFetchGroups(String... groups);
|
|
public FetchPlan removeFetchGroups(Collection groups);
|
|
public FetchPlan resetFetchGroups();
|
|
public Collection<String> getFetchGroups();
|
|
public void clearFetchGroups();
|
|
public FetchPlan setMaxFetchDepth(int depth);
|
|
public int getMaxFetchDepth();
|
|
</programlisting>
|
|
<para>
|
|
<xref linkend="ref_guide_runtime"/> details the <classname>
|
|
OpenJPAEntityManager</classname>, <classname>OpenJPAQuery</classname>, and
|
|
<classname>FetchPlan</classname> interfaces.
|
|
</para>
|
|
<example id="ref_guide_fetch_conf_query">
|
|
<title>
|
|
Using the FetchPlan
|
|
</title>
|
|
<programlisting>
|
|
import org.apache.openjpa.persistence.*;
|
|
|
|
...
|
|
|
|
OpenJPAQuery kq = OpenJPAPersistence.cast(em.createQuery(...));
|
|
kq.getFetchPlan().setMaxFetchDepth(3).addFetchGroup("detail");
|
|
List results = kq.getResultList();
|
|
</programlisting>
|
|
</example>
|
|
</section>
|
|
<section id="ref_guide_fetch_single_field">
|
|
<title>
|
|
Per-field Fetch Configuration
|
|
</title>
|
|
<indexterm zone="ref_guide_fetch_single_field">
|
|
<primary>
|
|
fetch groups
|
|
</primary>
|
|
<secondary>
|
|
single fields
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
In addition to controlling fetch configuration on a per-fetch-group basis, you
|
|
can configure OpenJPA to include particular fields in the current fetch
|
|
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
|
|
fields that will be eagerly loaded from the database.
|
|
</para>
|
|
<para>
|
|
JPA <classname>FetchPlan</classname> methods:
|
|
</para>
|
|
<programlisting>
|
|
public FetchPlan addField(String field);
|
|
public FetchPlan addFields(String... fields);
|
|
public FetchPlan addFields(Class cls, String... fields);
|
|
public FetchPlan addFields(Collection fields);
|
|
public FetchPlan addFields(Class cls, Collection fields);
|
|
public FetchPlan removeField(String field);
|
|
public FetchPlan removeFields(String... fields);
|
|
public FetchPlan removeFields(Class cls, String... fields);
|
|
public FetchPlan removeFields(Collection fields);
|
|
public FetchPlan removeFields(Class cls, Collection fields);
|
|
public Collection<String> getFields();
|
|
public void clearFields();
|
|
</programlisting>
|
|
<para>
|
|
The methods that take only string arguments use the fully-qualified field name,
|
|
such as <literal>org.mag.Magazine.publisher</literal>. Similarly, <methodname>
|
|
getFields</methodname> returns the set of fully-qualified field names. In all
|
|
methods, the named field must be defined in the class specified in the
|
|
invocation, not a superclass. So, if the field <literal>publisher</literal> is
|
|
defined in base class <classname>Publication</classname> rather than subclass
|
|
<classname>Magazine</classname>, you must invoke <literal>addField
|
|
(Publication.class, "publisher")</literal> and not <literal>addField
|
|
(Magazine.class, "publisher")</literal>. This is stricter than Java's default
|
|
field-masking algorithms, which would allow the latter method behavior if
|
|
<literal>Magazine</literal> did not also define a field called <literal>
|
|
publisher</literal>.
|
|
</para>
|
|
<para>
|
|
In order to avoid the cost of reflection, OpenJPA does not perform any
|
|
validation of the field name / class name pairs that you put into the fetch
|
|
configuration. If you specify non-existent class / field pairs, nothing adverse
|
|
will happen, but you will receive no notification of the fact that the specified
|
|
configuration is not being used.
|
|
</para>
|
|
<example id="ref_guide_fetch-conf_per_field">
|
|
<title>
|
|
Adding an Eager Field
|
|
</title>
|
|
<programlisting>
|
|
import org.apache.openjpa.persistence.*;
|
|
|
|
...
|
|
|
|
OpenJPAEntityManager kem = OpenJPAPersistence.cast(em);
|
|
kem.getFetchPlan().addField(Magazine.class, "publisher");
|
|
Magazine mag = em.find(Magazine.class, magId);
|
|
</programlisting>
|
|
</example>
|
|
</section>
|
|
<section id="ref_guide_fetch_impl">
|
|
<title>
|
|
Implementation Notes
|
|
</title>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
Even when a direct relation is not eagerly fetched, OpenJPA selects the foreign
|
|
key columns and caches the values. This way when you do traverse the relation,
|
|
OpenJPA can often find the related object in its cache, or at least avoid joins
|
|
when loading the related object from the database.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The above implicit foreign key-selecting behavior does not always apply when the
|
|
relation is in a subclass table. If the subclass table would not otherwise be
|
|
joined into the select, OpenJPA avoids the extra join just to select the foreign
|
|
key values.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
</section>
|
|
<section id="ref_guide_perfpack_eager">
|
|
<title>
|
|
Eager Fetching
|
|
</title>
|
|
<indexterm zone="ref_guide_perfpack_eager">
|
|
<primary>
|
|
eager fetching
|
|
</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
persistent fields
|
|
</primary>
|
|
<see>
|
|
eager fetching
|
|
</see>
|
|
</indexterm>
|
|
<indexterm zone="ref_guide_perfpack_eager">
|
|
<primary>
|
|
fetch groups
|
|
</primary>
|
|
<secondary>
|
|
eager fetching
|
|
</secondary>
|
|
<seealso>
|
|
eager fetching
|
|
</seealso>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
lazy loading
|
|
</primary>
|
|
<seealso>
|
|
eager fetching
|
|
</seealso>
|
|
<seealso>
|
|
fetch groups
|
|
</seealso>
|
|
</indexterm>
|
|
<para>
|
|
Eager fetching is the ability to efficiently load subclass data and related
|
|
objects along with the base instances being queried. Typically, OpenJPA has to
|
|
make a trip to the database whenever a relation is loaded, or when you first
|
|
access data that is mapped to a table other than the least-derived superclass
|
|
table. If you perform a query that returns 100 <classname>Person</classname>
|
|
objects, and then you have to retrieve the <classname>Address</classname> for
|
|
each person, OpenJPA may make as many as 101 queries (the initial query, plus
|
|
one for the address of each person returned). Or if some of the <classname>
|
|
Person</classname> instances turn out to be <classname>Employee</classname>s,
|
|
where <classname>Employee</classname> has additional data in its own joined
|
|
table, OpenJPA once again might need to make extra database trips to access the
|
|
additional employee data. With eager fetching, OpenJPA can reduce these cases to
|
|
a single query.
|
|
</para>
|
|
<para>
|
|
Eager fetching only affects relations in the 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
|
|
not normally be loaded immediately when retrieving an object or accessing a
|
|
field are not affected by eager fetching. In our example above, the address of
|
|
each person would only be eagerly fetched if the query were configured to
|
|
include the address field or its fetch group, or if the address were in the
|
|
default fetch group. This allows you to control exactly which fields are eagerly
|
|
fetched in different situations. Similarly, queries that exclude subclasses
|
|
aren't affected by eager subclass fetching, described below.
|
|
</para>
|
|
<para>
|
|
Eager fetching has three modes:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<literal>none</literal>: No eager fetching is performed. Related objects are
|
|
always loaded in an independent select statement. No joined subclass data is
|
|
loaded unless it is in the table(s) for the base type being queried. Unjoined
|
|
subclass data is loaded using separate select statements rather than a SQL UNION
|
|
operation.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
eager fetching
|
|
</primary>
|
|
<secondary>
|
|
join mode
|
|
</secondary>
|
|
</indexterm>
|
|
<literal>join</literal>: In this mode, OpenJPA joins to to-one relations in the
|
|
configured fetch groups. If OpenJPA is loading data for a single instance, then
|
|
OpenJPA will also join to any collection field in the configured fetch groups.
|
|
When loading data for multiple instances, though, (such as when executing a
|
|
<classname>Query</classname>) OpenJPA will not join to collections by default.
|
|
Instead, OpenJPA defaults to <literal>parallel</literal> mode for collections,
|
|
as described below. You can force OpenJPA use a join rather than parallel mode
|
|
for a collection field using the metadata extension described in
|
|
<xref linkend="eager-fetch-mode"/>.
|
|
</para>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
outer joins
|
|
</primary>
|
|
</indexterm>
|
|
Under <literal>join</literal> mode, OpenJPA uses a left outer join (or inner
|
|
join, if the relations' field metadata declares the relation non-nullable) to
|
|
select the related data along with the data for the target objects. This process
|
|
works recursively for to-one joins, so that if <classname>Person</classname> has
|
|
an <classname>Address</classname>, and <classname>Address</classname> has a
|
|
<classname>TelephoneNumber</classname>, and the fetch groups are configured
|
|
correctly, OpenJPA might issue a single select that joins across the tables for
|
|
all three classes. To-many joins can not recursively spawn other to-many joins,
|
|
but they can spawn recursive to-one joins.
|
|
</para>
|
|
<para>
|
|
Under the <literal>join</literal> subclass fetch mode, subclass data in joined
|
|
tables is selected by outer joining to all possible subclass tables of the type
|
|
being queried. 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 outer joins. Also, OpenJPA can not use
|
|
outer joins if you have set the <link linkend="openjpa.jdbc.DBDictionary">
|
|
<literal> DBDictionary</literal></link>'s <literal>JoinSyntax</literal> to
|
|
<literal>traditional</literal>. See <xref linkend="ref_guide_dbsetup_sql92"/>.
|
|
</para>
|
|
</note>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
eager fetching
|
|
</primary>
|
|
<secondary>
|
|
parallel mode
|
|
</secondary>
|
|
</indexterm>
|
|
<literal>parallel</literal>: Under this mode, OpenJPA selects to-one relations
|
|
and joined collections as outlined in the <literal>join</literal> mode
|
|
description above. Unjoined collection fields, however, are eagerly fetched
|
|
using a separate select statement for each collection, executed in parallel with
|
|
the select statement for the target objects. The parallel selects use the
|
|
<literal>WHERE</literal> conditions from the primary select, but add their own
|
|
joins to reach the related data. Thus, if you perform a query that returns 100
|
|
<classname>Company</classname> objects, where each company has a list of
|
|
<classname>Employee</classname> objects and <classname>Department</classname>
|
|
objects, OpenJPA will make 3 queries. The first will select the company objects,
|
|
the second will select the employees for those companies, and the third will
|
|
select the departments for the same companies. Just as for joins, this process
|
|
can be recursively applied to the objects in the relations being eagerly
|
|
fetched. Continuing our example, if the <classname>Employee</classname> class
|
|
had a list of <classname>Projects</classname> in one of the fetch groups being
|
|
loaded, OpenJPA would execute a single additional select in parallel to load the
|
|
projects of all employees of the matching companies.
|
|
</para>
|
|
<para>
|
|
Using an additional select to load each collection avoids transferring more data
|
|
than necessary from the database to the application. If eager joins were used
|
|
instead of parallel select statements, each collection added to the configured
|
|
fetch groups would cause the amount of data being transferred to rise
|
|
dangerously, to the point that you could easily overwhelm the network.
|
|
</para>
|
|
<para>
|
|
Polymorphic to-one relations to table-per-class mappings use parallel eager
|
|
fetching because proper joins are impossible. You can force other to-one
|
|
relations to use parallel rather than join mode eager fetching using the
|
|
metadata extension described in <xref linkend="eager-fetch-mode"/>.
|
|
</para>
|
|
<para>
|
|
Parallel subclass fetch mode only applies to queries on joined inheritance
|
|
hierarchies. Rather than outer-joining to
|
|
subclass tables, OpenJPA will issue the query separately for each subclass. In
|
|
all other situations, parallel subclass fetch mode acts just like join mode in
|
|
regards to vertically-mapped subclasses.
|
|
</para>
|
|
<para>
|
|
When OpenJPA knows that it is selecting for a single object only, it never uses
|
|
<literal>parallel</literal> mode, because the additional selects can be made
|
|
lazily just as efficiently. This mode only increases efficiency over <literal>
|
|
join</literal> mode when multiple objects with eager relations are being loaded,
|
|
or when multiple selects might be faster than joining to all possible
|
|
subclasses.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<section id="ref_guide_perfpack_eager_conf">
|
|
<title>
|
|
Configuring Eager Fetching
|
|
</title>
|
|
<indexterm zone="ref_guide_perfpack_eager_conf">
|
|
<primary>
|
|
eager fetching
|
|
</primary>
|
|
<secondary>
|
|
configuration
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
EagerFetchMode
|
|
</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
SubclassFetchMode
|
|
</primary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
eager fetching
|
|
</primary>
|
|
<secondary>
|
|
EagerFetchMode
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
eager fetching
|
|
</primary>
|
|
<secondary>
|
|
SubclassFetchMode
|
|
</secondary>
|
|
</indexterm>
|
|
You can control OpenJPA's default eager fetch mode through the
|
|
<link linkend="openjpa.jdbc.EagerFetchMode"><literal>
|
|
openjpa.jdbc.EagerFetchMode</literal></link> and
|
|
<link linkend="openjpa.jdbc.SubclassFetchMode"><literal>
|
|
openjpa.jdbc.SubclassFetchMode</literal></link> configuration properties. Set
|
|
each of these properties to one of the mode names described in the previous
|
|
section: <literal>none, join, parallel</literal>. If left unset, the eager
|
|
fetch mode defaults to <literal>parallel</literal> and the subclass fetch mode
|
|
defaults to <literal>join</literal> These are generally the most robust and
|
|
performant strategies.
|
|
</para>
|
|
<para>
|
|
You can easily override the default fetch modes at runtime for any lookup or
|
|
query through OpenJPA's fetch configuration APIs. See
|
|
<xref linkend="ref_guide_runtime"/> for details.
|
|
</para>
|
|
<example id="ref_guide_perfpack_eager_def">
|
|
<title>
|
|
Setting the Default Eager Fetch Mode
|
|
</title>
|
|
<programlisting>
|
|
<property name="openjpa.jdbc.EagerFetchMode" value="parallel"/>
|
|
<property name="openjpa.jdbc.SubclassFetchMode" value="join"/>
|
|
</programlisting>
|
|
</example>
|
|
<example id="ref_guide_perfpack_eager_runtime">
|
|
<title>
|
|
Setting the Eager Fetch Mode at Runtime
|
|
</title>
|
|
<programlisting>
|
|
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(FetchMode.PARALLEL);
|
|
fetch.setSubclassFetchMode(FetchMode.JOIN);
|
|
List results = q.getResultList();
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
You can specify a default subclass fetch mode for an individual class with the
|
|
metadata extension described in <xref linkend="subclass-fetch-mode"/>.
|
|
Note, however, that you cannot "upgrade" the runtime fetch mode with your class
|
|
setting. If the runtime fetch mode is <literal>none</literal>, no eager
|
|
subclass data fetching will take place, regardless of your metadata setting.
|
|
</para>
|
|
<para>
|
|
This applies to the eager fetch mode metadata extension as well (see
|
|
<xref linkend="eager-fetch-mode"/>). You can use this extension to
|
|
disable eager fetching on a field or to declare that a collection would rather
|
|
use joins than parallel selects or vice versa. But an extension value of
|
|
<literal>join</literal> won't cause any eager joining if the fetch
|
|
configuration's setting is <literal>none</literal>.
|
|
</para>
|
|
</section>
|
|
<section id="ref_guide_perfpack_eager_consider">
|
|
<title>
|
|
Eager Fetching Considerations and Limitations
|
|
</title>
|
|
<para>
|
|
There are several important points that you should consider when using eager
|
|
fetching:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
eager fetching
|
|
</primary>
|
|
<secondary>
|
|
with large result sets
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
large result sets
|
|
</primary>
|
|
<secondary>
|
|
interaction with eager fetching
|
|
</secondary>
|
|
</indexterm>
|
|
When you are using <literal>parallel</literal> eager fetch mode and you have
|
|
large result sets enabled (see <xref linkend="ref_guide_dbsetup_lrs"/>)
|
|
or you place a range on a query, OpenJPA performs the needed parallel selects on
|
|
one page of results at a time. For example, suppose your <literal>
|
|
FetchBatchSize</literal> is set to 20, and you perform a large result set query
|
|
on a class that has collection fields in the configured fetch groups. OpenJPA
|
|
will immediately cache the first <literal>20</literal> results of the query
|
|
using <literal>join</literal> mode eager fetching only. Then, it will issue the
|
|
extra selects needed to eager fetch your collection fields according to
|
|
<literal>parallel</literal> mode. Each select will use a SQL <literal>IN
|
|
</literal> clause (or multiple <literal>OR</literal> clauses if your class has a
|
|
compound primary key) to limit the selected collection elements to those owned
|
|
by the 20 cached results.
|
|
</para>
|
|
<para>
|
|
Once you iterate past the first 20 results, OpenJPA will cache the next 20 and
|
|
again issue any needed extra selects for collection fields, and so on. This
|
|
pattern ensures that you get the benefits of eager fetching without bringing
|
|
more data into memory than anticipated.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Once OpenJPA eager-joins into a class, it cannot issue any further eager to-many
|
|
joins or parallel selects from that class in the same query. To-one joins,
|
|
however, can recurse to any level.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Using a to-many join makes it impossible to determine the number of instances
|
|
the result set contains without traversing the entire set. This is because each
|
|
result object might be represented by multiple rows. Thus, queries with a range
|
|
specification or queries configured for lazy result set traversal automatically
|
|
turn off eager to-many joining.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
OpenJPA cannot eagerly join to polymorphic relations to non-leaf classes in a
|
|
table-per-class inheritance hierarchy. You can work around this restriction
|
|
using the mapping extensions described in <xref linkend="nonpolymorphic"/>.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
</section>
|
|
</chapter>
|