Skip Headers

Oracle TopLink Developer's Guide 10g Release 3 (10.1.3) B13593-01 |
| Home | Solution Area | Contents | Index

Previous | Next |

# Configuring Indirection

By default, when TopLink retrieves a persistent object, it retrieves all of the dependent objects to which it refers. When you enable indirection for an attribute mapped with a relationship mapping, TopLink uses an indirection object as a placeholder for the referenced object: TopLink 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 refers.

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

Table 35-4 summarizes which mappings support this option.

Table 35-4 Mapping Support for Indirection

Mapping | Value Holder Indirection | Transparent Indirect Container Indirection | Proxy Indirection | Using TopLink Workbench | Using Java
--- | --- | --- | --- | --- | ---
Relational Mappings |  |  |  |  |
Direct-to-Field Mapping |  |  |  |  |
Transformation Mapping |  |  |  |  |
One-to-One Mapping |  |  |  |  |
Variable One-to-One Mapping |  |  |  |  |
One-to-Many Mapping |  |  |  |  |
Many-to-Many Mapping |  |  |  |  |
Aggregate Collection Mapping |  |  |  |  |
Direct Collection Mapping |  |  |  |  |
Direct Map Mapping |  |  |  |  |
Object-Relational Mappings |  |  |  |  |
Object-Relational Reference Mapping |  |  |  |  |
Object-Relational Nested Table Mapping |  |  |  |  |
EIS Mappings |  |  |  |  |
EIS One-to-One Mapping |  |  |  |  |
EIS One-to-Many Mapping |  |  |  |  |
XML Mappings |  |  |  |  |
XML Transformation Mapping |  |  |  |  |

In general, Oracle recommends that you use value holder indirection (see "Value Holder Indirection") for one-to-one mappings and transparent indirect container indirection (see "Transparent Indirect Container Indirection") for collection mappings. Enable indirection for transformation mappings if the execution of the transformation is a resource-intensive task (such as accessing a database, in a relational project).

When using indirection with EJB, the version of EJB and application server you use affects how indirection is configured and what types of indirection are applicable (see "Indirection and EJB").

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").

For more information, see "Indirection".

## Using TopLink Workbench

To complete the indirection options on a mapping's General tab use this procedure:

1. Select the mapped attribute in the Navigator. Its properties appear in the Editor.

2. Click the General tab. The General tab appears.

   Figure 35-2 General Tab, Indirection Options

   Description of "Figure 35-2 General Tab, Indirection Options"

Field | Description
--- | ---
Use Indirection | Specify if this mapping uses indirection.
ValueHolder | Specify that the mapping uses Value Holder indirection. See "Value Holder Indirection" for more information.
Proxy | Specify that the mapping uses Proxy indirection. See "Proxy Indirection" for more information.

## Using Java

When creating mappings through the Java API, all foreign reference mappings default to using value-holder indirection and all transformation mappings default to not using indirection.

To disable indirection use `ForeignReferenceMapping` method `dontUseIndirection`.

To enable value holder indirection, use `ForeignReferenceMapping` method `useBasicIndirection`.

To enable transparent container indirection, use one of the following `CollectionMapping` methods:

- `useTransparentCollection`

- `useTransparentList`

- `useTransparentMap`

- `useTransparentSet`

To enable proxy indirection, use `ObjectReferenceMapping` method `useProxyIndirection`.

This section provides additional information on the following:

- Configuring ValueHolder Indirection

- Configuring ValueHolder Indirection With Method Accessing

- Configuring ValueHolder Indirection With EJB 3.0 on OC4J

- Configuring IndirectContainer Indirection

- Configuring Proxy Indirection

### Configuring ValueHolder Indirection

Instances of `oracle.toplink.mappings.ForeignReferenceMapping` and `oracle.toplink.mappings.foundation.AbstractTransformationMapping` provide the `useBasicIndirection` method to configure a mapping to an attribute that you code with an `oracle.toplink.indirection.ValueHolderInterface` between it and the real object.

