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
 

Writing Mappings in Code

In most cases, OracleAS TopLink Mapping Workbench is the preferred tool to create OracleAS TopLink elements however; OracleAS TopLink also supports building components of your application in Java code. You can code components ranging in size from small elements to complete projects. This section illustrates the techniques required for building several of these components, and includes discussions on:

Implementing Object-Relational Descriptors in Java

Use the ObjectRelationalDescriptor class to define object-relational descriptors. This descriptor subclass contains the following additional properties:

  • Structure name: Name of the object-type structure representing the class

  • Field ordering: Field index of the object-type (required because object-type can be returned through JDBC as indexed arrays)

The OracleAS TopLink Remote (RMI) Example illustrates an object-relational data model and descriptors. For more information, see the OracleAS TopLink Examples at <ORACLE_HOME>\toplink\doc\examples.htm.

Example 3-47 Creating an Object-Relational Descriptor

import oracle.toplink.objectrelational.*;
ObjectRelationalDescriptor descriptor = new ObjectRelationalDescriptor()
descriptor.setJavaClass(Employee.class);
descriptor.setTableName("EMPLOYEES");
descriptor.setStructureName("EMPLOYEE_T");
descriptor.setPrimaryKeyFieldName("OBJECT_ID");

descriptor.addFieldOrdering("OBJECT_ID"); 
descriptor.addFieldOrdering("F_NAME");
descriptor.addFieldOrdering("L_NAME");
descriptor.addFieldOrdering("ADDRESS"); 
descriptor.addFieldOrdering("MANAGER");
descriptor.addDirectMapping("id", "OBJECT_ID"); 
descriptor.addDirectMapping("firstName", "F_NAME"); 
descriptor.addDirectMapping("lastName", "L_NAME");
//Refer to the mappings section for examples of object relational mappings.
...

Implementing Primary Keys in Java

If a single field constitutes the primary key, send the setPrimaryKeyFieldName() message to the descriptor. For a composite primary key, send the addPrimaryKeyFieldName() message for each field that makes up the primary key.

Alternatively, use the setPrimaryKeyFieldNames() message that sends a Vector of the fields used as the primary key.

Example 3-48 Setting a Single-Field Primary Key in Java

// Define a new descriptor and set the primary key.
descriptor.setPrimaryKeyFieldName("ADDRESS_ID");

Example 3-49 Setting a Composite Primary Key in Java

// Define a new descriptor and set the primary key.
descriptor1.addPrimaryKeyFieldName("PHONE_NUMBER");
descriptor1.addPrimaryKeyFieldName("AREA_CODE");

Implementing Inheritance in Java

Although you can implement inheritance hierarchy in Java, under most circumstances, we recommend you use OracleAS TopLink Mapping Workbench.

To implement an inheritance hierarchy in Java, modify the descriptors for the superclass and its subclasses. The inheritance implementation for a descriptor is encapsulated in an InheritancePolicy object, which you can access by sending getInheritancePolicy() to the descriptor:

  • Unless you use a class extraction method, send the setClassIndicatorFieldName() message to the InheritancePolicy of the root class. The parameter is a string that indicates the table column that holds the subclass type information.

  • In the root class, define the values written to the database and indicate the class type as follows:

    • Send the addClassIndicator() message for each of the instantiable subclasses in the hierarchy. This message requires two parameters—the indicator value and the subclass it represents.

    • Send the useClassNameAsIndicator() message. This stores the full name of the class in the class indicator field.

  • Send the setParentClass() message to the descriptor for each subclass.

  • Configure a root or branch class to return only instances of itself, by calling the dontReadSubclassesOnQueries() method.


    Note:

    Descriptors that inherit table names from a parent are not sent the setTableName() and addTableName() messages for the tables they inherit. Only the root class defines the primary key.

Queries for Inherited Superclasses and Multiple Tables

If a superclass is configured to read subclasses and its subclasses define additional tables, build multiple queries to obtain all the rows for all the subclasses. For best performance in this situation, create a view against which to execute the query using the setReadAllSubclassesViewName() method. The view must internally perform an outer join or union on all the subclass tables and return a single result set with all the data.

