Oracle® Containers for J2EE Enterprise JavaBeans Developer's Guide 10g Release 3 (10.1.3) B14428-02 |
|
Previous |
Next |
This chapter describes the various options that you can configure in order to use an EJB 3.0 entity.
Note: In this release, OC4J supports a subset of the functionality specified in the EJB 3.0 public review draft. You may need to make code changes to your EJB 3.0 OC4J application after the EJB 3.0 specification is finalized and OC4J is updated to full EJB 3.0 compliance. For more information, see "Understanding EJB Support in OC4J".There are no OC4J-proprietary EJB 3.0 annotations. For all OC4J-specific configuration, you must still use the EJB 2.1 |
Table 7-1 lists these options and indicates which are basic (applicable to most applications) and which are advanced (applicable to more specialized applications).
For more information, see:
Table 7-1 Configurable Options for an EJB 3.0 Entity
Every EJB 3.0 entity must have a primary key field (see "Configuring an EJB 3.0 Entity Primary Key Field").
You can specify a primary key as a single primitive or JDK object type.
You can either assign primary key values yourself, or, more typically, you can associate a primary key field with a primary key value generator (see "Configuring EJB 3.0 Entity Automatic Primary Key Generation").
You must specify one entity field as the primary key. You can specify a primary key as a single primitive or JDK object type or as a composite primary key class made up of one or more primitive or JDK object types
Typically, you associate the primary key field with a primary key value generator (see "Configuring EJB 3.0 Entity Automatic Primary Key Generation").
Note: For an EJB 3.0 basic mapping code example, see:http://www.oracle.com/technology/tech/java/oc4j/ejb3/howtos-ejb3/howtoejb30mappingannotations/doc/how-to-ejb30-mapping-annotations.html#id |
Example 7-1 shows how to use the @Id
annotation to specify an entity field as the primary key. In this example, primary key values are generated using a table generator (see "Configuring EJB 3.0 Entity Automatic Primary Key Generation").
Typically, you associate a primary key field (see "Configuring an EJB 3.0 Entity Primary Key Field") with a primary key value generator so that when an entity instance is created, a new, unique primary key value is assigned automatically.
Table 7-2 lists the types of primary key value generators that you can define.
Table 7-2 EJB 3.0 Entity Primary Key Value Generators
Type | Description | For more information, see ... |
---|---|---|
Generated Id Table |
A database table the container uses to store generated primary key values for entities. Typically shared by multiple entity types that use table-based primary key generation. Each entity type will typically use its own row in the table to generate the primary key values for that entity class. Primary key values are positive integers. |
"Table Sequencing" in the Oracle TopLink Developer's Guide |
Table Generator |
A primary key generator which you can reference by name, defined at one of the package, class, method, or field level. The level at which you define it will depend upon the desired visibility and sharing of the generator. No scoping or visibility rules are actually enforced. Oracle recommends that you define the generator at the level for which it will be used. This generator is based on a database table. |
"Table Sequencing" in the Oracle TopLink Developer's Guide |
Sequence Generator |
A primary key generator which you can reference by name, defined at one of the package, class, method, or field level. The level at which you define it will depend upon the desired visibility and sharing of the generator. No scoping or visibility rules are actually enforced. Oracle recommends that you define the generator at the level for which it will be used. This generator is based on a sequence object that the database server provides. |
"Native Sequencing With an Oracle Database Platform" in the Oracle TopLink Developer's Guide "Native Sequencing With a Non-Oracle Database Platform" in the Oracle TopLink Developer's Guide |
Note: For an EJB 3.0 automatic primary key generation code example, see:http://www.oracle.com/technology/tech/java/oc4j/ejb3/howtos-ejb3/howtoejb30mappingannotations/doc/how-to-ejb30-mapping-annotations.html#sequencing |
Example 7-2 shows how to use the @GeneratedIdTable
annotation to specify a primary key value generator based on a database table. When a new instance of Employee
is created, a new value for entity field id
is obtained from EMPLOYEE_GENERATOR_TABLE
.
Example 7-2 @GeneratedIdTable
@Entity @Table(name="EJB_EMPLOYEE") @GeneratedIdTable( name="EMPLOYEE_GENERATOR_TABLE", table=@Table(name="EJB_EMPLOYEE_SEQ"), pkColumnName="SEQ_NAME", valueColumnName="SEQ_COUNT" ) public class Employee implements Serializable { ... @Id(generate=TABLE, generator="EMPLOYEE_GENERATOR_TABLE") @Column(name="EMPLOYEE_ID", primaryKey=true) public Integer getId() { return id; } ... }
Example 7-3 shows how to use the @TableGenerator
annotation to specify a primary key value generator based on a database table. When a new instance of Employee
is created, a new value for entity field id
is obtained from EMPLOYEE_GENERATOR_TABLE
. You must set the @Id
annotation attribute generate
to TABLE
in this case.
Example 7-3 @TableGenerator
@Entity @Table(name="EJB_ADDRESS") public class Address implements Serializable { ... @Id(generate=TABLE, generator="ADDRESS_TABLE_GENERATOR") @TableGenerator( name="ADDRESS_TABLE_GENERATOR", tableName="EMPLOYEE_GENERATOR_TABLE", pkColumnValue="ADDRESS_SEQ" ) @Column(name="ADDRESS_ID") public Integer getId() { return id; } ... }
Example 7-3 shows how to use the @SequenceGenerator
annotation to specify a primary key value generator based on a sequence object provided by the database. When a new instance of Employee
is created, a new value for entity field id
is obtained from database sequence object ADDRESS_SEQ
. You must set the @Id
annotation attribute generate
to SEQUENCE
in this case.
Example 7-4 @SequenceGenerator
@Entity @Table(name="EJB_ADDRESS") public class Address implements Serializable { ... @Id(generate=SEQUENCE, generator="ADDRESS_TABLE_GENERATOR") @SequenceGenerator( name="ADDRESS_TABLE_GENERATOR", sequenceName="ADDRESS_SEQ" ) @Column(name="ADDRESS_ID") public Integer getId() { return id; } ... }
You can define the characteristics of the database table into which the TopLink persistence manager persists your entity, including:
This is particularly important if you have an existing database schema.
If you do not have an existing database schema, you can delegate table and column definition to OC4J by omitting this configuration: at deployment time, OC4J will create default table and column names based on class and data member names.
Note: You can download an EJB 3.0 entity table and column code example from:http://www.oracle.com/technology/tech/java/oc4j/ejb3/howtos-ejb3/howtoejb30mappingannotations/doc/how-to-ejb30-mapping-annotations.html . |
The primary table is the table into which the TopLink persistence manager persists your entity: in particular, it is the table that stores the entity's primary key (see "Configuring an EJB 3.0 Entity Primary Key"). Optionally, you can also specify one or more secondary tables (see "Configuring a Secondary Table") if the entity's persistent data is stored across multiple tables.
You define the primary table at the entity class level.
Example 7-5 shows how to use the @Table
annotation to define the primary table for the Employee
class. The TopLink persistence manager will persist instances of this entity to a table named EJB_EMPLOYEE
.
Specifying one or more secondary tables indicates that the entity's persistent data is stored across multiple tables. You must first specify a primary table (see "Configuring the Primary Table") before you can specify any secondary tables.
You define a secondary table at the entity class level.
If you specify one or more secondary tables, you can specify the secondary table name in the column definition (see "Configuring a Join Column") for persistent fields that are stored in that table. This enables the distribution of entity persistent fields across multiple tables.
Example 7-6 shows how to use the @SecondaryTable
annotation to specify that some of the entity's persistent data is stored in a table named EJB_SALARY
.
The column is, by default, the name of the column in the primary table (see "Configuring the Primary Table") into which the TopLink persistence manager stores the field's value.
You define the column at one of the property (getter or setter method) or field level of your entity.
If you specified one or more secondary tables (see "Configuring a Secondary Table"), you can specify the secondary table name in the column definition. This enables the distribution of entity persistent fields across multiple tables.
Example 7-7 shows how to use the @Column
annotation to specify column F_NAME
in the primary table for field firstName
.
Example 7-7 @Column for the Primary Table
@Column(name="F_NAME") public String getFirstName() { return firstName; }
Example 7-8 shows how to use the @Column
annotation to specify column SALARY
in secondary table EMP_SALARY
for field salary
.
A join column specifies a mapped, foreign key column for joining an entity association or a secondary table.
You can define a join column with a:
secondary table (see Example 7-9)
one-to-one mapping (see Example 7-10)
many-to-one mapping (see Example 7-11)
one-to-many mapping (see Example 7-12)
Example 7-9 shows how to use the @JoinColumn
annotation to specify a join column with a secondary table. For more information, see "Configuring a Secondary Table".
Example 7-9 @JoinColumn with a Secondary Table
@Entity @Table(name="EJB_EMPLOYEE") @SecondaryTable(name="EJB_SALARY") @JoinColumn(name="EMP_ID", referencedColumnName="EMP_ID") public class Employee implements Serializable { ... }
Example 7-10 shows how to use the @JoinColumn
annotation to specify a join column with a one-to-one mapping. For more information, see "Configuring a One-to-One Mapping".
Example 7-10 @JoinColumn with a One-to-One Mapping
@OneToOne(cascade=ALL, fetch=LAZY) @JoinColumn(name="ADDR_ID") public Address getAddress() { return address; }
Example 7-11 shows how to use the @JoinColumn
annotation to specify a join column with a many-to-one mappiong. For more information, see "Configuring a Many-to-One Mapping".
Example 7-11 @JoinColumn with a Many-to-One Mapping
@ManyToOne(cascade=PERSIST, fetch=LAZY) @JoinColumn(name="MANAGER_ID", referencedColumnName="EMP_ID") public Employee getManager() { return manager; }
Example 7-12 shows how to use the @JoinColumn
annotation to specify a join column with a one-to-many mapping. Fore more information, see "Configuring a One-to-Many Mapping".
In an EJB 3.0 entity, you define container-managed relationship (CMR) fields (see "What are Container-Managed Relationship Fields?") as follows:
Note: You can download an EJB 3.0 entity container-managed relationship field code example from:http://www.oracle.com/technology/tech/java/oc4j/ejb3/howtos-ejb3/howtoejb30mappingannotations/doc/how-to-ejb30-mapping-annotations.html . |
Use a basic mapping to map an field that contains a primitive or JDK object value. For example, use a basic mapping to store a String
attribute in a VARCHAR
column.
You define a basic mapping at one of the property (getter or setter method) or field level of your entity.
For more information, see "Understanding Direct-to-Field Mapping" in the Oracle TopLink Developer's Guide.
Note: For an EJB 3.0 basic mapping code example, see:http://www.oracle.com/technology/tech/java/oc4j/ejb3/howtos-ejb3/howtoejb30mappingannotations/doc/how-to-ejb30-mapping-annotations.html#basic . |
Example 7-13 shows how to use the @Basic
annotation to specify a basic mapping for field firstName
.
Use a large object (LOB) mapping to specify that a persistent property or field should be persisted as a LOB to a database-supported LOB type. A LOB may be either a binary (BLOB) or character (CLOB) type.
You define a large object mapping at one of the property (getter or setter method) or field level of your entity.
For more information, see:
"Understanding Direct-to-Field Mapping" in the Oracle TopLink Developer's Guide
"Using a Converter Mapping" in the Oracle TopLink Developer's Guide
"Type Conversion Converter" in the Oracle TopLink Developer's Guide
Example 7-14 shows how to use the @Lob
annotation to specify a large object mapping for field image
.
Use a serialized object mapping to specify that a persistent property should be persisted as a serialized stream of bytes.
You define a serialized object at one of the property (getter or setter method) or field level of your entity.
For more information, see:
"Understanding Direct-to-Field Mapping" in the Oracle TopLink Developer's Guide
"Using a Converter Mapping" in the Oracle TopLink Developer's Guide
"Serialized Object Converter" in the Oracle TopLink Developer's Guide
Example 7-15 shows how to use the @Serialized
annotation to specify a serialized object mapping for field picture
.
Use a one-to-one mapping to 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.
You define a one-to-one mapping at one of the property (getter or setter method) or field level of your entity.
For more information, see "Understanding One-to-One Mapping" in the Oracle TopLink Developer's Guide.
Note: For an EJB 3.0 basic mapping code example, see:http://www.oracle.com/technology/tech/java/oc4j/ejb3/howtos-ejb3/howtoejb30mappingannotations/doc/how-to-ejb30-mapping-annotations.html#onetoone . |
Example 7-16 shows how to use the @OneToOne
annotation to specify a one-to-one mapping for field address
.
Use a many-to-one mapping to 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.
You define a many-to-one mapping at one of the property (getter or setter method) or field level of your entity.
For more information, see "Understanding One-to-One Mapping" in the Oracle TopLink Developer's Guide.
Note: For an EJB 3.0 basic mapping code example, see:http://www.oracle.com/technology/tech/java/oc4j/ejb3/howtos-ejb3/howtoejb30mappingannotations/doc/how-to-ejb30-mapping-annotations.html#manytoone . |
Example 7-17 shows how to use the @ManyToOne
annotation to specify a many-to-one mapping for field manager
.
Use a one-to-many mapping to represent the relationship between a single source object and a collection of target objects. This relationship is a good example of something that is simple to implement in Java using a Vector
(or other collection types) of target objects, but difficult to implement using relational databases.
You define a one-to-many mapping at one of the property (getter or setter method) or field level of your entity.
For more information, see "Understanding One-to-Many Mapping" in the Oracle TopLink Developer's Guide.
Note: For an EJB 3.0 basic mapping code example, see:http://www.oracle.com/technology/tech/java/oc4j/ejb3/howtos-ejb3/howtoejb30mappingannotations/doc/how-to-ejb30-mapping-annotations.html#onetomany . |
Example 7-18 shows how to use the @OneToMany
annotation to specify a one-to-many mapping for field managedEmployees
.
Use a many-to-many mapping to represent the relationships between a collection of source objects and a collection of target objects. This mapping requires the creation of an intermediate table (the association table) for managing the associations between the source and target records.
You define a many-to-many mapping at one of the property (getter or setter method) or field level of your entity.
For more information, see "Understanding Many-to-Many Mapping" in the Oracle TopLink Developer's Guide.
Note: For an EJB 3.0 basic mapping code example, see:http://www.oracle.com/technology/tech/java/oc4j/ejb3/howtos-ejb3/howtoejb30mappingannotations/doc/how-to-ejb30-mapping-annotations.html#manytomany . |
Example 7-19 shows how to use the @ManyToMany
annotation to specify a many-to-many mapping for field projects
and how to use the @AssociationTable
annotation to specify an association table.
Example 7-19 @ManyToMany
@ManyToMany(cascade=PERSIST) @AssociationTable( table=@Table(name="EJB_PROJ_EMP"), joinColumns=@JoinColumn(name="EMP_ID", referencedColumnName="EMP_ID"), inverseJoinColumns=@JoinColumn(name="PROJ_ID", referencedColumnName="PROJ_ID") ) public Collection getProjects() { return projects; }
Two entities–an owning (parent or source) entity and an owned (child or target) entity–are related by aggregation if there is a strict one-to-one relationship between them and all the attributes of the owned entity can be retrieved from the same table(s) as the owning entity. This means that if the owning entity exists, then the owned entity must also exist and if the owning entity is destroyed, then the owned entity is also destroyed.
An aggregate mapping allows you to associate data members in the owned entity with fields in the owning entity's underlying database tables.
In the owning entity, you designate the owned field or setter as embedded.In owned entity, you designate the class as embeddable and associate it with the owning entity's table name.
In the owning entity, you can override any column specifications (see "Configuring a Column") made in the owned entity.
For more information, see "Understanding Aggregate Mapping" in the Oracle TopLink Developer's Guide.
Note: For an EJB 3.0 basic mapping code example, see:http://www.oracle.com/technology/tech/java/oc4j/ejb3/howtos-ejb3/howtoejb30mappingannotations/doc/how-to-ejb30-mapping-annotations.html#embedded . |
Example 7-20 shows how to use the @Embedded
annotation to specify an aggregate mapping for field period
. This field contains an instance of EmploymentPeriod
. Example 7-21 shows how to use the @Embeddable
annotation to specify the EmploymentPeriod
entity class as being eligible for use in an aggregate mapping and how to use the @Table
annotation (see "Configuring the Primary Table") to associate this class with the owning entity's table.
Example 7-20 @Embedded
@Entity @Table(name="EJB_EMPLOYEE") public class Employee implements Serializable { ... @Embedded public EmploymentPeriod getPeriod() { return period; } ... }
Example 7-21 @Embeddable
@Embeddable @Table(name="EJB_EMPLOYEE") public class EmploymentPeriod implements Serializable { private Date startDate; private Date endDate; ... }
You can use the @AttributeOverride
in the owning entity (see Example 7-22) to override the column definitions made in the owned entity (see Example 7-23).
Example 7-22 @Embedded and @AttributeOverride
@Entity @Table(name="EJB_EMPLOYEE") public class Employee implements Serializable { ... @Embedded( { @AttributeOverride(name="startDate", column=@Column("EMP_START")), @AttributeOverride(name="endDate", column=@Column("EMP_END")) } ) public EmploymentPeriod getPeriod() { return period; } ... }
You can specify an entity field to function as a version field for use in a TopLink optimistic version locking policy. OC4J uses this version field to ensure integrity when reattaching (see "Detaching and Merging an Entity Bean Instance") and for overall optimistic concurrency control.
You define the optimistic lock version field at one of the property (getter or setter method) or field level of your entity.
For more information, see "Optimistic Version Locking Policies" in the Oracle TopLink Developer's Guide.
Example 7-24 shows how to use the @Version
annotation to define an optimistic version locking policy using column VERSION
.
Lazy loading is an Oracle-specific option that you configure using the EJB 2.1 orion-ejb-jar.xml
file.
For more information, see "Configuring Lazy Loading on Finder Methods".
You can specify an EJB 3.0 entity class method as a callback method for any of the following lifecycle events:
Pre-persist: a method called on an object when that object has the create operation applied to it.
Post-persist: a method called on an object that has just been inserted into the database. You can use this method to notify any of the object's dependents or to update information not accessible until the object has been inserted.
Pre-remove: a method called on an object when that object has the remove operation applied to it.
Post-remove: a method called on an object that has just been deleted from the database. You can use this method to notify or remove any of the object's dependents.
Pre-update: a method called when an object's row is about to be updated.
The TopLink persistence manager calls this method only if it determines that an actual update is required (only if it is prepared to send SQL to the database). Contrast this with a post-update callback which is called whether or not an actual change was required.
You can use this method to modify the row before insert.
Post-update: a method called on an object that has just been updated into the database.
Use this callback to update any dependent objects.
The TopLink persistence manager calls this method even if it determines that no actual update is required (even if it determines that no SQL needs to be sent to the database). Use the pre-update callback if you want to be notified only when the object has actually been changed.
Post-load: a method called on an object that has just been built from the database. This event can be used to correctly initialize an object's non-persistent attributes or to perform complex optimizations or mappings. This event is called whenever an object is built.
The entity class method must have the following signature:
public int <MethodName>()
For more information, see:
"Descriptor Event Manager" in the Oracle TopLink Developer's Guide
"Configuring a Domain Object Method as an Event Handler" in the Oracle TopLink Developer's Guide
Note: For an EJB 3.0 lifecycle callback method code example, see:http://www.oracle.com/technology/tech/java/oc4j/ejb3/howtos-ejb3/howtoejb30mappingannotations/doc/how-to-ejb30-mapping-annotations.html#callbacks . |
You can specify an EJB 3.0 entity class method as a lifecycle callback method using any of the following annotations:
Example 7-25 shows how to use the @PrePersist
annotation to specify EJB 3.0 entity class method initialize
as a lifecycle callback method.
OC4J supports the following inheritance strategies for mapping a class or class hierarchy to a relational database schema:
You can configure either approach using annotations (see "Using Annotations").
Note: For an EJB 3.0 inheritance code example, see:http://www.oracle.com/technology/tech/java/oc4j/ejb3/howtos-ejb3/howtoejb30inheritance/doc/how-to-ejb30-inheritance.html . |
In this strategy, fields that are specific to a subclass are mapped to a separate table than the fields that are common to the parent class, and a join is performed to instantiate the subclass.
The root of the class hierarchy is represented by a single table. Each subclass is represented by a separate table that contains the columns that are specific to the subclass (not inherited from its superclass), as well as the column that represent the subclass's primary key. If the subclass does not have any additional state over its superclass, a separate table is not required.
If the subclass table has primary key column, it serves as a foreign key to the primary key of the superclass table. If the subclass table primary key column name is the same as that of the primary key column of the superclass table, OC4J infers this relationship. If the subclass table primary key column name is not the same as that of the primary key column of the superclass table (or, if the subclass table does not have primary key column), you must specify a subclass table column to use to join the primary table of an entity subclass to the primary table of its superclass.
The primary table of the superclass also has a column that serves as a discriminator column, that is, a column whose value identifies the specific subclass to which the instance that is represented by the row belongs.
For more information, see "Configuring Joined Subclass Inheritance with Annotations".
In this strategy, all the classes in a hierarchy are mapped to a single table. The table has a column that serves as a discriminator column. Each subclass that adds additional state maps to this new state only in this single table. Such columns are only used by that subclass.
For more information, see "Configuring Single Table Inheritance with Annotations".
This section describes the following:
The following examples show how to configure inheritance using a joined subclass approach (see "Joined Subclass"): Example 7-26 shows how to use the @Inheritance
annotation in the base class Project
. Example 7-27 and Example 7-28 show how to use the @Inheritance
annotation in derived classes LargeProject
and SmallProject
, respectively.
The primary table is EJB_PROJECT
to which both Project
and SmallProject
are mapped. EJB_PROJECT
has a discriminator column called PROJ_TYPE
that represents Project
, LargeProject
and SmallProject
with values P
, L
and S
, respectively. LargeProject
adds additional state to Project
, so is mapped to its own table, EJB_LPROJECT
, which contains fields specific to LargeProject
, such as BUDGET
. Note that EJB_LPROJECT does not have a primary key column; instead it has a foreign key (PROJ_ID
) that has the same name as the primary key of EJB_PROJECT
.
Note that in Example 7-27, because the LargeProject class primary key column name (LARGE_PROJECT_ID
) is not the same as that of the primary key column of the superclass table (ID
), you must use the @InheritanceJoinColumn
annotation to specify the column used to join the LargeProject primary table to the primary table of its superclass.
Example 7-26 @Inheritance: Base Class Project in Joined Subclass Inheritance
@Entity @Table(name="EJB_PROJECT") @Inheritance(strategy=JOINED, discriminatorValue="P") @DiscriminatorColumn(name="PROJ_TYPE") public class Project implements Serializable { ... @Id() @Column(name="PROJECT_ID", primaryKey=true) public Integer getId() { return id; } ... }
Example 7-27 @Inheritance: Derived Class LargeProject in Joined Subclass Inheritance
@Entity @Table(name="EJB_LPROJECT") @Inheritance(discriminatorValue="L") @InheritanceJoinColumn(name="LARGE_PROJECT_ID") public class LargeProject extends Project { ... @Id() @Column(name="LARGE_PROJECT_ID", primaryKey=true) public Integer getProjectId() { return projectId; } ... }
The following examples show how to configure inheritance using a single table for each class hierarchy approach (see "Single Table for each Class Hierarchy"): Example 7-26 shows how to use the @Inheritance
annotation in the base class Project
. Example 7-27 and Example 7-28 show how the @Inheritance
annotation is not needed in derived classes LargeProject
and SmallProject
, respectively.
The primary table is EJB_PROJECT
to which both Project
and SmallProject
are mapped. The EJB_PROJECT
table would contain all the columns for Project
and an additional column (BUDGET
) used only by LargeProject
.
Example 7-29 @Inheritance: Base Class Project in Single Table Inheritance
@Entity @Table(name="EJB_PROJECT") @Inheritance(strategy=SINGLE_TABLE, discriminatorValue="P") @DiscriminatorColumn(name="PROJ_TYPE") public class Project implements Serializable { ... }