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