If the attribute is of a `Collection` type (such as a `Vector`), then you can either use an `IndirectContainer` (see "Configuring IndirectContainer Indirection") or define the `ValueHolder` in the constructor as follows:

`addresses = new ValueHolder(new Vector());`

Example 35-2 illustrates the `Employee` class using `ValueHolder` indirection. The class definition conceals the use of ValueHolder within the existing getter and setter methods.

Example 35-2 Class Using ValueHolder Indirection

    public class Employee {

        protected ValueHolderInterface address;

        // Initialize ValueHolders in constructor
        public Employee() {
            address = new ValueHolder();
        }

        public Address getAddress() {
            return (Address) this.addressHolder.getValue();
        }

        public void setAddress(Address address) {
            this.addressHolder.setValue(address);
        }
    }

Example 35-3 shows how to configure a one-to-one mapping to the `address` attribute.

Example 35-3 Mapping Using ValueHolder Indirection

    OneToOneMapping mapping = new OneToOneMapping();
    mapping.useBasicIndirection();
    mapping.setReferenceClass(Employee.class);
    mapping.setAttributeName("address");

The application uses `Employee` methods `getAddress` and `setAddress` to access the `Address` object. Because basic indirection is enabled, TopLink expects the persistent fields to be of type `ValueHolderInterface`.

### Configuring ValueHolder Indirection With Method Accessing

If you are using `ValueHolder` indirection with method accessing (see "Configuring Method Accessing"), in addition to changing your attributes types in your Java code to `ValueHolderInterface`, you must also provide TopLink with two pairs of getter and setter methods:

- getter and setter of the indirection object that are registered with the mapping and used only by TopLink. They include a `get` method that returns an instance that conforms to `ValueHolderInterface`, and a `set` method that accepts one argument that conforms to the same interface.

- getter and setter of the actual attribute value used by the application

Example 35-2 illustrates the `Employee` class using `ValueHolder` indirection with method access. The class definition is modified so that the `address` attribute of `Employee` is a `ValueHolderInterface` instead of an `Address`, and appropriate getter and setter methods are supplied.

Example 35-4 Class Using ValueHolder Indirection with Method Accessing

    public class Employee {

        protected ValueHolderInterface address;

        // Initialize ValueHolders in constructor
        public Employee() {
            address = new ValueHolder();
        }

        // getter and setter registered with the mapping and used only by TopLink
        public ValueHolderInterface getAddressHolder() {
            return address;
        }
        public void setAddressHolder(ValueHolderInterface holder) {
            address = holder;
        }

        // getter and setter methods used by the application to access the attribute
        public Address getAddress() {
            return (Address) address.getValue();
        }
        public void setAddress(Address theAddress) {
            address.setValue(theAddress);
        }
    }

Example 35-3 shows how to configure a one-to-one mapping to the `address` attribute.

Example 35-5 Mapping Using ValueHolder Indirection with Method Accessing

    OneToOneMapping mapping = new OneToOneMapping();
    mapping.useBasicIndirection();
    mapping.setReferenceClass(Employee.class);
    mapping.setAttributeName("address");
    mapping.setGetMethodName("getAddressHolder");
    mapping.setSetMethodName("setAddressHolder");

The application uses `Employee` methods `getAddress` and `setAddress` to access the `Address` object. Because basic indirection is enabled, TopLink uses `Employee` methods `getAddressHolder` and `setAddressHolder` methods when performing persistence operations on instances of `Employee`.

### Configuring ValueHolder Indirection With EJB 3.0 on OC4J

When using indirection with EJB 3.0 CMP on OC4J (see "EJB 3.0 CMP and OC4J"), if your application serializes any indirection-enabled EJB (see "Indirection, Serialization, and Detachment"), then, to preserve untriggered indirection objects on deserialization, configure your client to use the same Java agent that OC4J uses, as follows:

1. Include the following JAR files (from `<``TOPLINK_HOME``>\jlib`) in your client classpath:

   - `toplink.jar`

   - `toplink-agent.jar`

   - `asm.jar`

   - `asm-util.jar`

   - `ejb3-toplink-session.xml` (and whatever project deployment XML it refers to)

