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