Oracle8i Enterprise JavaBeans Developer's Guide and Reference Release 3 (8.1.7) Part Number A83725-01 |
Library | Service | Contents | Index

## Difference Between Bean-Managed and Container-Managed Beans

There are two methods for managing the persistent data within an entity bean: bean-managed and container-managed persistence. The main difference between bean-managed and container-managed persistent beans is defined by who manages the persistence of the entity bean's data.

In practical terms, the following table provides a definition for both types and a summary of the programmatic and declarative differences between them:

| Bean-Managed Persistence | Container-Managed Persistence
--- | --- | ---
Persistence management | You are required to implement the persistence management within the `ejbStore` and `ejbLoad` `EntityBean` methods. These methods must contain logic for saving and restoring the persistent data. For example, the `ejbStore` method must have logic in it to store the entity bean's data to the appropriate database. If it does not, the data can be lost. See "3. Implementing EntityBean Interface Methods" for an example of implementing bean-managed persistence. | The management of the persistent data is done for you. That is, the container invokes a persistence manager on behalf of your bean. You use `ejbStore` and `ejbLoad` for preparing the data before the commit or for manipulating the data after it is refreshed from the database. The container always invokes the `ejbStore` method right before the commit. In addition, it always invokes the `ejbLoad` method right after reinstating CMP data from the database.
Finder methods allowed | The `findByPrimaryKey` method and any other finder method you wish to implement are allowed. | Only the `findByPrimaryKey` method and a finder method for the where clause are allowed.
Defining CMP fields | N/A | Required within the EJB deployment descriptor. The primary key must also be declared as a CMP field.
Mapping CMP fields to resource destination. | N/A | Required. Dependent on persistence manager.
Definition of persistence manager. | N/A | Required within the Oracle-specific deployment descriptor. See the next section for a description of a persistence manager.

### Container-Managed Persistence

You can choose to have the container manage your persistent data for the bean. You have less to develop and manage, as the container stores and reloads your persistent data to and from the database.

When you use container-managed persistence, the container invokes a persistence manager class that provides the persistence management business logic. For this release, the only supported persistence manager is Oracle Persistence Service Interface Reference Implementation (PSI-RI).

To enable the container to manage your persistent data, you need to perform the following:

1. Modify the appropriate bean class callback methods

2. Define the primary key

3. Declare the container-managed persistent fields within the deployment descriptor

4. Declare the persistence manager class

5. Map container-managed persistent fields to a database

#### Modify Bean Class Callback Methods

If you do not want to manage your persistent data, choose to have your bean managed by the container. This means that you do not have to implement some of the callback methods as the container and the persistence manager performs the persistence and primary key management for you. The container will still call these methods--so you can add logic for other purposes. You still must provide at least an empty implementation for all callback methods.

The following table details the implementation requirements for the bean class' callback functions:

Callback Method | Functionality Required
--- | ---
`ejbCreate` | The same functionality as bean-managed persistent beans. You must initialize all container-managed persistent fields, including the primary key.
`ejbPostCreate` | The same functionality as bean-managed persistent beans. You have the option to provide any other initialization, which can involve the entity context.
`ejbRemove` | No functionality for removing the persistent data from the outside resource is required. The persistent manager removes all persistent data associated with the entity bean from the database. You must at least provide an empty implementation for the callback, which means that you can add logic for performing any cleanup functionality you require.
`ejbFindByPrimaryKey` | No functionality is required for returning the primary key to the container. The container manages the primary key--after it is initialized by the `ejbCreate` method. Thus, the container performs the functionality normally required of this method. You still must provide an empty implementation for this method.
`ejbStore` | No functionaltiy is required for saving persistent data within this method. The persistent manager saves all persistent data to the database for you. However, you must provide at least an empty implementation as the container invokes the `ejbStore` method before invoking the persistent manager. This enables you to perform any data management or cleanup before the persistent data is saved.
`ejbLoad` | No functionality is required for restoring persistent data within this method. The persistence manager restores all persistent data for you. However, you must provide at least an empty implementation as the container invokes the `ejbLoad` method after invoking the persistent manager. This enables you to perform any logic to manipulate the persistent data after it is restored to the bean.
`setEntityContext` | Associates the bean instance with context information. The container calls this method after the bean creation. The enterprise bean can store the reference to the context object in an instance variable, for use in transaction management. Beans that manage their own transactions can use the session context to get the transaction context. You can also allocate any resources that will exist for the lifetime of the bean within this method. You should release these resources in `unsetEntityContext`.
`unsetEntityContext` | Unset the associated entity context and release any resources allocated in `setEntityContext`.

##### A Finder Method for the Where Clause