2. Add the following argument to the Java command line you use to start your client:

       -javaagent:toplink-agent.jar

### Configuring IndirectContainer Indirection

Instances of `oracle.toplink.mappings.ForeignReferenceMapping` and `oracle.toplink.mappings.foundation.AbstractTransformationMapping` provide the `useContainerIndirection` method to configure a mapping to an attribute that you code with an `oracle.toplink.indirection.IndirectContainer` between it and the real object.

Using an `IndirectContainer`, a `java.util.Collection` class can act as a TopLink indirection object: the `Collection` will only read its contents from the database when necessary (typically, when a `Collection` accessor is invoked). Without an `IndirectContainer`, all members of the `Collection` must be retrieved when the `Collection` attribute is accessed.

Example 35-2 illustrates the `Employee` class using `IndirectContainer` indirection with method access. The class definition is modified so that the `addresses` attribute of `Employee` is an `IndirectContainer` instead of an `Address`es, and appropriate getter and setter methods are supplied. In this example, `addresses` is a `java.util.List`, so an instance of `oracle.toplink.indirection.IndirectList` is used.

Example 35-6 Class Using IndirectContainer Indirection

    public class Employee {

        protected IndirectList addresses;

        // Initialize ValueHolders in constructor
        public Employee() {
            addresses = new IndirectList();
        }

        // getter and setter methods registered with the mapping and used by TopLink
        public ValueHolderInterface getAddressesHolder() {
            return addresses.getValueHolder();
        }
        public void setAddressesHolder(ValueHolderInterface holder) {
            addresses = addresses.setValueHolder(holder);
        }

        // getter and setter methods used by the application to access the attribute
        public List getAddresses() {
            return (List) addresses.getValue();
        }
        public void setAddresses(List newAddresses) {
            addresses.removeAll();
            addresses.addAll(newAddresses);
        }
    }

Example 35-3 shows how to configure a one-to-one mapping to the `addresses` attribute.

Example 35-7 Mapping Using IndirectContainer Indirection

    OneToOneMapping mapping = new OneToOneMapping();
    mapping.useBasicIndirection();
    mapping.setReferenceClass(Employee.class);
    mapping.setAttributeName("addresses");
    mapping.setGetMethodName("getAddressesHolder");
    mapping.setSetMethodName("setAddressesHolder");

### Configuring Proxy Indirection

Example 35-8 illustrates an `Employee` to `Address` one-to-one relationship.

Example 35-8 Proxy indirection Examples

    public interface Employee {
        public String getName();
        public Address getAddress();
        public void setName(String value);
        public void setAddress(Address value);
        . . .
    }
    public class EmployeeImpl implements Employee {
        public String name;
        public Address address;
        . . .
        public Address getAddress() {
            return this.address;
        }
        public void setAddress(Address value) {
            this.address = value;
        }
    }
    public interface Address {
        public String getStreet();
        public void setStreet(String value);
        . . .
    }
    public class AddressImpl implements Address {
        public String street;
        . . .
    }

In Example 35-8, both the `EmployeeImpl` and the `AddressImpl` classes implement public interfaces (`Employee` and `Address` respectively). Therefore, because the `AddressImpl` class is the target of the one-to-one relationship, it is the only class that must implement an interface. However, if the `EmployeeImpl` is ever to be the target of another one-to-one relationship using transparent indirection, it must also implement an interface, as shown in the following example:

    Employee emp = (Employee) session.readObject(Employee.class);
    System.out.println(emp.toString());
    System.out.println(emp.getAddress().toString());
    // Would print:
    [Employee] John Smith
    { IndirectProxy: not instantiated }
    String street = emp.getAddress().getStreet();
    // Triggers database read to get Address information
    System.out.println(emp.toString());
    System.out.println(emp.getAddress().toString());
    // Would print:
    [Employee] John Smith
    { [Address] 123 Main St. }

Using proxy indirection does not change how you instantiate your own domain objects for an insert operation. You still use the following code:

    Employee emp = new EmployeeImpl("John Smith");
    Address add = new AddressImpl("123 Main St.");
    emp.setAddress(add);