Customizing Inheritance

Occasionally, using the default OracleAS TopLink inheritance mechanism is not possible. For these cases, you can customize the inheritance mechanism. Instead of using a class indicator field and mapping, use a class extraction method. This method takes the row of the object and returns the class to be used for that row. The setClassExtractionMethodName() method is used to accomplish this.

Queries for inherited classes usually also require filtering of the table rows. By default, OracleAS TopLink generates this from the class indicator information. If you provide the class extraction method, specify the filtering expressions. You can set these for concrete classes through setOnlyInstancesExpression() and for branch classes through setWithAllSubclassesExpression().

Figure 3-10 illustrates an example of an inheritance hierarchy. The Vehicle-Bicycle branch demonstrates how you can store all subclass information in one table. The FueledVehicle-Car branch demonstrates how you can store subclass information in two tables.

Figure 3-10 Inheritance Hierarchy

Description of inhrtnc.gif follows
Description of the illustration inhrtnc.gif

The Car and Bicycle classes are leaf classes. Queries performed on them return instances of Car and Bicycle respectively.

FueledVehicle is a branch class. By default, branch classes are configured to read instances and subclass instances. Queries for FueledVehicle return instances of FueledVehicle and instances of Car.

NonFueledVehicle is a branch class and is configured to read subclasses. Because it does not have a class indicator defined in the root, it cannot be written to the database. Queries performed on NonFueledVehicle return instances of its subclasses.

Vehicle is a root class, which is configured to read instances of itself and instances of its subclass, by default. Queries performed on the Vehicle class return instances of any of the concrete classes in the hierarchy.

Example 3-50 Implementing Descriptors for the Classes in the Inheritance Hierarchy

// Vehicle is a root class. Because it is the root class, it must add the class 
// indicators for its subclasses.
public static Descriptor descriptor() 
{
    Descriptor descriptor = new Descriptor();
    descriptor.setJavaClass(Vehicle.class);
    descriptor.setTableName("VEHICLE");
    descriptor.setPrimaryKeyFieldName("ID");

    // Class indicators must be supplied for each of the subclasses in the  
    // hierarchy that can have instances.
    InheritancePolicy policy = descriptor.getInheritancePolicy();
    policy.setClassIndicatorFieldName("TYPE");
    policy.addClassIndicator(FueledVehicle.class, "Fueled");
    policy.addClassIndicator(Car.class, "Car");
    policy.addClassIndicator(Bicycle.class, "Bicycle");

    descriptor.addDirectMapping("id", "ID");
    descriptor.addDirectMapping("passengerCapacity", "CAP");

    return descriptor;
}

// FueledVehicle descriptor; it is a branch class and a subclass of Vehicle. 
// Queries made on this class will return instances of itself and instances of 
// its subclasses.
public static Descriptor descriptor() 
{
    Descriptor descriptor = new Descriptor();
    descriptor.setJavaClass(FueledVehicle.class);
    descriptor.addTableName("FUEL_VEH");
    descriptor.getInheritancePolicy().setParentClass(Vehicle.class);
    descriptor.addDirectMapping("fuelCapacity", "FUEL_CAP");
    descriptor.addDirectMapping("fuelType", "FUEL_TYPE");
    return descriptor;
}

// Car descriptor; it is a leaf class and subclass of FueledVehicle.
public static Descriptor descriptor() 
{
    Descriptor descriptor = new Descriptor();
    descriptor.setJavaClass(Car.class);
    descriptor.addTableName("CAR");
    descriptor.getInheritancePolicy().setParentClass(FueledVehicle.class);

    // Next define the attribute mappings.
    descriptor.addDirectMapping("description", "DESCRIP");
    descriptor.addDirectMapping("fuelType", "FUEL_VEH.FUEL_TYPE");
    return descriptor;
}

// NonFueledVehicle descriptor; it is a branch class and a subclass of Vehicle. 
// Queries made on this class will return instances of its subclasses.
public static Descriptor descriptor()
{
    Descriptor descriptor = new Descriptor();
    descriptor.setJavaClass(NonFueledVehicle.class);
    descriptor.getInheritancePolicy().setParentClass(Vehicle.class);
    return descriptor;
}

