Understanding EclipseLink, 2.4
  Go To Table Of Contents
 Search
 PDF

Object-Relational Mapping Concepts

This section describes concepts for relational mappings that are unique to EclipseLink:

Indirection (Lazy Loading)

By default, when EclipseLink retrieves a persistent object, it retrieves all of the dependent objects to which it refers. When you configure indirection (also known as lazy reading, lazy loading, and just-in-time reading) for an attribute mapped with a relationship mapping, EclipseLink uses an indirection object as a place holder for the referenced object: EclipseLink defers reading the dependent object until you access that specific attribute. This can result in a significant performance improvement, especially if the application is interested only in the contents of the retrieved object, rather than the objects to which it is related.

Oracle strongly recommends using indirection for all relationship mappings. Not only does this lets you optimize data source access, but it also allows EclipseLink to optimize the unit of work processing, cache access, and concurrency.


NoteNote:

The use of indirection is especially important for providing a proper maintenance of bidirectional relationships. In this case, you must use indirection. If you are operating with collections, you must use transparent indirection (see Transparent Indirection).


Figure 7-8 shows an indirection example. Without indirection, reading the Order object also reads the dependent collection of LineItem objects. With indirection, reading the Order object does not read the dependent collection of LineItem objects: the lineItems attribute refers to an indirection object. You can access other attributes (such as customerId), but EclipseLink reads the dependent LineItem objects only if and when you access the lineItems attribute.

Figure 7-8 EclipseLink Indirection

Description of Figure 7-8 follows
Description of "Figure 7-8 EclipseLink Indirection"

EclipseLink supports the following types of indirection:

When using indirection with an object that your application serializes, you must consider the effect of any untriggered indirection objects at deserialization time. See Indirection, Serialization, and Detachment.

Value Holder Indirection

Persistent classes that use indirection must replace relationship attributes with value holder attributes. A value holder is an instance of a class that implements the ValueHolderInterface interface, such as ValueHolder. This object stores the information necessary to retrieve the object it is replacing from the database. If the application does not access the value holder, the replaced object is never read from the database.

To obtain the object that the value holder replaces, use the getValue and setValue methods of the ValueHolderInterface. A convenient way of using these methods is to hide the getValue and setValue methods of the ValueHolderInterface inside get and set methods, as shown in the following illustrations.

Figure 7-9 shows the Employee object being read from the database. The Address object is not read and will not be created unless it is accessed.

Figure 7-9 Address Object Not Read

Description of Figure 7-9 follows
Description of "Figure 7-9 Address Object Not Read"

The first time the address is accessed, as in Figure 7-10, the ValueHolder reads and returns the Address object.

Figure 7-10 Initial Request

Description of Figure 7-10 follows
Description of "Figure 7-10 Initial Request"

Subsequent requests for the address do not access the database, as shown in Figure 7-11.

Figure 7-11 Subsequent Requests

Description of Figure 7-11 follows
Description of "Figure 7-11 Subsequent Requests"

If you are using method access, the get and set methods specified in the mapping must access the instance of ValueHolderInterface, rather than the object referenced by the value holder. The application should not use these getter and setter, but use the getter and setter that hide the usage of value holders, for example:

public class Employee {
 
   private ValueHolderInterface addressValueHolder;
 
   // Use this get/set pair when configuring your Mapping
   public void setAddressValueHolder(ValueHolderInterface value) {
      this.addressValueHolder = value;
   }
   public ValueHolderInterface getAddressValueHolder() {
      return this.addressValueHolder;
   }
 
   // Your application uses these methods to interact with Addresses
   public void setAddress(Address address) {
      this.addressValueHolder.setValue(address);
   }
   public Address getAddress() {
      return this.addressValueHolder.getValue(address);
   }
 
}

Transparent Indirection

Transparent indirection lets you declare any relationship attribute of a persistent class that holds a collection of related objects as any of the following:

  • java.util.Collection

  • java.util.Hastable

  • java.util.List

  • java.util.Map

  • java.util.Set

  • java.util.Vector

EclipseLink will use an indirection object that implements the appropriate interface and also performs just-in-time reading of the related objects. When using transparent indirection, you do not have to declare the attributes as ValueHolderInterface.

Newly created collection mappings use transparent indirection by default if their attribute is not a ValueHolderInterface.

You can configure EclipseLink to automatically weave transparent indirect container indirection for JPA entities and Plain Old Java Object (POJO) classes. For more information, see Using Java Byte-code Weaving and About Weaving.

Proxy Indirection

The Java class Proxy lets you use dynamic proxy objects as place-holders for a defined interface. Certain EclipseLink mappings can be configured to use proxy indirection, which gives you the benefits of indirection without the need to include EclipseLink classes in your domain model. Proxy indirection is to one-to-one relationship mappings as indirect containers are to collection mappings.

To use proxy indirection, your domain model must satisfy all of the following criteria:

  • The target class of the one-to-one relationship must implement a public interface.

  • The one-to-one attribute on the source class must be of the interface type.

  • If you employ method accessing, then the getter and setter methods must use the interface.

Before using proxy indirection, be aware of the restrictions it places on how you use the unit of work (see Proxy Indirection Restrictions).

To configure proxy indirection, you can use JDeveloper or Java in an amendment method.

Proxy Indirection Restrictions

Proxy objects in Java are only able to intercept messages sent. If a primitive operation such as ==, instanceof, or getClass is used on a proxy, it will not be intercepted. This limitation can require the application to be somewhat aware of the usage of proxy objects.

You cannot register the target of a proxy indirection implementation with a unit of work. Instead, first register the source object with the unit of work. This lets you retrieve a target object clone with a call to a getter on the source object clone.

Weaved Indirection

For JPA entities or POJO classes that you configure for weaving, EclipseLink weaves value holder indirection for one-to-one mappings. If you want EclipseLink to weave change tracking and your application includes collection mappings (one-to-many or many-to-many), then you must configure all collection mappings to use transparent indirect container indirection only (you may not configure your collection mappings to use eager loading nor value holder indirection).

For more information, see Using Java Byte-code Weaving.

Indirection and JPA

When you set mapping annotation attribute fetch to lazy, the EclipseLink JPA persistence provider uses indirection.

By default, one-to-many and many-to-many relationships are lazy and use transparent indirection, while one-to-one and many-to-one relationships are not lazy.

If you set one-to-one or many-to-one relationships to lazy, and you enable weaving, the EclipseLink JPA persistence provider will use weaving to enable value holder indirection for these relationships.

For more information, see the following:

Indirection, Serialization, and Detachment

When using indirection (lazy loading), it is likely that a graph of persistent objects will contain untriggered indirection objects. Because indirection objects are transient and do not survive serialization between one JVM and another, untriggered indirection objects will trigger an error if the relationship is accessed after deserialization.

The application must ensure that any indirect relationships that will be required after deserialization have been instantiated before serialization. This can be done through accessing the get method for any relationship using ValueHolder or weaved indirection, and by calling the size method to any relationship using transparent indirection. If the application desired the relationships to be always instantiated on serialization, you could overwrite the serialization writeObject method in the persistent class to first instantiate the desired relationships. Use caution for objects with many or deep relationships to avoid serializing large object graphs: ideally, only the relationships required by the client should be instantiated.

When serializing JPA entities, any lazy relationships that have not been instantiated prior to serialization will trigger errors if they are accessed. If weaving is used on the server, and the entities are serialized to a client, the same weaved classes must exist on the client, either through static weaving of the jar, or through launching the client JVM using the EclipseLink agent.

For more information, see Using Java Byte-code Weaving.