This section describes concepts for relational and nonrelational mappings that are unique to EclipseLink:
To define a mapping, you draw upon the following components:
The data representation specific to the data source (such as a relational database table or schema-defined XML element) in which you store the object's data.
A descriptor for a particular object class.
An object class to map.
Note: A mapping is the same regardless of whether your project is persistent or nonpersistent. |
For an example of a typical EclipseLink mapping, see Mapping Examples.
The type of data source you define in your project determines the type of mappings you can use and how you configure them. In a persistent project, you use mappings to persist to a data source. In a nonpersistent project, you use mappings simply to transform between the object format and some other data representation (such as XML).
A descriptor represents a particular domain object: it describes the object's class. A descriptor also owns the mappings: one mapping for each of the class data members that you intend to persist or transform in memory. For more information about descriptors, see Chapter 5, "Understanding Descriptors".
Although EclipseLink supports more complex mappings, most EclipseLink classes map to a single database table or XML element that defines the type of information available in the class. Each object instance of a given class maps to a single row comprising the object's attributes, plus an identifier (the primary key) that uniquely identifies the object.
Figure 6-1 illustrates the simplest database mapping case in which:
Table_X in the database represents Class_X.
Object_X1 and Object_X2 are instances of Class_X.
Individual rows in Table_X represent Object_X1 and Object_X2, as well as any other instances of Class_X.
Figure 6-1 How Classes and Objects Map to a Database Table
EclipseLink provides you with the tools to build these mappings, from the simple mappings illustrated in Figure 6-1, to complex mappings.
For an additional example of a relational mapping, see Figure 6-2, "Serialized Object Converter (relational)".
If existing EclipseLink mappings do not meet your needs, you can create custom mappings using mapping extensions. These extensions include the following:
Note: Except for simple type translation, you can use the mapping converters and transformers regardless of whether your data source is relational or nonrelational. Simple type translation is applicable only to XML projects. |
The serialized object converter can be used with direct and direct collection mappings, allowing you to map complex objects into binary fields through Java object serialization. Serialized objects are normally stored in RAW
or Binary Large Object (BLOB)
fields in the database, or HEX
or BASE64
elements in an XML document.
Figure 6-2 shows an example of a direct-to-field mappings that uses a serialized object converter. The attribute jobDescription
contains a formatted text document that is stored in the JOB_DESC
field of the database.
Figure 6-2 Serialized Object Converter (relational)
Figure 6-3 demonstrates an example of a nonrelational mapping that uses a serialized object converter. The attribute jobDescription
contains a formatted text document that EclipseLink stores in the JOB DESCRIPTION
element of an XML schema.
Figure 6-3 Serialized Object Converter (nonrelational)
The serialized object converter relies on the Java serializer. Before you map a domain object with the serialized object converter, ensure that the domain object implements the java.io.Serializable
interface (or inherits that implementation) and marks all nonserializable fields transient.
The type conversion converter can be used with direct and direct collection mappings, allowing you to map complex objects into binary fields. For example, a Number
in the data source can be mapped to a String
in Java, or a java.util.Date
in Java can be mapped to a java.sql.Date
in the data source.
Figure 6-4 illustrates a type conversion mapping (relational). Because the java.util.Date
class is stored by default as a Timestamp
in the database, it must first be converted to an explicit database type such as java.sql.Date
(required only for DB2–most other databases have a single date data type that can store any date or time).
Figure 6-4 Type Conversion Mapping (relational)
Figure 6-5 illustrates a type conversion mapping (nonrelational). java.util.Date
object is mapped to a String in a XML schema.
Figure 6-5 Type Conversion Mapping (nonrelational)
You can use a type conversion converter to specify the specific database type when that type must be handled specially for the database. This includes support for the special Oracle JDBC binding options required for NCHAR
, NVARCHAR2
, and NCLOB
fields as well as the special Oracle Thin JDBC insert and update requirements for handling BLOB
and CLOB
fields greater than 5K.
EclipseLink uses the NCharacter
, NClob
and NString
types in the org.eclipse.persistence.platform.database.oracle
package as the converter data type to support the NCHAR
, NCLOB
and NVARCHAR2
types. EclipseLink uses the java.sql.Blob
and Clob
types as the converter data type to support BLOB
and CLOB
values greater than 5K.
You can configure a type conversion converter to map a data source time type (such as TIMESTAMP
) to a java.lang.String
provided that the String value conforms to the following formats:
YYYY/MM/DD HH:MM:SS
YY/MM/DD HH:MM:SS
YYYY-MM-DD HH:MM:SS
YY-MM-DD HH:MM:SS
For more complex String
to TIMESTAMP
type conversion, consider a transformation mapping (see Transformation Mapping).
You can also use the @TypeConverter
annotation to modify data values during the reading and writing of a mapped attribute. Each TypeConverter
must be uniquely named and can be defined at the class, field, and property level, and can be specified within an Entity
, MappedSuperclass
and Embeddable
class. A TypeConverter
is always specified by using an @Convert
annotation.
You can place a @TypeConverter
on a Basic
, BasicMap
, or BasicCollection
mapping. For more information on these annotations, see Java Persistence API (JPA) Extensions Reference for EclipseLink.
The object type converter can be used with direct and direct collection mappings allowing you to match a fixed number of values to Java objects. Use this converter when the values in the schema differ from those in Java.
Figure 6-6 illustrates an object type conversion between the Employee
attribute gender
and the XML element gender
. If the value of the Java object attribute is Female
, EclipseLink stores it in the XML element as F
.
You can also perform object type transformations by using the @ObjectTypeConverter
annotation. This annotation specifies an org.eclipse.persistence.mappings.converters.ObjectTypeConverter
that converts a fixed number of database data value(s) to Java object value(s) during the reading and writing of a mapped attribute. For this annotation you must provide values for the array of conversion values by using the @ConversionValue
annotation. For more information, see the descriptions of @ObjectTypeConverter
and @ConversionValue
in Java Persistence API (JPA) Extensions Reference for EclipseLink.
In some special circumstances, existing mapping types and their default Java to data source type handling may be insufficient. In these special cases, you can consider using a transformation mapping to perform specialized translations between how a value is represented in Java and in the data source.
Tip: 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 direct-to-field mapping. |
Figure 6-7 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.
A transformation mapping is made up of the following two components:
attribute transformer: performs the object attribute transformation at read time
field transformer: performs the object attribute-to-field transformation at write time
You can implement a transformer as either a separate class or as a method on your domain object.
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 optionally specify a second parameter, 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.
Within your implementation of the attribute and field transformation, you can take whatever actions are necessary to transform your application data to suit your data source, and vise versa.
You can perform transformation mappings between database columns and attribute values by using the @Transformation
annotation. Use this annotation with the @WriteTransformer
and @ReadTransformer
annotations. The @WriteTransformer
annotation is used to transform a single attribute value to a single database column value. For this annotation you have the option of providing an implementation of the FieldTransformer
interface. For the @ReadTransformer
annotation, you must provide an implementation of the org.eclipse.persistence.mappings.transformers.AttributeTransformer
interface. For more information on these annotations, see the descriptions of the @Transformation
, @ReadTransformer
, and @WriteTransformer
in Java Persistence API (JPA) Extensions Reference for EclipseLink.