// Bicycle descriptor; it is a leaf class and subclass of NonFueledVehicle. 
public static Descriptor descriptor()
{
    Descriptor descriptor = new Descriptor();
    descriptor.setJavaClass(Bicycle.class);
    descriptor.getInheritancePolicy().setParentClass(NonFueledVehicle.class);
    descriptor.addDirectMapping("description", "BICY_DES");
    return descriptor;
}

/* FueledVehicle class; If a class extraction method is used, the following needs to be added to specify that only the branch class itself needs to be returned. This example is just specifying the class indicator field, which can also be specified in OracleAS TopLink Mapping Workbench in the Descriptor Advanced Properties dialog. */
public void addToDescriptor(Descriptor descriptor) 
{
    ExpressionBuilder builder = new ExpressionBuilder();
    descriptor.getInheritancePolicy().setOnlyInstancesExpression(
        builder.getField("VEHICLE.TYPE").equal("F")
    );
}

Reference

Table 3-7 summarizes the most common public methods for InheritancePolicy. For more information about the available methods for InheritancePolicy, see the Oracle Application Server TopLink API Reference.

Table 3-7 Elements for the Inheritance Policy

Element Default Method Name
Class indicators use indicator mapping setClassIndicatorFieldName(String fieldName)
Parent classes not applicable setParentClass(Class parentClass)

Implementing Indirection in Java

To create indirection objects in code, the application must replace the relationship reference with a ValueHolderInterface. It must also call the useIndirection() method of the mapping if the mapping does not use indirection by default. Likewise, call the dontUseIndirection() method to disable indirection. ValueHolderInterface is defined in the oracle.toplink.indirection.

Example 3-51 A Mapping that Does Not Use Indirection

/* Define the One-to-One mapping. Note that One-to-One mappings have indirection enabled by default, so the "dontUseIndirection()" method must be called if indirection is not used. */
OneToOneMapping oneToOneMapping = new OneToOneMapping();
oneToOneMapping.setAttributeName("address");
oneToOneMapping.setReferenceClass(Address.class);
oneToOneMapping.setForeignKeyFieldName("ADDRESS_ID");
oneToOneMapping.dontUseIndirection();
oneToOneMapping.setSetMethodName("setAddress");
oneToOneMapping.setGetMethodName("getAddress");
descriptor.addMapping(oneToOneMapping);

The following code illustrates a mapping using indirection.

/* Define the One-to-One mapping. One-to-One mappings have indirection enabled by default, so the "useIndirection()" method is unnecessary if indirection is used. */
OneToOneMapping oneToOneMapping = new OneToOneMapping();
oneToOneMapping.setAttributeName("address");
oneToOneMapping.setReferenceClass(Address.class);
oneToOneMapping.setForeignKeyFieldName("ADDRESS_ID");
oneToOneMapping.setSetMethodName("setAddressHolder");
oneToOneMapping.setGetMethodName("getAddressHolder");
descriptor.addMapping(oneToOneMapping);

Implementing Interfaces in Java

Descriptors can own their parent interfaces. They can set multiple interfaces if they have implemented multiple interfaces. The query keys are defined in a normal way except that they must define the abstract query key from the interface descriptor in their descriptors. An abstract query key on the interface descriptor enables it to write expression queries on the interface.

Example 3-52 Using an Abstract Query Key on the Interface Descriptor

ExpressionBuilder contact = new ExpressionBuilder();
session.readObject(Contact.class, contact.get("id").equal(2));

Setting the Copy Policy in Java

