Oracle® Application Server Containers for J2EE Enterprise JavaBeans Developer's Guide
10g Release 2 (10.1.2) Part No. B15505-02 |
|
Previous |
Next |
This chapter demonstrates simple Container Managed Persistence (CMP) EJB development with a basic configuration and deployment. Download the CMP entity bean example (cmpapp.jar
) from the OC4J sample code page at on the OTN Web site.
This chapter demonstrates the following:
See Chapter 8, "BMP Entity Beans", for an example of how to create a simple bean-managed persistent entity bean. For a description of persisting object relationships between EJBs, see Chapter 6, "Entity Relationship Mapping".
The persistent data in your CMP bean can be one of the following:
Persistence field—Simple data type that is persisted to a database table. This field is a direct attribute of the bean.
Relationship field—Relationship to another bean.
Each type results in its own complex rules of how to configure. This section discusses persistence fields. For information on relationship fields, see Chapter 6, "Entity Relationship Mapping".
In CMP entity beans, you define the persistent data both in the bean instance and in the deployment descriptor.
Get/Set methods in the bean instance: For each persistence and relationship field, both a get and a set method is created. For persistence fields, the data type of the parameter returned from the get method and passed into the set method defines the simple data type of the field. The name of the field is designated by the name of the get and set methods.
The following XML shows the get and set methods for the employee name persistence field. A String
is passed back from the get method and into the set method. Thus, the String
is the simple data type of the field. If you remove the "get" and "set" from the method names and then lower the case of the first letter, you have the persistence field name. In this case, empName
is the persistence field name.
public abstract String getEmpName() throws RemoteException; public abstract void setEmpName(String empName) throws RemoteException;
The deployment descriptor defines these fields as persistent. Each field name must be defined in a <cmp-field><field-name>
element in the EJB deployment descriptor. In the employee example, three persistence data fields are defined in the data accessor methods: empNo
, empName
, and salary
.
These fields are defined as persistent fields in the ejb-jar.xml
deployment descriptor within the <cmp-field><field-name>
element, as follows:
<enterprise-beans> <entity> <display-name>Employee</display-name> <ejb-name>EmployeeBean</ejb-name> <local-home>employee.EmployeeLocalHome</local-home> <local>employee.EmployeeLocal</local> <ejb-class>employee.EmployeeBean</ejb-class> <persistence-type>Container</persistence-type> <prim-key-class>java.lang.Integer</prim-key-class> <reentrant>False</reentrant> <cmp-version>2.x</cmp-version> <abstract-schema-name>Employee</abstract-schema-name><cmp-field><field-name>empNo</field-name></cmp-field> <cmp-field><field-name>empName</field-name></cmp-field> <cmp-field><field-name>salary</field-name></cmp-field>
<primkey-field>empNo</primkey-field>
</entity> ... </enterprise-beans>
For these fields to be mapped to a database, you can do one of the following:
Accept the defaults for these fields and avoid more deployment descriptor configuration. See "Default Mapping of Persistent Fields to the Database" on how the default mapping occurs.
Map the persistent data fields to columns in a table that exists in a designated database. The persistent data mapping is configured within the orion-ejb-jar.xml
file. See "Explicit Mapping of Persistent Fields to the Database" for more information.
Note: The entire CMP entity bean example (cmpapp.jar ) is available on OTN from the OC4J sample code page at http://www.oracle.com/technology/tech/java/oc4j/demos/ on the OTN Web site.
|
If you simply define the persistent fields in the ejb-jar.xml
file, then OC4J provides the following mappings of these fields to the database:
Database—The default database as set up in your OC4J instance configuration. For the JNDI name, use the <location>
element for emulated data sources and <ejb-location>
element for non-emulated data sources.
Upon installation, the default database is a locally installed Oracle database that must be listening on port 1521 with a SID of ORCL
. To customize the default database, change the first configured database to point to your database.
Note: See the Data Source chapter in the Oracle Application Server Containers for J2EE Services Guide for more information on configuring Data Source objects. |
Table—The container automatically creates a default table where the name of the table is guaranteed to be unique. For all future redeployments, copy the generated orion-ejb-jar.xml
file with this table name into the same directory as your ejb-jar.xml
file. Thus, all future redeployments have the same table names as first generated. If you do not copy this file over, different table names may be generated.
The table name is constructed with the following names, where each is separated by an underscore (_):
EJB name defined in <ejb-name>
in the deployment descriptor.
JAR file name, including the .jar
extension. However, all dashes (-) and periods (.) are converted to underscores (_) to follow SQL conventions. For example, if the name of your JAR file is employee.jar
, then employee_jar
is appended to the name.
Application name: This is the name of the application name, which you define during deployment.
If the constructed name is greater than thirty characters, the name is truncated at twenty-four characters. Then six characters made up of an alphanumeric hash code is appended to the name.
For example, if the EJB name is EmpBean
, the JAR file is empl.jar
, and the application name is employee
, then the default table name is EmpBean_empl_jar_employee
.
Column names—The columns in the entity bean table each have the same name as the <cmp-field>
elements in the designated database. The data types for the database, translating Java data types to database data types, are defined in the specific database XML file, such as oracle.xml
.
Note: Auto-creation of tables in third-party databases may fail for certain data types unless the persistent-type mapping for VARCHAR is defined in theorion-ejb-jar.xml as follows:
|
As "Default Mapping of Persistent Fields to the Database" discusses, your persistent data can be automatically mapped to a database table by the container. However, if the data represented by your bean is more complex or you do not want to accept the defaults that OC4J provides for you, then you can map the persistent data to an existing database table and its columns within the orion-ejb-jar.xml
file. Once the fields are mapped, the container provides the persistence storage of the persistent data to the indicated table and rows.
For explicit mapping, Oracle recommends that you do the following:
Deploy your application with only the ejb-jar.xml
elements configured.
OC4J creates an orion-ejb-jar.xml
file for you with the default mappings in them. It is easier to modify these fields than to create them from scratch. This provides you a method for choosing all or part of the modifications that are discussed in this section.
Modify the <entity-deployment>
element in the orion-ejb-jar.xml
file to use the database table and columns you specify.
Once you define persistent fields, each within its own <cmp-field>
element, you can map each to a specific database table and column. Thus, you can map CMP fields to existing database tables. The mapping occurs with the OC4J-specific deployment descriptor: orion-ejb-jar.xml
.
The explicit mapping of CMP fields is completed within an <entity-deployment>
element. This element contains all mapping for an entity bean. However, the attributes and elements that are specific to CMP field mapping is as follows:
<entity-deployment name="..." location="..." table="..." data-source="...">
<primkey-mapping>
<cmp-field-mapping name="..." persistence-name="..." />
</primkey-mapping>
<cmp-field-mapping name="..." persistence-name="..." />
...
</entity-deployment>
Element or Attribute Name | Description |
---|---|
name
|
Bean name, which is defined in the ejb-jar.xml file in the <ejb-name> element.
|
location
|
JNDI location |
table
|
Database table name |
data-source
|
Data source for the database where the table resides |
primkey-mapping
|
Definition of how the primary key is mapped to the table. |
cmp-field-mapping
|
The name attribute specifies the <cmp-field> in the deployment descriptor, which is mapped to a table column in the persistence-name attribute.
|
You can configure the following within the orion-ejb-jar.xml
file:
Configure the <entity-deployment>
element for every entity bean that contains CMP fields that will be mapped within it.
Configure a <cmp-field-mapping>
element for every field within the bean that is mapped. Each <cmp-field-mapping>
element must contain the name of the field to be persisted.
Configure the primary key in the <primkey-mapping>
element contained within its own <cmp-field-mapping>
element.
Configure simple data types (such as a primitive, simple object, or serializable object) that are mapped to a single field within a single <cmp-field-mapping>
element. The name and database field are fully defined within the element attributes.
Example 4-1 Mapping Persistent Fields to a Specific Database Table
The following example demonstrates how to map persistent data fields in your bean instance to database tables and columns by mapping the employee persistence data fields to the Oracle database table EMP
.
The bean is identified in the <entity-deployment>
name
attribute. The JNDI name for this bean is defined in the location
attribute.
The database table name is defined in the table
attribute. And the database is specified in the data-source
attribute, which should be identical to the <ejb-location>
name of a DataSource
defined in the data-sources.xml
file.
The bean primary key, empNo
, is mapped to the database table column, EMPNO
, within the <primkey-mapping>
element.
The bean persistent data fields, empName
and salary
, are mapped to the database table columns ENAME
and SAL
within the <cmp-field-mapping>
element.
<entity-deployment name="EmpBean" location="emp/EmpBean" wrapper="EmpHome_EntityHomeWrapper2" max-tx-retries="3" table="emp" data-source="jdbc/OracleDS"> <primkey-mapping> <cmp-field-mapping name="empNo" persistence-name="empno" /> </primkey-mapping> <cmp-field-mapping name="empName" persistence-name="ename" /> <cmp-field-mapping name="salary" persistence-name="sal" /> ... </entity-deployment>
After deployment, OC4J maps the element values to the following:
Bean | Database |
---|---|
emp/EmpBean
|
EMP table, located at jdbc/OracleDS in the data-sources.xml file
|
empNo
|
EMPNO column as primary key
|
empName
|
ENAME column
|
salary
|
SAL column
|
Each finder method retrieves one or more objects. In the default scenario (which is set to NO lazy loading), the finder method causes a single SQL select statement to be executed against the database. For a CMP bean, one or more objects are retrieved with all of their CMP fields. So, for example, with the findAllEmployees
method, this finder retrieves all employee objects with all of the CMP fields in each employee object.
If you turn on lazy loading, then only the primary keys of the objects retrieved within the finder are returned. Then, only when you access the object within your implementation, the OC4J container uploads the actual object based on the primary key. With the findAllEmployees
finder method example, all of the employee primary keys are returned in a Collection
. The first time you access one of the employees in the Collection
, OC4J uses the primary key to retrieve the single employee object from the database. You may want to turn on the lazy loading feature if the number of objects that you are retrieving is so large that loading them all into your local cache would be a performance degradation.
You have a performance consideration with lazy loading. If you retrieve multiple objects, but you only use a few of them, then you should turn on lazy loading. In addition, if you only use objects through the getPrimaryKey
method, then you should also turn on lazy loading.
To turn on lazy loading in the findByPrimaryKey
method, set the findByPrimaryKey-lazy-loading
attribute to true, as follows:
<entity-deployment ... findByPrimaryKey-lazy-loading="true" ... >
To turn on lazy loading in any custom finder method, set the lazy-loading attribute to true in the <finder-method>
element for that custom finder, as follows:
<finder-method ... lazy-loading="true" ...> ... </finder-method>
In defining the container-managed persistent fields in the <cmp-field>
and the primary key types, you can define simple data types and Java user classes that are serializable.
The following table provides a list of the supported simple data types, which you can provide in the persistence-type
attribute, with the mapping of these types to SQL types and to Oracle database types. None of these mappings are guaranteed to work on non-Oracle databases.
Table 4-1 Simple Data Types
Known Type (native) | SQL type | Oracle type |
---|---|---|
java.lang.String | VARCHAR(255) | VARCHAR2(255) |
java.lang.Integer[ ] | INTEGER | NUMBER(20,0) |
java.lang.Long[ ] | INTEGER | NUMBER(20,0) |
java.lang.Short[ ] | INTEGER | NUMBER(10,0) |
java.lang.Double[ ] | DOUBLE PRECISION | NUMBER(30,0) |
java.lang.Float[ ] | FLOAT | NUMBER(20,5) |
java.lang.Byte[ ] | SMALLINT | NUMBER(10,0) |
java.lang.Character[ ] | CHAR | CHAR(1) |
java.lang.Boolean[ ] | BIT | NUMBER(1,0) |
java.util.Date | DATETIME | DATE |
java.sql.Date | DATE | DATE |
java.util.Time | DATE | DATE |
java.sql.Timestamp | TIMESTAMP | TIMESTAMP |
java.lang.String | CLOB | CLOB |
char[ ] | CLOB | CLOB |
byte[ ] | BLOB | BLOB |
java.io.Serializable (4KB limit) | LONGVARBINARY | BLOB |
Note: You can modify the mapping of these data types in theconfig/database-schema/<db>.xml XML configuration files.
|
The Date
and Time
map to DATE
in the database, because the DATE
contains the time. The Timestamp
, however, maps to TIMESTAMP
in the database, which gives the time in nanoseconds.
Mapping java.sql.CLOB
and java.sql.BLOB
directly is not currently supported because these objects are not serializable. However you can map a String or char[]
and byte[]
to database column type CLOB and BLOB respectively. Mapping a char[]
to a CLOB or a byte[]
to a BLOB can only be done with an Oracle database. The Oracle JDBC API was modified to handle this operation.
There is a 4 KB limit when mapping a serialized object to a BLOB type over the JDBC Thin driver.
When String and char[]
variables map to a VARCHAR2 in the database, it can only hold up to 2K. However, you can map String object or char[]
larger than 2K to a CLOB by doing the following:
The bean implementation uses the String or char[]
objects.
The persistence-type
attribute of the <cmp-field-mapping>
element defines the object as a CLOB, as follows:
<cmp-field-mapping name="stringdata" persistence-name="stringdata" persistence-type="CLOB" />
In the same manner, you can map a byte[]
in the bean implementation to a BLOB, as follows:
<cmp-field-mapping name="bytedata" persistence-name="bytedata" persistence-type="BLOB" />
In addition to simple data types, you can define user classes that implement Serializable
. These classes are stored in a BLOB in the database.