blob: 7f0170b8312e8590a1666894c489b77a195b3200 [file] [log] [blame]
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>7.&nbsp; Fetch Groups</title><link rel="stylesheet" href="css/docbook.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.72.0"><link rel="start" href="manual.html" title="Apache OpenJPA User's Guide"><link rel="up" href="ref_guide_pc.html" title="Chapter&nbsp;5.&nbsp; Persistent Classes"><link rel="prev" href="ref_guide_pc_scos.html" title="6.&nbsp; Persistent Fields"><link rel="next" href="ref_guide_perfpack_eager.html" title="8.&nbsp; Eager Fetching"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">7.&nbsp;
Fetch Groups
</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ref_guide_pc_scos.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;5.&nbsp;
Persistent Classes
</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ref_guide_perfpack_eager.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="ref_guide_fetch"></a>7.&nbsp;
Fetch Groups
</h2></div></div></div><div class="toc"><dl><dt><span class="section"><a href="ref_guide_fetch.html#ref_guide_fetch_custom">7.1.
Custom Fetch Groups
</a></span></dt><dt><span class="section"><a href="ref_guide_fetch.html#ref_guide_fetch_conf">7.2.
Custom Fetch Group Configuration
</a></span></dt><dt><span class="section"><a href="ref_guide_fetch.html#ref_guide_fetch_single_field">7.3.
Per-field Fetch Configuration
</a></span></dt><dt><span class="section"><a href="ref_guide_fetch.html#ref_guide_fetch_impl">7.4.
Implementation Notes
</a></span></dt></dl></div><a class="indexterm" name="d0e22342"></a><p>
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.
</p><p>
The JPA Overview's <a href="jpa_overview_meta_field.html#jpa_overview_meta_fetch" title="2.6.1.&nbsp; Fetch Type">Section&nbsp;2.6.1, &#8220;
Fetch Type
&#8221;</a> 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.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ref_guide_fetch_custom"></a>7.1.&nbsp;
Custom Fetch Groups
</h3></div></div></div><p>
OpenJPA places any field that is eagerly loaded according to the JPA metadata
rules into the built-in <span class="emphasis"><em>default</em></span> 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.
</p><p>
You create fetch groups with the
<a xmlns:xlink="http://www.w3.org/1999/xlink" href="../javadoc/org/apache/openjpa/persistence/FetchGroup.html" target="_top">
<code class="classname">org.apache.openjpa.persistence.FetchGroup</code></a>
annotation. If your class only has one custom fetch group, you can place this
annotation directly on the class declaration. Otherwise, use the
<a xmlns:xlink="http://www.w3.org/1999/xlink" href="../javadoc/org/apache/openjpa/persistence/FetchGroups.html" target="_top">
<code class="classname">org.apache.openjpa.persistence.FetchGroups</code></a>
annotation to declare an array of individual <code class="classname">FetchGroup</code>
values. The <code class="classname">FetchGroup</code> annotation has the following
properties:
</p><div class="itemizedlist"><ul type="disc"><li><p>
<code class="literal">String name</code>: 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 <span class="emphasis"><em>detail</em></span> 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 <span class="emphasis"><em>list</em></span> fetch group
containing only the fields needed to display a table of products, as in a search
result.
</p><p>
The following names are reserved for use by OpenJPA: <code class="literal">default</code>
, <code class="literal">values</code>, <code class="literal">all</code>, <code class="literal">none</code>,
and any name beginning with <code class="literal">jdo</code>, <code class="literal">jpa</code>, or
<code class="literal">openjpa</code>.
</p></li><li><p>
<code class="literal">FetchAttribute[] attributes</code>: The set of persistent fields or
properties in the fetch group.
</p></li><li><p>
<code class="literal">String[] fetchGroups</code>: Other fetch groups whose fields to
include in this group.
</p></li></ul></div><p>
As you might expect, listing a
<a xmlns:xlink="http://www.w3.org/1999/xlink" href="../javadoc/org/apache/openjpa/persistence/FetchAttribute.html" target="_top">
<code class="classname">org.apache.openjpa.persistence.FetchAttribute</code></a>
within a <code class="classname">FetchGroup</code> includes the corresponding persistent
field or property in the fetch group. Each <code class="classname">FetchAttribute</code>
has the following properties:
</p><div class="itemizedlist"><ul type="disc"><li><p>
<code class="literal">String name</code>: The name of the persistent field or property to
include in the fetch group.
</p></li><li><p>
<code class="literal">recursionDepth</code>: 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 <code class="classname">Employee</code> class with a
<code class="literal">manager</code> field, also of type <code class="classname">Employee</code>.
When we load an <code class="classname">Employee</code> and the <code class="literal">
manager</code> 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 <code class="classname">Employee</code> 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.
</p></li></ul></div><div class="example"><a name="ref_guide_fetch_customgroups"></a><p class="title"><b>Example&nbsp;5.18.&nbsp;
Custom Fetch Group Metadata
</b></p><div class="example-contents"><p>
Creates a <span class="emphasis"><em>detail</em></span> fetch group consisting of the
<code class="literal">publisher</code> and <code class="literal">articles</code> relations.
</p><pre class="programlisting">
import org.apache.openjpa.persistence.*;
@Entity
@FetchGroups({
@FetchGroup(name="detail", attributes={
@FetchAttribute(name="publisher"),
@FetchAttribute(name="articles")
}),
...
})
public class Magazine {
...
}
</pre></div></div><br class="example-break"><p>
A field can be a member of any number of fetch groups. A field can also
declare a <span class="emphasis"><em>load fetch group</em></span>.
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 <a href="ref_guide_fetch.html" title="7.&nbsp; Fetch Groups">fetch group</a> containing B and
C, you can tell OpenJPA to load all of these fields together when A is first
accessed.
</p><p>
Use OpenJPA's
<a xmlns:xlink="http://www.w3.org/1999/xlink" href="../javadoc/org/apache/openjpa/persistence/LoadFetchGroup.html" target="_top">
<code class="classname">org.apache.openjpa.persistence.LoadFetchGroup</code></a>
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.
</p><div class="example"><a name="ref_guide_fetch_loadgroup"></a><p class="title"><b>Example&nbsp;5.19.&nbsp;
Load Fetch Group Metadata
</b></p><div class="example-contents"><pre class="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;
...
}
</pre></div></div><br class="example-break"></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ref_guide_fetch_conf"></a>7.2.&nbsp;
Custom Fetch Group Configuration
</h3></div></div></div><a class="indexterm" name="d0e22508"></a><p>
<a class="indexterm" name="d0e22515"></a>
You can control the default set of fetch groups with the
<a href="ref_guide_conf_openjpa.html#openjpa.FetchGroups" title="5.31.&nbsp; openjpa.FetchGroups"><code class="literal">openjpa.FetchGroups</code>
</a> configuration property. Set this property to a comma-separated list of
fetch group names.
</p><p>
You can also set the system's default maximum fetch depth with the
<a href="ref_guide_conf_openjpa.html#openjpa.MaxFetchDepth" title="5.41.&nbsp; openjpa.MaxFetchDepth"><code class="literal">openjpa.MaxFetchDepth</code>
</a> configuration property. The maximum fetch depth determines how "deep"
into the object graph to traverse when loading an instance. For example, with
a <code class="literal">MaxFetchDepth</code> of 1, OpenJPA will load at most the target
instance and its immediate relations. With a <code class="literal">MaxFetchDepth</code>
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 <code class="literal">MaxFetchDepth</code> 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.
</p><p>
OpenJPA's <code class="classname">OpenJPAEntityManager</code> and <code class="classname">
OpenJPAQuery</code> extensions to the standard <code class="classname">EntityManager
</code> and <code class="classname">Query</code> interfaces provide access to a
<a xmlns:xlink="http://www.w3.org/1999/xlink" href="../javadoc/org/apache/openjpa/persistence/FetchPlan.html" target="_top">
<code class="classname">org.apache.openjpa.persistence.FetchPlan</code></a> object.
The <code class="classname">FetchPlan</code> maintains the set of active fetch groups
and the maximum fetch depth. It begins with the groups and depth defined in the
<code class="literal">openjpa.FetchGroups</code> and <code class="literal">openjpa.MaxFetchDepth
</code> properties, but allows you to add or remove groups and change the
maximum fetch depth for an individual <code class="classname">EntityManager</code> or
<code class="classname">Query</code> through the methods below.
</p><pre class="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&lt;String&gt; getFetchGroups();
public void clearFetchGroups();
public FetchPlan setMaxFetchDepth(int depth);
public int getMaxFetchDepth();
</pre><p>
<a href="ref_guide_runtime.html" title="Chapter&nbsp;9.&nbsp; Runtime Extensions">Chapter&nbsp;9, <i xmlns:xlink="http://www.w3.org/1999/xlink">
Runtime Extensions
</i></a> details the <code class="classname">
OpenJPAEntityManager</code>, <code class="classname">OpenJPAQuery</code>, and
<code class="classname">FetchPlan</code> interfaces.
</p><div class="example"><a name="ref_guide_fetch_conf_query"></a><p class="title"><b>Example&nbsp;5.20.&nbsp;
Using the FetchPlan
</b></p><div class="example-contents"><pre class="programlisting">
import org.apache.openjpa.persistence.*;
...
OpenJPAQuery kq = OpenJPAPersistence.cast(em.createQuery(...));
kq.getFetchPlan().setMaxFetchDepth(3).addFetchGroup("detail");
List results = kq.getResultList();
</pre></div></div><br class="example-break"></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ref_guide_fetch_single_field"></a>7.3.&nbsp;
Per-field Fetch Configuration
</h3></div></div></div><a class="indexterm" name="d0e22599"></a><p>
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.
</p><p>
JPA <code class="classname">FetchPlan</code> methods:
</p><pre class="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&lt;String&gt; getFields();
public void clearFields();
</pre><p>
The methods that take only string arguments use the fully-qualified field name,
such as <code class="literal">org.mag.Magazine.publisher</code>. Similarly, <code class="methodname">
getFields</code> 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 <code class="literal">publisher</code> is
defined in base class <code class="classname">Publication</code> rather than subclass
<code class="classname">Magazine</code>, you must invoke <code class="literal">addField
(Publication.class, "publisher")</code> and not <code class="literal">addField
(Magazine.class, "publisher")</code>. This is stricter than Java's default
field-masking algorithms, which would allow the latter method behavior if
<code class="literal">Magazine</code> did not also define a field called <code class="literal">
publisher</code>.
</p><p>
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.
</p><div class="example"><a name="ref_guide_fetch-conf_per_field"></a><p class="title"><b>Example&nbsp;5.21.&nbsp;
Adding an Eager Field
</b></p><div class="example-contents"><pre class="programlisting">
import org.apache.openjpa.persistence.*;
...
OpenJPAEntityManager kem = OpenJPAPersistence.cast(em);
kem.getFetchPlan().addField(Magazine.class, "publisher");
Magazine mag = em.find(Magazine.class, magId);
</pre></div></div><br class="example-break"></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ref_guide_fetch_impl"></a>7.4.&nbsp;
Implementation Notes
</h3></div></div></div><div class="itemizedlist"><ul type="disc"><li><p>
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.
</p></li><li><p>
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.
</p></li></ul></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ref_guide_pc_scos.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ref_guide_pc.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ref_guide_perfpack_eager.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">6.&nbsp;
Persistent Fields
&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="manual.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;8.&nbsp;
Eager Fetching
</td></tr></table></div></body></html>