The Descriptor class provides three methods that determine how an object is cloned:

  • useInstantiationCopyPolicy(): the default method; OracleAS TopLink creates a new instance of the object using the technique indicated by the instantiation policy of the descriptor. The default behavior is to use the default constructor. The new instance is then populated by using the mappings of the descriptor to copy attributes from the original object.


    Note:

    Descriptor.useInstantiationCopyPolicy() replaces Descriptor.useConstructorCopyPolicy() available in previous versions of OracleAS TopLink. The old method is still supported, but it has been deprecated.

  • useCloneCopyPolicy(): OracleAS TopLink calls the clone() method of the object; ensure that the clone method is written correctly and returns a logical shallow clone of the object.

  • useCloneCopyPolicy(String): this method is called by passing in a string that contains the name of a method that clones the object; ensure that the method specified returns a logical shallow clone of the object.

Implementing Multiple Tables in Java

To define a multiple table descriptor, call the addTableName() method for each table the descriptor maps to. If the descriptor inherits its primary table and is defining only a single additional one, then the descriptor is mapped normally to this table.

Primary Keys Match

Normally, the primary key is defined only for the primary table of the descriptor. The primary table is the first table specified through addTableName(). The primary key is not defined for the additional tables and is required to be the same as in the primary table. If the key of the additional table is different, refer to the next example.

By default, all the fields in a mapping are presumed to be part of the primary table. If a field of a mapping is for one of the additional tables, it must be fully qualified with the table name of the field.

Example 3-53 Implementing a Multiple Table Descriptor In Which the Primary Keys Match

//Define a new descriptor that uses three tables.
Descriptor descriptor = new Descriptor();
descriptor.setJavaClass(Employee.class);
descriptor.addTableName("PERSONNEL"); // Primary table
descriptor.addTableName("EMPLOYMENT");
descriptor.addTableName("USERS");

descriptor.addPrimaryKeyFieldName("PER_NUMBER");
descriptor.addPrimaryKeyFieldName("DEP_NUMBER");

descriptor.addDirectMapping("id", "PER_NUMBER");
descriptor.addDirectMapping("firstName", "F_NAME");
descriptor.addDirectMapping("lastName", "L_NAME");

OneToOneMapping department = new OneToOneMapping();
department.setAttributeName("department");
department.setReferenceClass(Department.class);
department.setForeignKeyFieldName("DEP_NUMBER");
descriptor.addMapping(department);
// Mapping the primary key fields in the additional tables is not required
descriptor.addDirectMapping("salary", "EMPLOYMENT.SALARY");

AggregateObjectMapping period = new AggregateObjectMapping();
period.setAttributeName(period);
period.setReferenceClass(EmployementPeriod.class);
period.addFieldNameTranslation("EMPLOYMENT.S_DATE", "S_DATE");
period.addFieldNameTranslation("EMPLOYMENT.E_DATE", "E_DATE");
descriptor.addMapping(period);

descriptor.addDirectMapping("userName", "USERS.NAME");
descriptor.addDirectMapping("password", "USERS.PASSWORD");

Primary Keys are Named Differently

If the primary key of the additional table is named differently, then call the descriptor method addMultipleTablePrimaryKeyName(), which provides:

  • The field of the primary key from the primary table

  • The additional table name

  • The field in the additional table to which the primary key maps

Example 3-54 Implementing a Multiple Table Descriptor In Which the Additional Table Primary Keys are Named Differently

//Define a new descriptor that uses three tables.
Descriptor descriptor = new Descriptor();
descriptor.setJavaClass(Employee.class);
descriptor.addTableName("PERSONNEL"); 
// Primary table
descriptor.addTableName("EMPLOYMENT");
descriptor.addTableName("USERS");

descriptor.addPrimaryKeyFieldName("PER_NUMBER");
descriptor.addPrimaryKeyFieldName("DEP_NUMBER");

descriptor.addMultipleTablePrimaryKeyName("PERSONEL.PER_NUMBER",
  "USERS.PERSONEL_NO");
descriptor.addMultipleTablePrimaryKeyName("PERSONEL.DEP_NUMBER",
  "USERS.DEPARTMENT_NO");

// Assumed EMPLOYMENT uses same primary key
descriptor.addDirectMapping(id, PER_NUMBER);

OneToOneMapping department = new OneToOneMapping();
department.setAttributeName("department");
department.setReferenceClass(Department.class);
department.setForeignKeyFieldName("DEP_NUMBER");
descriptor.addMapping(department);

