Skip Headers
Oracle TopLink Developer's Guide
10g Release 3 (10.1.3)
B13593-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
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.

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  follows
    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

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 Addresses, 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);