Skip Headers
Oracle® Application Server TopLink Application Developer's Guide
10g Release 2 (10.1.2)
Part No. B15901-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
 

Advanced Mappings

Several complex mappings are available in OracleAS TopLink. This section discusses the following mapping types:

Transformation Mappings

Transformation mappings enable you to create specialized translations between how a value is represented in Java and in the database. Use transformation mappings only when mapping multiple fields into a single attribute. Transformation mapping is often appropriate when you use values from multiple fields to create an object.


Note:

Because of the complexity of transformation mappings, it is often easier to perform the transformation with get and set methods of a direct-to-field mapping.

After you create the required transformation method, use OracleAS TopLink Mapping Workbench to implement transformation mappings.

For more information, see "Working with Transformation Mappings" in the Oracle Application Server TopLink Mapping Workbench User's Guide.

Implementing Transformation Mappings in Java

Transformation mappings are instances of the TransformationMapping class and require the following elements:

  • The attribute to be mapped, set by sending the setAttributeName() message; not required for write-only mappings

  • The method to be invoked that sets the value of the attribute from information in the database row; set by sending the setAttributeTransformation() message that expects one or two parameters: a DatabaseRow and optionally a Session

  • A set of methods associated to fields in the database, where the value for each field is the result of invoking the associated method; associations are made by sending the addFieldTransformation() message, passing along the database field name and the method name

Use the optional setGetMethodName() and setSetMethodName() messages to access the attribute through user-defined methods, rather than directly.

Example 3-32 Creating a Transformation Mapping and Registering It with the Descriptor

This example provides custom support for two fields. You can use this approach to map any number of fields.

// Create a new mapping and register it with the descriptor.
TransformationMapping transformation1 = new TransformationMapping();
transformation1.setAttributeName ("dateAndTimeOfBirth");
transformation1.setAttributeTransformation ("buildDateAndTime");
transformation1.addFieldTransformation("B_DAY", "getDateOfBirth");
transformation1.addFieldTransformation("B_TIME", "getTimeOfBirth");
descriptor.addMapping(transformation1);
// Define attribute transformation method to read from the database row
public java.util.Date buildDateAndTime(DatabaseRow row) {
    java.sql.Date sqlDateOfBirth = (java.sql.Date)row.get("B_DAY");
    java.sql.Time timeOfBirth = (java.sql.Time)row.get("B_TIME");
    java.util.Date utilDateOfBirth = new java.util.Date(
        sqlDateOfBirth.getYear(),
        sqlDateOfBirth.getMonth(),
        sqlDateOfBirth.getDate(),
        timeOfBirth.getHours(),
        timeOfBirth.getMinutes(),
        timeOfBirth.getSeconds());
    return utilDateOfBirth;
}

// Define a field transformation method to write to the database
public java.sql.Time getTimeOfBirth()
{
    return new java.sql.Time this.dateAndTimeOfBirth.getHours(),
       this. dateAndTimeOfBirth.getMinutes(),
      this.dateAndTimeOfBirth.getSeconds()); 
}

// Define a field transformation method to write to the database
public java.sql.Date getDateOfBirth()
{
    return new java.sql.DateOfBirth this.dateAndTimeOfBirth.getYear(),
      this.dateAndTimeOfBirth.getMonth(), this.dateAndTimeOfBirth.getDate());
}

Example 3-33 Creating a Transformation Mapping Using Indirection

// Create a new mapping and register it with the descriptor.
TransformationMapping transformation2 = new transformation2.setAttributeName("designation");
transformation2.setGetMethodName ("getDesignationHolder");
transformation2.setSetMethodName ("setDesignationHolder");
transformation2.setAttributeTransformation ("getRankFromRow");
transformation2.addFieldTransformation("RANK", "getRankFromObject");
transformation2.useIndirection();
descriptor.addMapping(transformation2);