// Primary key does not have to be mapped for additional tables.
...

Tables Related by Foreign Key Relationships

For OracleAS TopLink to support read, insert, update, and delete operations on an object mapped to multiple tables:

  • Specify the foreign key information on the descriptor.

  • Specify the foreign keys and primary keys in the object.

The API is addMultipleTableForeignKeyFieldName(). This method builds the join expression and adjusts the table insertion order to respect the foreign key constraints.

Example 3-55 illustrates the setup of a descriptor for an object mapped to multiple tables in which the tables are related by a foreign key relationship from the primary table to the secondary table. The addMultipleTableForeignKeyFieldName() method is used to specify the direction of the foreign key relationship.

If the foreign key is in the secondary table and refers to the primary table, then the order of the arguments to addMultipleTableForeignKeyFieldName() is reversed.


Note:

To allow read, insert, update, and delete operation to be performed on the Employee object, map the foreign key field in the primary table and the primary key in the secondary table.

Example 3-55 Implementing Multiple Tables In Which a Foreign Key from the Primary Table to the Secondary Table Is Used to Join the Tables

Descriptor descriptor = new Descriptor();
descriptor.setJavaClass(Employee.class);
Vector vector = new Vector();
vector.addElement("EMPLOYEE");
vector.addElement(ADDRESS");
descriptor.setTableNames(vector);
descriptor.addPrimaryKeyFieldName("EMPLOYEE.EMP_ID");
// Map the foreign key field of the employee table and the primary key of the address table.
descriptor.addDirectMapping("addressID", "EMPLOYEE.ADDR_ID");

/* Setup the join from the address table to the country employee table to the address table by specifying the FK info to the descriptor. Set the foreign key info from the address table to the country table. */
descriptor.addMultipleTableForeignKeyFieldName("EMPLOYEE.ADDR_ID",
  "ADDRESS.ADDR_ID");

Non Standard Table Relationships

Occasionally, the join condition can be nonstandard. In this case, the query manager of the descriptor can be used to provide a custom multiple table join expression. The getQueryManager() method is called on the descriptor to obtain its query manager, and the setMultipleTableJoinExpression() method is used to customize the join expression.

Simply specifying the join expression allows OracleAS TopLink to perform read operations for the object. Insert operations can also be supported if the table insertion order is specified and the primary key of the additional tables is mapped manually.

The insertion order is required to conform to foreign key constraints when inserting to the multiple tables. Specify the insert order using the descriptor method setMultipleTableInsertOrder().

Example 3-56 illustrates the use of the setMultipleTableJoinExpression() and setMultipleTableInsertOrder() methods. In addition, it illustrates the use of a custom join expression without specifying the table insert order.


Note:

Using these methods does not support update or delete operations because of the lack of primary key information for the secondary tables. If update and delete operations are required, perform them with custom SQL, or explicitly specify the foreign key information as explained in the previous section.

Example 3-56 Implementing Multiple Tables In Which You Specify a Join Expression and the Table Insert Order

Using this method allows only read and insert operations to be performed on Employee objects. Note that the primary key of the secondary table, and the foreign key of the primary table, must be mapped and maintained by the application for insert operations to work.

Descriptor descriptor = new Descriptor();
descriptor.setJavaClass(Employee.class);
Vector vector = new Vector();
vector.addElement("EMPLOYEE");
vector.addElement(ADDRESS");
descriptor.setTableNames(vector);

// Specify the primary key information for each table.
descriptor.addPrimaryKeyFieldName("EMPLOYEE.EMP_ID");

// Map the foreign key field of the employee table and the primary key of the 
// address table. 
descriptor.addDirectMapping("employee_addressID", "EMPLOYEE.ADDR_ID");
descriptor.addDirectMapping("address_addressID", "ADDRESS.ADDR_ID");
/* Setup the join from the employee table to the address table using a custom join expression and specifying the table insert order. */
ExpressionBuilder builder = new ExpressionBuilder();
descriptor.getQueryManager().setMultipleTableJoinExpression(builder.getField
  ("EMPLOYEE.ADDR_ID").equal(builder.getField("ADDRESS.ADDR_ID")));
Vector tables = new Vector(2);
tables.addElement(new DatabaseTable("ADDRESS"));
tables.addElement(new DatabaseTable("EMPLOYEE"));
descriptor.setMultipleTableInsertOrder(tables);
...

Example 3-57 Mapping a Multiple Table Descriptor In Which a Custom Join Expression is Required

In this example, only read operations are supported.

//Define a new descriptor that uses three tables.
Descriptor descriptor = new Descriptor();
descriptor.setJavaClass(Employee.class);
descriptor.addTableName("PERSONNEL"); 
// Primary table
descriptor.addTableName("EMPLOYMENT");
descriptor.addPrimaryKeyFieldName("PER_NO");
descriptor.addPrimaryKeyFieldName("DEP_NO");

ExpressionBuilder builder = new ExpressionBuilder();
descriptor.getQueryManager().setMultipleTableJoinExpression((builder.getField
  ("PERSONEL.EMP_NO").equal(builder.getField("EMPLOYMENT.EMP_NO")));
descriptor.addDirectMapping("personelNumber", "PER_NO");

OneToOneMapping department = new OneToOneMapping();
department.setAttributeName("department");
department.setReferenceClass(Department.class);
department.setForeignKeyFieldName("DEP_NO");
descriptor.addMapping(department);
// The primary key field on the EMPLOYMENT does not have to be mapped.
...

Implementing Sequence Numbers in Java

To implement sequence numbers using Java code, send the setSequenceNumberFieldName( ) message to the descriptor to register the name of the database field that holds the sequence number. The setSequenceNumberName( ) method also holds the name of the sequence. This name can be one of the entries in the SEQ_NAME column or the name of the sequence object (if you are using Oracle native sequencing).


Notes:

The sequence field must be in the first (primary) table if multiple tables are used. If you use Sybase SQL Server, Microsoft SQL Server, or IBM Informix native sequencing, this implementation has no direct meaning but must still be set for compatibility reasons.

Implementing Locking in Java

Use the API to set optimistic locking completely in code. All the API is on the descriptor:

  • useVersionLocking(String): sets this descriptor to use version locking and increments the value in the specified field name for update or delete

  • useChangedFieldsLocking(): tells this descriptor to compare only modified fields for an update or delete

  • useTimestampLocking(String): sets this descriptor to use timestamp locking and writes the current server time in the field every update or delete

  • useAllFieldsLocking(): tells this descriptor to compare every field for an update or delete

  • useSelectedFieldsLocking(Vector): tells this descriptor to compare the field names specified in this vector of Strings for an update or delete

Example 3-58 Implementing Optimistic Locking Using the Version Field of Employee Table as the Version Number of the Optimistic Lock

/* Set the field that control optimistic locking. No mappings are set for fields which are version fields for optimistic locking. */
descriptor.useVersionLocking("VERSION");

The code in Example 3-58 stores the optimistic locking value in the identity map. If the value must be stored in a nonread-only mapping, then the code can be:

descriptor.useVersionLocking("VERSION", false);

The false indicates that the lock value is not stored in the cache, but is stored in the object.

Java Implementation of Optimistic Locking

Use the API to set optimistic locking in code. All the API is on the descriptor:

  • useVersionLocking(String): sets this descriptor to use version locking and increments the value in the specified field name for every update or delete

  • useTimestampLocking(String): sets this descriptor to use timestamp locking and writes the current server time in the specified field name for every update or delete

  • useChangedFieldsLocking(): tells this descriptor to compare only modified fields for an update or delete

  • useAllFieldsLocking(): tells this descriptor to compare every field for an update or delete

  • useSelectedFieldsLocking(Vector): tells this descriptor to compare the field names specified in this vector of Strings for an update or delete

Example 3-59 illustrates how to implement optimistic locking using the VERSION field of EMPLOYEE table as the version number of the optimistic lock.

Example 3-59 Implementing Optimistic Locking Example

descriptor.useVersionLocking("VERSION");

The code in Example 3-59 stores the optimistic locking value in the identity map. If the value must be stored in a nonread-only mapping, then the code appears as follows:

descriptor.useVersionLocking("VERSION", false);

The false indicates that the lock value is not stored in the cache, but is stored in the object.

Implementing oracle.sql.TimeStamp

OracleAS TopLink provides additional support for mapping Java date and time data types to Oracle database DATE, TIMESTAMP, and TIMESTAMPTZ data types when you use the Oracle JDBC driver with Oracle9i Database Server or higher and the Oracle9Platform in OracleAS TopLink.

This section describes how the additional timestamp mapping support affects the following:

Direct-to-Field Mapping

In a direct-to-field mapping, you are not required specify the database type of the field value; OracleAS TopLink determines the appropriate data type conversion.

Table 3-8 lists the supported direct-to-field mapping combinations.

Table 3-8 Supported Oracle Database Date and Time Direct-to-Field Mappings

Java Type Database Type Description
java.sql.Time TIMESTAMP Full bidirectional support.
TIMESTAMPTZ Full bidirectional support.
DATE Full bidirectional support.
java.sql.Date TIMESTAMP Full bidirectional support.
TIMESTAMPTZ Full bidirectional support.
DATE Full bidirectional support.
java.sql.Timestamp TIMESTAMP Full bidirectional support.
TIMESTAMPTZ Full bidirectional support.
DATE Nanoseconds are not stored in the database.
java.util.Date TIMESTAMP Full bidirectional support.
TIMESTAMPTZ Full bidirectional support.
DATE Milliseconds are not stored in the database.
java.util.Calendar TIMESTAMP
  • With native SQL or binding, timestamp is stored based on the Calendar's timezone.
  • With standard SQL or binding, timestamp is stored based on the local timezone.

TIMESTAMPTZ
  • With native SQL or binding, timestamp is stored based on the Calendar's timezone.
  • With standard SQL or binding, timestamp is stored based on the local timezone.

DATE Neither timezone nor milliseconds are stored in the database.

Note that some of these mappings result in a loss of precision: avoid these combinations if you require the precision. For example, if you create a direct-to-field mapping between a java.sql.Date attribute and a TIMESTAMPTZ database field, there is no loss of precision. However, if you create a direct-to-field mapping between a java.sql.Timestamp attribute and a DATE database field, the nanoseconds of the attribute are not stored in the database.

Type Conversion Mapping

In a type conversion mapping, you specify the attribute name and database field name as well as the attribute class and database field class.

As Table 3-9 illustrates, for a type conversion mapping, OracleAS TopLink supports only oracle.sql.TIMESTAMP as the database field class.

If you configure the mapping in code using the TypeConversionMapping.setFieldClassification method, use the appropriate Oracle extended Java type: oracle.sql.TIMESTAMP.class.

Table 3-9 Supported Oracle Database Date and Time Transformation Mappings

Java Type Database Type Description
java.sql.Time TIMESTAMP Full bidirectional support.
java.sql.Date TIMESTAMP Full bidirectional support.
java.sql.Timestamp TIMESTAMP Full bidirectional support.
java.util.Date TIMESTAMP Full bidirectional support.
java.util.Calendar TIMESTAMP Oracle does not recommend this mapping type. Timezone is not stored in the database.


Note:

If you enable JDBC parameter binding, the mapping converts the type stored in the object model back into an oracle.sql.Timestamp object or throws a conversion exception if not supported by the conversion manager in use.


Note:

When using Oracle JDBC 9.0.1 driver, resultSet.getTimestamp(int) returns oracle.sql.TIMESTAMP, instead of java.sql.Timestamp. As a result, oracle.sql.TIMESTAMP is stored in the DatabaseRow. Although OracleAS TopLink converts it to java.sql.Timestamp at a later stage for a successful read, serialization on an attribute of ValueHolderInterface type representing an object mapped to TIMESTAMP field will fail because DatabaseRow is an attribute of ValueHolder and oracle.sql.TIMESTAMP is not serializable.