Oracle Fusion Middleware Developer's Guide for Oracle TopLink 11g Release 1 (11.1.1) Part Number B32441-03 |
|
|
View PDF |
A relational mapping transforms any object data member type to a corresponding relational database (SQL) data source representation in any supported relational database. Relational mappings let you map an object model into a relational data model.
Relational mappings transform object data members to relational database fields. Use them to map simple data types including primitives (such as int
), JDK classes (such as String
), and large object (LOB) values. You can also use them to transform object data members that reference other domain objects by way of association where data source representations require object identity maintenance (such as sequencing and back references) and possess various types of multiplicity and navigability. The appropriate mapping class is chosen primarily by the cardinality of the relationship.
Do not confuse relational mappings with object-relational data type mappings (see Chapter 40, "Introduction to Object-Relational Data Type Mappings"). An object-relational data type mapping transforms certain object data member types to structured data source representations optimized for storage in specialized object-relational data type databases, such as Oracle Database. Object-relational data type mappings let you map an object model into an object-relational data type data model. In general, you can use relational mappings with any supported relational database. You can only use object-relational data type mappings with specialized object-relational data type databases optimized to support object-relational data type data source representations.
This chapter includes the following sections:
For information on mapping concepts and features common to more than one type of TopLink mappings, see Chapter 17, "Introduction to Mappings".
TopLink supports the relational mappings listed in Table 27-1.
Table 27-1 TopLink Relational Mapping Types
Type of Mapping | Description | Oracle JDeveloper |
TopLink Workbench | Java |
---|---|---|---|---|
Direct-to-field (see Section 27.3, "Direct-to-Field Mapping") |
Map a Java attribute directly to a database field. |
![]() |
![]() |
![]() |
Direct-to-XMLType (see Section 27.4, "Direct-to-XMLType Mapping") |
Map Java attributes to an |
![]() |
![]() |
![]() |
One-to-one (see Section 27.5, "One-to-One Mapping") |
Map a reference to another persistent Java object to the database. |
![]() |
![]() |
![]() |
Variable one-to-one (see Section 27.6, "Variable One-to-One Mapping") |
Map a reference to an interface to the database. |
![]() |
![]() |
![]() |
One-to-many (see Section 27.7, "One-to-Many Mapping") |
Map Java collections of persistent objects to the database. |
![]() |
![]() |
![]() |
Many-to-many (see Section 27.8, "Many-to-Many Mapping") |
Use an association table to map Java collections of persistent objects to the database. |
![]() |
![]() |
![]() |
Aggregate collection (see Section 27.9, "Aggregate Collection Mapping") |
Map Java collections of persistent objects to the database. |
|
|
![]() |
Direct collection (see Section 27.10, "Direct Collection Mapping") |
Map Java collections of objects that do not have descriptors. |
![]() |
![]() |
![]() |
Direct map (see Section 27.11, "Direct Map Mapping") |
Direct map mappings store instances that implement |
![]() |
![]() |
![]() |
Aggregate object (see Section 27.12, "Aggregate Object Mapping") |
Create strict one-to-one mappings that require both objects to exist in the same database row. |
![]() |
![]() |
|
Transformation (see Section 27.13, "Transformation Mapping") |
Create custom mappings where one or more fields can be used to create the object to be stored in the attribute. |
![]() |
![]() |
![]() |
This section introduces direct mapping concepts unique to TopLink, including the following:
The direction of a relationship may be either unidirectional or bidirectional. In a unidirectional relationship, only one entity bean has a relationship field that refers to the other. All TopLink relational mappings are unidirectional, from the class being described (the source class) to the class with which it is associated (the target class). The target class does not have a reference to the source class in a unidirectional relationship.
In a bidirectional relationship, each entity bean has a relationship field that refers to the other bean. Through the relationship field, an entity bean's code can access its related object. To implement a bidirectional relationship (classes that reference each other), use two unidirectional mappings with the sources and targets reversed.
Note:
Maintenance of bidirectional relationships presents a number of technical challenges. For more information, see the following:You can store object attributes directly in a database table as follows:
Direct mapping (see Section 27.2.2.1, "Using a Direct Mapping")
Converter Mapping (see Section 27.2.2.2, "Using a Converter Mapping")
Transformation mapping (see Section 27.2.2.3, "Using a Transformation Mapping")
If the attribute type is comparable to a database type, the information can be stored directly simply by using a direct-to-field mapping (see Section 27.3, "Direct-to-Field Mapping").
If the attribute type is comparable to a database type but requires conversion, the information can be stored directly by using a direct-to-field mapping (see Section 27.3, "Direct-to-Field Mapping") and an appropriate Converter
instance.
In the previous release, TopLink provided subclasses of DirectToFieldMapping
for object type direct mappings, serialized object direct mappings, and type conversion direct mappings. In this release, these subclasses are deprecated. In their place, Oracle recommends that you use the DirectToFieldMapping
method setConverter
and the corresponding Converter
instance. Table 27-2 summarizes these changes.
Table 27-2 Using a Converter for Direct-to-Field Mappings
Deprecated DirectToFieldMapping subclass... | Replaced by Converter instance... |
---|---|
|
|
|
|
|
|
If the application's objects contain attributes that cannot be represented as direct-to-field with an existing converter, use a direct-to-field mapping with a custom converter.
If there is no database primitive type that is logically comparable to the attribute's type, or, if an attribute requires data from multiple fields, it must be transformed on its way to and from the database.
In this case, use a transformation mapping (see Section 27.13, "Transformation Mapping").
Use direct mappings to map the (non-CMR) CMF attributes of a bean.
In EJB CMP projects, the bean class does not define real variables in the class – only abstract getter and setter methods. To map the bean's attributes, you must import ejb-jar.xml
file into TopLink Workbench (see Section 117.5, "Configuring Persistence Type").
You can map entity bean attributes using direct mappings without any special considerations.
Note:
When you work with EJB, do not map theentity context
attribute (type javax.ejb.EntityContext
).There are some special considerations when using one-to-one mappings (see Section 27.5.1, "One-to-One Mappings and EJB 2.n CMP"), one-to-many mappings (see Section 27.7.1, "One-to-Many Mappings and EJB 2.n CMP"), and many-to-many mappings (see Section 27.8.1, "Many-to-Many Mappings and EJB 2.n CMP").
Use direct-to-field mappings to map primitive object attributes, or non persistent regular objects, such as the JDK classes. For example, use a direct-to-field mapping to store a String
attribute in a VARCHAR
field.
Example 27-1 Direct-to-Field Mapping Example
Figure 27-1 illustrates a direct-to-field mapping between the Java attribute city
and the relational database column CITY
. Similarly, direct-to-field mappings could be defined from country
to COUNTRY
, id
to ADDRESS_ID
, established
to EST_DATE
, and province
to PROVINCE
.
You can use a direct-to-field mapping with any of the following Converter
instances:
Object type converter (see Section 17.2.6.3, "Object Type Converter")
Serialized object converter (see Section 17.2.6.1, "Serialized Object Converter")
Type conversion converter (see Section 17.2.6.2, "Type Conversion Converter")
You can use a direct-to-field mapping with a change policy (see Section 119.30, "Configuring Change Policy".
See Chapter 29, "Configuring a Relational Direct-to-Field Mapping" for more information.
Using a direct-to-XMLType
mapping, you can map XML data in the form of a String
or an org.w3c.dom.Document
object to an XMLType column in an Oracle Database (introduced in version 9.2.0.1).
If you plan to use direct-to-XMLType
mappings in TopLink Workbench and the TopLink runtime, you must include the Oracle Database xdb.jar
file in the TopLink Workbench classpath (see Section 5.2, "Configuring the TopLink Workbench Environment").
The TopLink query framework provides a number of expression operators you can use to create queries based on the content of that XML data (see Section 110.2.4, "XMLType Functions").
See Chapter 30, "Configuring a Relational Direct-to-XMLType Mapping" for more information.
One-to-one mappings represent simple pointer references between two Java objects. In Java, a single pointer stored in an attribute represents the mapping between the source and target objects. Relational database tables implement these mappings using foreign keys.
Figure 27-2 illustrates a one-to-one relationship from the address
attribute of an Employee
object to an Address
object. To store this relationship in the database, create a one-to-one mapping between the address
attribute and the Address
class. This mapping stores the id
of the Address
instance in the EMPLOYEE
table when the Employee
instance is written. It also links the Employee
instance to the Address
instance when the Employee
is read from the database. Because an Address
does not have any references to the Employee
, it does not have to provide a mapping to Employee
.
For one-to-one mappings, the source table normally contains a foreign key reference to a record in the target table. In Figure 27-2, the ADDR_ID
field of the EMPLOYEE
table is a foreign key.
You can also implement a one-to-one mapping where the target table contains a foreign key reference to the source table. In Figure 27-2, the database design would change such that the ADDRESS
row would contain the EMP_ID
to identify the Employee
to which it belonged. In this case, the target must also have a relationship mapping to the source.
The update, insert and delete operations, which are normally done for the target before the source for privately owned one-to-one relationships, are performed in the opposite order when the target owns the foreign key. Target foreign keys normally occur in bidirectional one-to-one mappings (see Section 27.2.1, "Directionality"), because one side has a foreign key and the other shares the same foreign key in the other's table.
Target foreign keys can also occur when large cascaded composite primary keys exist (that is, one object's primary key is composed of the primary key of many other objects). In this case it is possible to have a one-to-one mapping that contains both foreign keys and target foreign keys.
In a foreign key, TopLink automatically updates the foreign key value in the object's row. In a target foreign key, it does not. In TopLink, use the Target Foreign Key option when a target foreign key relationship is defined.
When mapping a relationship, you must understand these differences between a foreign key and a target foreign key, to ensure that the relationship is defined correctly.
In a bidirectional relationship where the two classes in the relationship reference each other, only one of the mappings should have a foreign key. The other mapping should have a target foreign key. If one of the mappings in a bidirectional relationship is a one-to-many mapping, see Chapter 32, "Configuring a Relational Variable One-to-One Mapping" for details.
You can use a one-to-one mapping with a change policy (see Section 119.30, "Configuring Change Policy".
See Section 31, "Configuring a Relational One-to-One Mapping" for more information.
To maintain EJB compliance, the object attribute that points to the target of the relationship must be the local interface type–not the bean class.
TopLink provides variations on one-to-one mappings that lets you define complex relationships when the target of the relationship is a dependent Java object. For example, variable one-to-one mappings enable you to specify variable target objects in the relationship. These variations are not available for entity beans, but are valid for dependent Java objects.
For more information, see the Chapter 32, "Configuring a Relational Variable One-to-One Mapping".
Variable class relationships are similar to polymorphic relationships, except that in this case the target classes are not related through inheritance (and thus not good candidates for an abstract table), but through an interface.
To define variable class relationships in TopLink Workbench, use the variable one-to-one mapping selection, but choose the interface as the reference class. This makes the mapping a variable one-to-one. When defining mappings in Java code, use the VariableOneToOneMapping
class.
TopLink supports variable relationships only in one-to-one mappings. It handles this relationship in two ways:
Through the class indicator field (see Section 32.2, "Configuring Class Indicator").
Through unique primary key values among target classes implementing the interface (see Section 32.3, "Configuring Unique Primary Key").
Figure 27-3 Variable One-to-One Mappings with Class Indicator
See Chapter 32, "Configuring a Relational Variable One-to-One Mapping" for more information.
One-to-many mappings are used to represent the relationship between a single source object and a collection of target objects. They are a good example of something that is simple to implement in Java using a Collection
(or other collection types) of target objects, but difficult to implement using relational databases.
In a Java Collection
, the owner references its parts. In a relational database, the parts reference their owner. Relational databases use this implementation to make querying more efficient.
The purpose of creating this one-to-one mapping in the target is so that the foreign key information can be written when the target object is saved. Alternatives to the one-to-one mapping back reference include the following:
Use a direct-to-field mapping to map the foreign key and maintain its value in the application. Here the object model does not require a back reference, but the data model still requires a foreign key in the target table.
Use a many-to-many mapping to implement a logical one-to-many. This has the advantage of not requiring a back reference in the object model and not requiring a foreign key in the data model. In this model the many-to-many relation table stores the collection. It is possible to put a constraint on the join table to enforce that the relation is a logical one-to-many relationship.
Note:
Thephone
attribute shown in Figure 27-4 is of type Vector
. You can use a Collection
interface (or any class that implements the Collection
interface) for declaring the collection attribute. See Section 121.14, "Configuring Container Policy" for details.You can use a many-to-many mapping with a change policy (see Section 119.30, "Configuring Change Policy".
See Chapter 33, "Configuring a Relational One-to-Many Mapping" for more information.
Use one-to-many mappings for relationships between entity beans or between an entity bean and a collection of privately owned regular Java objects. When you create one-to-many mappings, also create a one-to-one mapping from the target objects back to the source. The object attribute that contains a pointer to the bean must be the local interface type–not the bean class.
TopLink automatically maintains back-pointers when you create or update bidirectional relationships between beans.
For more information, see Section 121.18, "Configuring Bidirectional Relationship".
Many-to-many mappings represent the relationships between a collection of source objects and a collection of target objects. They require the creation of an intermediate table for managing the associations between the source and target records.
Figure 27-5 illustrates a many-to-many mapping in Java and in relational database tables.
Note:
Theprojects
attribute shown inFigure 27-5 is of type Vector
. You can use a Collection
interface (or any class that implements the Collection
interface) for declaring the collection attribute. See Section 121.14, "Configuring Container Policy" for details.Many-to-many mappings are implemented using a relation table. This table contains columns for the primary keys of the source and target tables. Composite primary keys require a column for each field of the composite key. The intermediate table must be created in the database before using the many-to-many mapping.
The target class does not have to implement any behavior for the many-to-many mappings. If the target class also creates a many-to-many mapping back to its source, then it can use the same relation table, but one of the mappings must be set to read-only. If both mappings write to the table, they can cause collisions.
Indirection (lazy loading) is enabled by default in a many-to-many mapping, which requires that the attribute have the ValueHolderInterface
type or transparent collections. For more information on indirection, see Section 17.2.4, "Indirection (Lazy Loading)".
You can use a many-to-many mapping with a change policy (see Section 119.30, "Configuring Change Policy".
See Chapter 34, "Configuring a Relational Many-to-Many Mapping" for more information.
When you use CMP, many-to-many mappings are valid only between entity beans, and cannot be privately owned. The only exception is when a many-to-many mapping is used to implement a logical one-to-many mapping with a relation table.
TopLink automatically maintains back-pointers when you create or update bidirectional relationships.
For more information, see Section 121.18, "Configuring Bidirectional Relationship".
Aggregate collection mappings are used to represent the aggregate relationship between a single-source object and a collection of target objects. Unlike the TopLink one-to-many mappings, in which there should be a one-to-one back reference mapping from the target objects to the source object, there is no back reference required for the aggregate collection mappings, because the foreign key relationship is resolved by the aggregation.
Note:
To use aggregate collections with TopLink Workbench, you must use an amendment method (see Section 119.35, "Configuring Amendment Methods"), or manually edit the project source to add the mapping.Although aggregate collection mappings are similar to one-to-many mappings, they are not replacements for one-to-many mappings. Use aggregate collections only in situations where the target collections are of a reasonable size and if having a one-to-one back mapping is difficult.
Because oneEtoEmany relationships offer better performance and are more robust and scalable, consider using a oneEtoEmany relationship rather than an aggregate collection. In addition, aggregate collections are privately owned by the source of the relationship and must not be shared or referenced by other objects.
This section describes the following:
See Chapter 35, "Configuring a Relational Aggregate Collection Mapping" for more information.
Aggregate collection descriptors can use inheritance. You must also declare subclasses as aggregate collection. The subclasses can have their own mapped tables, or share the table with their parent class. See Section 16.2.2, "Descriptors and Inheritance" for more information on inheritance.
In a Java Collection
, the owner references its parts. In a relational database, the parts reference their owners. Relational databases use this implementation to make querying more efficient.
Aggregate collection mappings require a target table for the target objects.
To implement an aggregate collection mapping, the following must take place:
The descriptor of the target class must declare itself as an aggregate collection object. Unlike the aggregate object mapping, in which the target descriptor does not have a specific table to associate with, there must be a target table for the target object.
The descriptor of the source class must add an aggregate collection mapping that specifies the target class.
You can use aggregate collection mappings with entity beans if the source of the relationship is an entity bean or Java object, and the mapping targets are regular Java objects. Entity beans cannot be the target of an aggregate object mapping.
To implement an aggregate collection mapping, the following must take place:
The descriptor of the target class must declare itself to be an aggregate collection object. Unlike the aggregate object mapping, in which the target descriptor does not have a specific table to associate with, there must be a target table for the target object.
The descriptor of the source class must add an aggregate collection mapping that specifies the target class.
Direct collection mappings store collections of Java objects that are not TopLink-enabled. The object type stored in the direct collection is typically a Java type, such as String
.
It is also possible to use direct collection mappings to map a collection of non-String
objects. For example, it is possible to have an attribute that contains a collection of Integer
or Date
instances. The instances stored in the collection can be any type supported by the database and has a corresponding wrapper class in Java.
Support for primitive data types such as int
is not provided, because Java Collection
holds only objects.
Figure 27-6 illustrates how a direct collection is stored in a separate table with two fields. The first field is the reference key field, which contains a reference to the primary key of the instance owning the collection. The second field contains an object in the collection and is called the direct field. There is one record in the table for each object in the collection.
Note:
Theresponsibilities
attribute shown inFigure 27-6 is of type Vector
. You can use a Collection
interface (or any class that implements the Collection
interface) for declaring the collection attribute. See Section 121.14, "Configuring Container Policy" for details.Maps are not supported for direct collection because there is no key value.
You can use a direct collection mapping with any of the following Converter
instances:
You can use a direct collection mapping with a change policy (see Section 119.30, "Configuring Change Policy").
See Chapter 36, "Configuring a Relational Direct Collection Mapping" for more information.
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 are Java primitive wrapper types such as String
objects.
Figure 27-7 illustrates how a direct map is stored in a separate table with three fields. The first field (EMPID
) is the reference key field, which contains a reference to the primary key of the instance owning the collection. The second field (ADDRESS
) contains an object in the collection and is called the direct value field. The third field (TYPE
) contains the direct key field. In this example, the direct map uses a object type converter for the direct key field, converting the single character W in the database to the full string Work in the object (and H to Home).
You can use a direct collection mapping with any of the following Converter
instances:
You can use a direct map mapping with a change policy (see Section 119.30, "Configuring Change Policy").
See Chapter 38, "Configuring a Relational Direct Map Mapping" for more information.
Two objects–a source (parent or owning) object and a target (child or owned) object–are related by aggregation if there is a strict one-to-one relationship between them and all the attributes of the target object can be retrieved from the same table(s) as the source object. This means that if the source object exists, then the target object must also exist and if the source object is destroyed, then the target object is also destroyed.
An aggregate mapping allows you to associate data members in the target object with fields in the source object's underlying database tables.
You configure the aggregate mapping in the source object's descriptor. However, before doing so, you must designate the target object's descriptor as an aggregate (see Section 23.6, "Configuring a Relational Descriptor as a Class or Aggregate Type").
Aggregate objects are privately owned and should not be shared or referenced by other objects.
You cannot configure one-to-one, one-to-many, or many-to-many mappings from a nonaggregate object to an aggregate target object.
You can configure such mappings from an aggregate target object to another nonaggregate object. If you configure a one-to-many mapping from an aggregate target object to another nonaggregate object, you must configure a one-to-one mapping from the other object back to the source object that owns the aggregate (instead of to the aggregate target object itself). This is because the source object contains the table and primary key information of the aggregate target.
You can configure inheritance for a descriptor designated as an aggregate (see Section 16.2.2, "Descriptors and Inheritance"), however, in this case, all the descriptors in the inheritance tree must be aggregates. Aggregate and class descriptors cannot exist in the same inheritance tree.
This section describes the following:
You can use an aggregate object mapping with a change policy (see Section 119.30, "Configuring Change Policy".
For more information on configuring an aggregate object relationship mapping, see Chapter 37, "Configuring a Relational Aggregate Object Mapping".
Figure 27-8 shows an example aggregate object mapping between source object Employee
and target object Period
. In this example, the target object is not shared by other types of source object.
Figure 27-8 Aggregate Object Mapping with a Single Source Object
Aggregate target classes not shared among multiple source classes can have any type of mapping, including other aggregate object mappings.
Figure 27-9 shows an example aggregate object mapping in which different source objects–Employee
and Project
–map instances of the same type of target object, Period
.
Figure 27-9 Aggregate Object Mapping with Multiple Source Objects
When you configure the aggregate object mapping in the source object, you choose the source object table for that particular mapping. This allows different source types to store the same target information within their tables. Each source object's table may use different field names. TopLink automatically manages the case where multiple source object tables use different field names.
For example, in Figure 27-9, The Employee
attribute employPeriod
is mapped by an aggregate object mapping to target object Period
. This mapping associates Period
attribute startDate
with EMPLOYEE
table field START_DATE
. The Project
attribute projectPeriod
is also mapped by an aggregate object mapping to target object Period
. This mapping associates Period
attribute startDate
with PROJECT
table field S_DATE
.
Aggregate target classes shared with multiple source classes cannot have one-to-many or many-to-many mappings.
You must ensure that the following takes place:
The descriptor of the target class declares itself to be an aggregate object. Because all its information comes from its parent's table(s), the target descriptor does not have a specific table associated with it. You must, however, choose one or more candidate table(s) from which you can use fields in mapping the target.
In the example above, you could choose the EMPLOYEE
table so that the START_DATE
and END_DATE
fields are available during mapping.
The descriptor of the source class adds an aggregate object mapping that specifies the target class.
In the example above, the Employee
class has an attribute called employPeriod
that would be mapped as an aggregate object mapping with Period
as the reference class.
The source class must ensure that its table has fields that correspond to the field names registered with the target class.
If a source object has a null
target reference, TopLink writes NULLs to the aggregate database fields (see Section 37.3, "Configuring Allowing Null Values"). When the source is read from the database, it can handle this null
target in one of two ways:
Create an instance of the object with all its attributes equal to null
.
Put a null
reference in the source object without instantiating a target. (This is the default method of handling null
targets.)
Use transformation mappings for specialized translations for how a value is represented in Java and how it is represented in the database.
Tip:
Use transformation mappings only when mapping multiple fields into a single attribute. Because of the complexity of transformation mappings, it is often easier to perform the transformation with a converter or getter and setter methods of a directEtoEfield mapping. See Chapter 29, "Configuring a Relational Direct-to-Field Mapping" for more information.Figure 27-10 illustrates a transformation mapping. The values from the B_DATE
and B_TIME
fields are used to create a java.util.Date
to be stored in the birthDate
attribute.
Often, a transformation mapping is appropriate when values from multiple fields are used to create an object. This type of mapping requires that you provide an attribute transformation that is invoked when reading the object from the database. This must have at least one parameter that is an instance of Record
. In your attribute transformation, you can use Record
method get
to retrieve the value in a specific column. Your attribute transformation can specify a second parameter, when it is an instance of Session
. The Session
performs queries on the database to get additional values needed in the transformation. The transformation should return the value to be stored in the attribute.
Transformation mappings also require a field transformation for each field, to be written to the database when the object is saved. The transformation returns the value to be stored in that field.
See Chapter 39, "Configuring a Relational Transformation Mapping" for more information.