//Define an attribute transformation method to read from database row.
public String getRankFromRow() 
{
    Integer value = new Integer(((Number)row.get("RANK)).intValue());
    String rank = null;
    if (value.intValue() == 1) {
        rank = "Executive";
    }
    if (value.intValue() == 2) {
        rank = "Non-Executive";
    }
    return rank;
}
//Define a field transformation method to write to the database.
public Integer getRankFromObject()
{
    Integer rank = null;

    if (getDesignation().equals("Executive")) rank = new Integer(1);
    if (getDesignation().equals("Non-Executive")) rank = new Integer(2);
    return rank;
}

//Provide accessor methods for the indirection.
private ValueHolderInterface designation;
public ValueHolderInterface getDesignationHolder()
{
    return designation;
}
public void setDesignationHolder(ValueHolderInterface value)
{
    designation = value;
}

For more information about the available methods for TransformationMapping, see the Oracle Application Server TopLink API Reference.

Serialized Object Mappings

Serialized object mappings are used to store large data objects, such as multimedia files and BLOBs, in the database. Serialization transforms these large objects as a stream of bits.

Serialized object mappings are instances of the SerializedObjectMapping class and require the following elements:

  • The attribute to be mapped, set by sending the setAttributeName() message

  • The field that stores the value of the attribute, set by the setFieldName() message

Use the optional setGetMethodName() and setSetMethodName() messages to access the attribute through user-defined methods, rather than directly. You do not have to define accessors when you use Java 2.

Example 3-34 Creating a Serialized Object Mapping and Registering It with the Descriptor

// Create a new mapping and register it with the descriptor.
SerializedObjectMapping serializedMapping = new SerializedObjectMapping();
serializedMapping.setAttributeName("jobDescription");
serializedMapping.setFieldName("JOB_DESC");
descriptor.addMapping(serializedMapping);

For more information about the available methods for SerializedObjectMapping, see the Oracle Application Server TopLink API Reference.

Variable One-to-One Mappings

Variable one-to-one mappings are instances of the VariableOneToOneMapping() class and require the following elements:

  • The attribute to be mapped, set by sending the setAttributeName() message

  • The reference class, set by sending the setReferenceClass() message

  • The foreign key and target query key information, normally specified by sending the setForeignQueryKeyName() message and passing the source foreign key field name and the target abstract query key name on the interface descriptor


    Note:

    If the primary keys of the target implementor descriptors are composite, then send the addForeignQueryKeyName() message for each of the foreign key fields, and target query keys that make up the relationship.

If the mapping uses a class indicator field:

  • Specify a type indicator field.

  • Specify the class indicator values on the mapping so that mapping can determine the class of object to create.


    Note:

    Because Indirection is enabled by default, the attribute must be a ValueHolderInterface.

Example 3-35 Defining a Variable One-to-One Mapping Using a Class Indicator Field

VariableOneToOneMapping variableOneToOneMapping = new VariableOneToOneMapping();
variableOneToOneMapping.setAttributeName("contact");
variableOneToOneMapping.setReferenceClass (Contact.class); 
variableOneToOneMapping.setForeignQueryKeyName ("C_ID", "id");
variableOneToOneMapping.setTypeFieldName("TYPE");
variableOneToOneMapping.addClassIndicator(Email.class, "Email");
variableOneToOneMapping.addClassIndicator(Phone.class, "Phone");
variableOneToOneMapping.dontUseIndirection();
variableOneToOneMapping.privateOwnedRelationship();

Example 3-36 Defining a Variable One-to-One Mapping Using a Primary Key

VariableOneToOneMapping variableOneToOneMapping = new VariableOneToOneMapping();
variableOneToOneMapping.setAttributeName("contact");
variableOneToOneMapping.setReferenceClass (Contact.class);
variableOneToOneMapping.setForeignQueryKeyName ("C_ID", "id");
variableOneToOneMapping.dontUseIndirection();
variableOneToOneMapping.privateOwnedRelationship();

For more information about the available methods for VariableOneToOneMapping, see the Oracle Application Server TopLink API Reference.

Object Relational Mappings

Relational mappings define the reference between persistent objects. Object relational mappings enable you to persist an object model into an object-relational data model. OracleAS TopLink Mapping Workbench does not directly support these mappings—you must define them in code through amendment methods.

OracleAS TopLink supports the following object-relational mappings:

Array Mappings

In an object-relational data-model, structures can contain arrays (collections of other data types). These arrays can contain primitive data types or collections of other structures. OracleAS TopLink stores the arrays with their parent structure in the same table.

All elements in the array must be of the same data type. The number of elements in an array controls the size of the array. An Oracle database allows arrays of variable sizes (called Varrays).

Oracle8i or higher offers two collection types:

  • Varray – Used to represent a collection of primitive data or aggregate structures.

  • Nested table – Similar to varrays except they store information in a separate table from the table of the parent structure

OracleAS TopLink supports arrays of primitive data through the ArrayMapping class. This is similar to DirectCollectionMapping—it represents a collection of primitives in Java. However, the ArrayMapping class does not require an additional table to store the values in the collection.

OracleAS TopLink supports arrays of aggregate structures through the ObjectArrayMapping class.

OracleAS TopLink supports nested tables through the NestedTableMapping class.

Implementing Array Mappings in Java

Array mappings are instances of the ArrayMapping class and require the following elements:

  • The attribute to be mapped, set by sending the setAttributeName() message

  • The field to be mapped, set by sending the setFieldName() message

  • The name of the array, set by sending the setStructureName() message

Example 3-37 Creating an Array Mapping for the Employee Source Class and Registering It with the Descriptor

// Create a new mapping and register it with the source descriptor.
ArrayMapping arrayMapping = new ArrayMapping();
arrayMapping.setAttributeName("responsibilities");
arrayMapping.setStructureName("Responsibilities_t");
arrayMapping.setFieldName("RESPONSIBILITIES");
descriptor.addMapping(arrayMapping);

In addition to the API illustrated in Example 3-37, other common APIs for use with implement array mapping include:

  • setReferenceClass(Class referenceClass): to set the parent class

  • setGetMethodName(String name) and setSetMethodName(String name): to provide method access

For more information about the available methods for ArrayMapping, see the Oracle Application Server TopLink API Reference.

Object Array Mappings

In an object-relational data-model, object arrays allow for an array of object types or structures to be embedded into a single column in a database table or an object table.

OracleAS TopLink supports object array mappings to define a collection-aggregated relationship in which the target objects share the same row as the source object.

Implementing Object Array Mappings in Java

Object array mappings are instances of the ObjectArrayMapping class. You must associate this mapping to an attribute in the parent class. Object array mappings require the following elements:

  • The attribute to be mapped, set by sending the setAttributeName() message

  • The field to be mapped, set by sending the setFieldName() message

  • The name of the array, set by sending the setStructureName() message

Use the optional setGetMethodName() and setSetMethodName() messages to access the attribute through user defined methods, rather than directly.

Example 3-38 Creating an Object Array Mapping for the Insurance Source Class and Registering It with the Descriptor

// Create a new mapping and register it with the source descriptor.
ObjectArrayMapping phonesMapping = new ObjectArrayMapping();
phonesMapping.setAttributeName("phones");
phonesMapping.setGetMethodName("getPhones");
phonesMapping.setSetMethodName("setPhones");
phonesMapping.setStructureName("PHONELIST_TYPE");
phonesMapping.setReferenceClass(Phone.class);
phonesMapping.setFieldName("PHONES");
descriptor.addMapping(phonesMapping);

For more information about the available methods for ObjectArrayMapping, see the Oracle Application Server TopLink API Reference.

Structure Mappings

In an object-relational data-model, structures are user defined data types or object-types. This is similar to a Java class—it defines attributes or fields in which each attribute is either:

  • A primitive data type

  • Another structure

  • Reference to another structure

OracleAS TopLink maps each structure to a Java class defined in your object model and defines a descriptor for each class. A StructureMapping maps nested structures, similar to an AggregateObjectMapping. However, the structure mapping supports null values and shared aggregates without requiring additional settings (because of the object-relational support of the database).

Implementing Structure Mappings in Java

Structure mappings are instances of the StructureMapping class. You must associate this mapping to an attribute in each of the parent classes. Structure mappings require the following elements:

  • The attribute to be mapped, set by sending the setAttributeName() message

  • The field to be mapped, set by sending the setFieldName() message

  • The target (child) class, set by sending the setReferenceClass() message

Use the optional setGetMethodName() and setSetMethodName() message to access the attribute through user-defined methods, rather than directly.

Make the following changes to the target (child) class descriptor:

  • Send the descriptorIsAggregate() message to indicate that it is not a root level.

  • Remove table or primary key information.

Example 3-39 Creating a Structure Mapping for the Employee Source Class and Registering It with the Descriptor

// Create a new mapping and register it with the source descriptor.
StructureMapping structureMapping = new StructureMapping();
structureMapping.setAttributeName("address");
structureMapping.setReferenceClass(Address.class); 
structureMapping.setFieldName("address");
descriptor.addMapping(structureMapping);

Example 3-40 Creating the Descriptor of the Address Aggregate Target Class

The aggregate target descriptor does not need a mapping to its parent, or any table or primary key information.

// Create a descriptor for the aggregate class. The table name and primary key are not specified in the aggregate descriptor.
ObjectRelationalDescriptor descriptor = new ObjectRelationalDescriptor ();
descriptor.setJavaClass(Address.class);
descriptor.setStructureName("ADDRESS_T");
descriptor.descriptorIsAggregate();

// Define the field ordering
descriptor.addFieldOrdering("STREET");
descriptor.addFieldOrdering("CITY");
...

// Define the attribute mappings or relationship mappings.
...

In addition to the API illustrated in Example 3-40, other common APIs for use with structure mapping include:

  • readWrite()

  • readOnly()

  • setIsReadOnly(boolean readOnly)

For more information about the available methods for StructureMapping, see the Oracle Application Server TopLink API Reference.

Reference Mappings

In an object-relational data-model, structures reference each other through refs—not through foreign keys (as in a traditional data model). Refs are based on the ObjectID of the target structure.

OracleAS TopLink supports refs through the ReferenceMapping. They represent an object reference in Java, similar to a OneToOneMapping. However, the reference mapping does not require foreign key information.

Implementing Reference Mappings in Java

Reference mappings are instances of the ReferenceMapping class. You must associate this mapping to an attribute in the source class. Reference mappings require the following elements:

  • The attribute to be mapped, set by sending the setAttributeName() message

  • The field to be mapped, set by sending the setFieldName() message

  • The target class, set by sending the setReferenceClass () message

Use the optional setGetMethodName() and setSetMethodName() messages to access the attribute through user-defined methods, rather than directly.

Example 3-41 Creating a Reference Mapping for the Employee Source Class and Registering It with the Descriptor

// Create a new mapping and register it with the source descriptor.
ReferenceMapping referenceMapping = new ReferenceMapping();
referenceMapping.setAttributeName("manager");
referenceMapping.setReferenceClass(Employee.class);
referenceMapping.setFieldName("MANAGER");
descriptor.addMapping(refrenceMapping);

In addition to the API illustrated in Example 3-41, other common APIs for use with reference mappings include:

  • useBasicIndirection(): implements OracleAS TopLink valueholder indirection

  • dontUseIndirection()

  • readWrite()

  • readOnly()

  • setIsReadOnly(boolean readOnly)

For more information about the available methods for ReferenceMapping, see the Oracle Application Server TopLink API Reference.

Nested Table Mappings

Nested table types model an unordered set of elements. These elements may be built-in or user-defined types. You can view a nested table as a single-column table or, if the nested table is an object type, as a multi-column table (with a column for each attribute of the object type).

Nested tables represent a one-to-many or many-to-many relationship of references to another independent structure. They support querying and joining better than Varrays that are inlined to the parent table.

OracleAS TopLink supports nested tables through the NestedTableMapping. They represent a collection of object references in Java, similar to a OneToManyMapping or ManyToManyMapping. However, the nested table mapping does not require foreign key information (such as a one-to-many mapping) or the relational table (such as a many-to-many mapping).

Implementing Nested Table Mappings in Java

Nested table mappings are instances of the NestedTableMapping class. This mapping is associated to an attribute in the parent class. Nested table mappings require the following elements:

  • The attribute to be mapped, set by sending the setAttributeName() message

  • The field to be mapped, set by sending the setFieldName() message

  • The name of the array structure, set by sending the setStructureName() message

Use the optional setGetMethodName() and setSetMethodName() messages to allow OracleAS TopLink to access the attribute through user-defined methods, rather than directly.

Example 3-42 Creating a Nested Table Mapping for the Insurance Source Class and Registering It with the Descriptor

// Create a new mapping and register it with the source descriptor.
NestedTableMapping policiesMapping = new NestedTableMapping();
policiesMapping.setAttributeName("policies");
policiesMapping.setGetMethodName("getPolicies");
policiesMapping.setSetMethodName("setPolicies");
policiesMapping.setReferenceClass(Policy.class);
policiesMapping.dontUseIndirection();
policiesMapping.setStructureName("POLICIES_TYPE");
policiesMapping.setFieldName("POLICIES");
policiesMapping.privateOwnedRelationship();
policiesMapping.setSelectionSQLString("select p.* from policyHolders ph,
  table(ph.policies) t, policies p where ph.ssn=#SSN and ref(p) = value(t)");
descriptor.addMapping(policiesMapping);

In addition to the API illustrated in Example 3-42, other common APIs for use with nested table mappings include:

  • useBasicIndirection(): implements OracleAS TopLink valueholder indirection

  • dontUseIndirection()

  • setUsesIndirection(boolean usesIndirection)

  • independentRelationship()

  • privateOwnedRelationship()

  • setIsPrivateOwned(Boolean isPrivateOwned)

For more information about the available methods for NestedTableMapping, see the Oracle Application Server TopLink API Reference.

Direct Map Mappings

Direct map mappings store instances that implement java.util.Map. Unlike one-to-many or many-to-many mappings, the keys and values of the map in this type of mapping are Java objects that do not have descriptors. The object type stored in the key and the value of direct map mappings are Java primitive wrapper types such as String objects.

Support for primitive data types such as int is not provided because Java maps hold only objects.

Direct map mappings are instances of the DirectMapMapping class and require the following elements:

  • The attribute to be mapped, set by sending the setAttributeName() message

  • The database table that holds the keys and values to be stored in the map, set by sending the setReferenceTableName() message

  • The field in the reference table from which the keys are read and placed into the map; this is called the direct key field and is set by sending the setDirectKeyFieldName() message

  • The foreign key information, which you specify by sending the setReferenceKeyFieldName() message and passing the name of the field that is a foreign reference to the primary key of the source object


    Note:

    If the target primary key is composite, send the addReferenceKeyFieldName() message for each of the fields that make up the key.

  • The field in the reference table from which the values are read and placed into the map; this is called the direct field and is set by sending the setDirectFieldName() message

  • The Java type of key in map from which the keys are converted from keys are read from the database placed into the map; this is set by sending the setKeyClass() message

  • The Java type of value in map from which the values are converted from values are read from the database placed into the map; this is set by sending the setValueClass() message

Example 3-43 Creating a Simple Direct Map Mapping

DirectMapMapping directMapMapping = new DirectMapMapping();
directMapMapping.setAttributeName("cities");
directMapMapping.setReferenceTableName("CITY_TEMP");
directMapMapping.setReferenceKeyFieldName("RECORD_ID");
directMapMapping.setDirectKeyFieldName("CITY");
directMapMapping.setDirectFieldName("TEMPERATURE");
directMapMapping.setKeyClass(String.class);
directMapMapping.setValueClass(Integer.class);

descriptor.addMapping(directMapMapping);

In addition to the API illustrated in Example 3-43, other common APIs for use with direct map mappings include:

  • useBasicIndirection(): implements OracleAS TopLink valueholder indirection

  • useTransparentCollection(): if you use transparent indirection, this element places a special collection in the attribute of the source object

  • dontUseIndirection(): implements no indirection

For more information about the available methods for DirectMapMapping, see the Oracle Application Server TopLink API Reference.