Oracle enables you to perform a SQL query against the persistent data table through a CMP-only finder method with a `find<`name`>` naming syntax. This method takes a String that denotes the "`where`" clause of a SQL query. Thus, the String would include the entire statement except for the "`select` * `from` `<table"`. If you supply an empty string, all values are selected from this table.

You must define any such finder method within the Home interface. The container will provide the implementation for satisfying the where clause for the finder method.

For example, the following defines finder methods within the home interface, where one retrieves all customers and the other retrieves a single customer. Notice how the `findAllCustomers` method, which retrieves all customers in the table, returns an `Enumeration`.

Note: Normally, the return type for multiple items in a finder method would be a `Collection`. However, `Collection` is not supported in this release. You must use the `Enumeration` type to receive multiple items from any finder method.

    public Customer findByWhere(String whereString)

    	throws RemoteException, FinderException;

    public java.util.Enumeration findMultipleCustomers(String whereString)

    	throws RemoteException, FinderException;

If you want to retrieve a single customer, provide the name, the SQL would be constructed as follows:

    select * from customer where name = "Smith, John";

The `findbyWhere` finder method would include the entire statement except for the "`select * from customer`". It assumes that you want to select against the persistence table, as follows:

    Customer find_customer = findByWhere ("where name = ", + custname);

If you want to select a few rows from employee based upon a certain condition, the SQL would be constructed as follows:

    select * from customer where item_bought = treadmill order by name;

The `find<`name`>` method, which in this example is findByWhere, would include the entire statement except for the "`select` * `from` `employee`". It assumes that you want to select all matches against the persistence table. This is demonstrated below:

    Enumeration customer_list = findMultipleCustomers(

    	"where item_bought = treadmill order by name");

Or, if you wanted a full customer listing, provide an empty string. The container will invoke a "`select` * `from` `customer`" and retrieve all records.

    Enumeration customer_list = findMultipleCustomers();

#### Define Your Primary Key

The main difference between defining a bean-managed and container-managed persistent primary key is that the fields within the key must be declared as container-managed persistent fields in the deployment descriptor. All fields within the primary key are restricted to be either primitive, serializable, and types that can be mapped to SQL types. See "Persistence Fields" for more information.

You can define your primary key in one of two ways:

- Defining A Single Object as your Primary Key

- Defining a Complex Primary Key Class

##### Defining A Single Object as your Primary Key

Define your primary key as a container-managed persistent field and its type within the deployment descriptor. The following shows the primary key, `custid`, declared as a `<cmp-field>` and `<primkey-field>` and its type declared within the `<prim-key-class>`:

    <enterprise-beans>
      <entity>
          <description>customer bean</description>
          <ejb-name>/test/customer</ejb-name>
          <home>customer.CustomerHome</home>
          <remote>customer.Customer</remote>
          <ejb-class>customerServer.CustomerBean</ejb-class>
          <persistence-type>Container</persistence-type>
          <prim-key-class>java.lang.String</prim-key-class>
          <primkey-field>custid</primkey-field>
          <reentrant>False</reentrant>
          <cmp-field><field-name>custid</field-name></cmp-field>
          <cmp-field><field-name>name</field-name></cmp-field>
          <cmp-field><field-name>addr</field-name></cmp-field>
      </entity>
    </enterprise-beans>

The primary key variable declared within the bean class must be declared as `public`.

This should be a Java type that can be mapped to a SQL type through SQLJ. Also, this object must be serializable. See "Entity Bean Elements" for a full description.

##### Defining a Complex Primary Key Class

If your primary key is more complex than a simple data type, you define the fields that make up the primary key as container-managed fields within the deployment descriptor. Then, you declare these fields as the primary key within a class. This class must be serializable. Also, all primary key variables declared within the bean class must be types that can be mapped to SQL types.

Within the bean class, the primary key variables must be declared as `public`. Also, you must provide a constructor with no arguments for creating an empty primary key instance.

Within the serializable primary key class, you implement the `equals` and `hashCode` methods to provide for an implementation specific to this primary key.

The following example is a cruise ship cabin bean primary key that identifies each cabin with ship name, deck name, and cabin number.

    package cruise;

    public class CabinPK implements java.io.Serializable
    {
    //Ship names { Castaway, LightFantastic, FantasyRide }
      public String ship;

    //Deck names { Upper Promendade, Promenade, Lower Promenade, Main Deck,
                     Lower Deck }
      public String deck;

      //Cabin numbers A100-N300
      public String cabin;

      //empty constructor
      public CabinPK ( ) { }

      public boolean equals(Object obj) {
        if ((obj instanceof CabinPK) &&
            (((CabinPK)obj).ship == this.ship) &&
             (((CabinPK)obj).deck == this.deck) &&
             (((CabinPK)obj).cabin == this.cabin))
          return true;
        return false;
      }

      public int hashCode() {
        return ((ship + deck + cabin).hash);
      }

The class that defines the primary key is declared within the XML deployment descriptor, as follows:

    <enterprise-beans>
          <entity>
             <ejb-name>CabinBean</ejb-name>
             <home>cruise.CabinHome</home>
             <remote>cruise.Cabin</remote>
             <ejb-class>cruiseServer.CabinBean</ejb-class>
             <persistence-type>Container</persistence-type>
             <prim-key-class>cruise.CabinPK</prim-key-class>
             <reentrant>False</reentrant>
             <cmp-field><field-name>deck</field-name></cmp-field>
             <cmp-field><field-name>cabin</field-name></cmp-field>
    ...
    </enterprise-beans>

See "Entity Bean Elements" for a full description of the deployment descriptor definition.

##### Manage the Primary Key

You must initialize all CMP fields, including the primary key, within the `ejbCreate` method. The `ejbCreate` method for the purchase order example initializes the primary key, `ponumber`, to the next available number in the purchase order number sequence.

    // The create methods takes care of generating a new PO and returns
    // its primary key
    public String ejbCreate () throws CreateException, RemoteException
    {
      String ponumber = null;
      try {
        //retrieve the next available purchase order number
        #sql { select ponumber.nextval into :ponumber from dual };
        //assign this number as this instance's identification number
        #sql { insert into pos (ponumber, status) values (:ponumber, 'OPEN') };
      } catch (SQLException e) {
        throw new PurchaseException (this, "create", e);
      }
      return ponumber;
    }

#### Declare Persistence Fields

All container-managed persistent fields must be declared as `public` within your bean class. They cannot be transient. In addition, these fields are restricted to be either primitive, serializable, and types that can be mapped to SQL types. See Table A-2, "Unsupported Java Types for Persistent Variables" for more information.

#### Declare Persistence Provider

The container invokes a persistence provider for managing your CMP bean. This release supports Oracle Persistence Service Interface Reference Implementation (PSI-RI). For more information on defining the provider, see "Defining Container-Managed Persistence" for a full description.

Note: Make sure that the class that contains the persistence manager is loaded within the database.

The following shows the portion of the Oracle-specific deployment descriptor that defines the persistence manager:

    ...
    <persistence-provider>
      <description> specifies a type of persistence manager </description>
      <persistence-name>psi-ri</persistence-name>
      <persistence-deployer>oracle.aurora.ejb.persistence.ocmp.OcmpEntityDeployer</p
    ersistence-deployer>
    </persistence-provider>

    <persistence-descriptor>
      <description> This specifies a particular type of persistence manager to be us
    ed for a bean.  param is where you would put bean specific persistence info in t
    he format of params.  The deployment process just passes what's in the param to
    the persistence deployer.  For the baby persistence, we do parse the persistence
    -mapping but for other persistence backend we don't do anything with the params
     </description>
      <ejb-name>customerbean</ejb-name>
      <persistence-name>psi-ri</persistence-name>
      <psi-ri>
          <schema>SCOTT</schema>
          <table>customers</table>
          <attr-mapping>
            <field-name>custid</field-name>
            <column-name>cust_id</column-name>
          </attr-mapping>
          <attr-mapping>
            <field-name>name</field-name>
            <column-name>cust_name</column-name>
          </attr-mapping>
          <attr-mapping>
            <field-name>addr</field-name>
            <column-name>cust_addr</column-name>
          </attr-mapping>
      </psi-ri>
    </persistence-descriptor>
    </oracle-descriptor>

#### Map Container-Managed Persistence Fields

All CMP data fields defined within your bean must be declared within the deployment descriptor in the `<cmp-field>` element. See "Entity Bean Elements" for a full description. In addition, you must map these fields to the intended database table and respective columns. See "Persistence Fields" for more information.

The following is a portion of the Oracle-specific deployment descriptor, which maps the primary key and any container-managed persistence fields from the customer example (with the single primary key field) to the database table and column that the persistence provider stores the values for these fields within. Specifically, the container-manager stores the persistent fields into the customers table in SCOTT's schema. The persistent fields are mapped as follows:

Persistent Field | Table Column
--- | ---
custid (primary key) | cust_id column in the customers table
name | cust_name column in the customers table
addr | cust_addr column in the customers table

    <psi-ri>
          <schema>SCOTT</schema>
          <table>customers</table>
          <attr-mapping>
            <field-name>custid</field-name>
            <column-name>cust_id</column-name>
          </attr-mapping>
          <attr-mapping>
            <field-name>name</field-name>
            <column-name>cust_name</column-name>
          </attr-mapping>
          <attr-mapping>
            <field-name>addr</field-name>
            <column-name>cust_addr</column-name>
          </attr-mapping>
    </psi-ri>

| Copyright © 1996-2000, Oracle Corporation. All Rights Reserved. |
Library | Service | Contents | Index