This chapter describes the type of Enterprise Java Bean called entity bean. It specifically includes these sections:
An entity bean is a server-side class that represents an object in an underlying data store. You can think of an entity bean class as a representation of a database table and each instance of the entity bean class as a single row of that table. Entity beans can also represent complex relationships among one or more related tables or components of a non-relational data store like SAP, PeopleSoft, or Lotus Notes.
SilverStream's Version 3.0 container managed persistence requires that the underlying data store be a relational database, and not some other type of data store, so this chapter focuses on EJBs used in this way.
Entity bean access
Entity beans deployed on the SilverStream Server can be accessed by:
Entity beans deployed on the SilverStream Server can access:
Entity beans running on a server can locate and call other entity or session beans on the same or different SilverStream Server.
Entity bean components
Entity beans include the following components:
About the javax.ejb.EntityBean interface
The javax.ejb.EntityBean interface includes the methods listed below. They are used by the container to manage the bean, to synchronize the bean with its underlying data store, and to provide information to the bean about its current environment.
For more information about these methods, see the Java2 Enterprise APIs in the online API Reference.
Since entity beans are representations of an underlying data store, the data contained in the entity instances must be synchronized with the data in the row that they represent. This process of synchronization is known as persistence.
You might think of persistence as the following database-related tasks:
Since an entity bean is a representation of the row in the underlying data store, persistence also includes the following tasks:
The mechanism to provide persistence can be explicitly programmed in the entity bean; this is known as bean-managed persistence. The mechanism to provide persistence can also be implicit or declarative; this is known as container-managed persistence.
About the methods that manage persistence
The javax.ejb.EntityBean interface includes two methods that are used for persistence management. They are:
Gets the data from the database into the bean's persistent fields.
Puts the data from the bean's persistent fields into the database.
In entity beans with container-managed persistence (referred to as CMP beans), since the container manages the data, you can leave these methods empty. If the data needs to be manipulated before it is stored in the database or after the bean is populated, you can write an implementation for either method. See the section on Extending container-managed persistence for more information.
With BMP entity beans, the bean-writer must write method implementations for both ejbLoad() and ejbStore().
With CMP beans, the container handles all of the database connection and data access functions. The bean writer specifies, in the deployment descriptor, which of the entity bean's persistent fields the container should manage. At deployment time, the deployer maps the entity bean to a database table in the underlying data store and maps the bean's persistent fields to columns in that table. The deployer also maps any finder methods to a SilverStream expression. (You can think of this mapping as specifying the Where clause of a SQL Select statement.) The container uses these mappings to generate the appropriate JDBC and SQL calls.
You might want to use CMP, because:
When you use CMP, the SilverStream container generates the database calls appropriate to the connected database. When you use BMP, you write the JDBC calls directly against the database to retrieve and update the bean's database fields. Since this code is in the bean, any changes would require modifications and recompilation of the bean.
In CMP, SilverStream generates the optimized database access code at deployment time. If changes are required in a CMP bean, the deployer simply remaps and redeploys the bean. The generated code is modified, not the bean code.
In CMP, you do not have to write any database access or transaction-related code because you can rely on the container to do it.
You might not use CMP, because:
In bean-managed persistence, everything is programmatic. The bean writer writes all of the necessary code to connect to the underlying data store, to create, delete, and update the records in the underlying data store and to synchronize the entity bean's persistent fields with the underlying data store. Unlike CMP, where the container generates all of this code at deployment time, the bean-writer must include this code directly in the entity bean.
Although it is more work, you might use BMP when:
You might not use BMP because:
Modifying the persistence model
You can modify the behavior of both the BMP and the CMP models using SilverStream. The SilverStream container provides the flexibility to use certain SilverStream features as appropriate to your application. For example, if you choose BMP, you can use AgaDatas to access your data instead of JDBC. If you choose CMP, you can write code in the ejbLoad() or ejbStore() to manage some field mappings that cannot be specified in a declarative way.
For more information on these techniques, see the section
Extending container-managed persistence.
Since entity beans represent rows in the underlying data store, you need to think about them in a different way than session beans. If a session bean does not exist, you instantiate one by calling its create() method. If you call a create method on an entity bean, you actually create a record in the underlying data store; calling remove() actually deletes the underlying record. This section describes the lifecycle of entity beans and the methods used to manage them. It includes the following sections:
Entity beans are located using "finder methods". Finder methods represent SQL Select statements. Finder methods can return the remote object reference of a single bean, or a Collection or Enumeration of remote object references. Every entity bean must define at least the findByPrimaryKey() method.
A findByPrimaryKey() operation on a CMP bean (with a transaction in progress) executes as follows:
Bean's are lazy when the delay instantiation property is set to true in SilverStream's deployment. See Deploying EJBs for a complete description of the delay instantiation property.
The bean's ejbLoad() method is not called until the client calls additional business methods. This is true for both lazy and non-lazy beans.
Entity bean instances are created by calling the create() method on the EJBHome and passing enough information about the entity to construct the database row. CMP entity beans are created as follows:
It must pass in enough information for a database record to be created (for example, it must include all required values which are not default values).
Instance pooling
SilverStream (Version 3.0) does not maintain a pool of idle/unused entity beans. Instead it instantiates the beans as requested. Some EJB servers might maintain such a pool to reduce the costs associated with instantiating entity beans; however, because most of the cost of activating an entity bean is in the ejbLoad() operation, which has to be done whether or not the bean is pooled, the only saving from pooling beans is in reducing memory allocation. Given the total amount of memory allocation in every Java remote call, this is insignificant.
Entity bean instances are removed by calling the remove() method on the EJBObject. CMP entity beans are removed as follows:
Entity beans are updated by changing the value of one or more persistent fields and synchronizing the change with the data store. CMP entity beans are updated as follows (this assumes that you have already done a findByPrimaryKey()):
For CMP entity beans, each time that you call a method, the SilverStream client compares the value in each persistent field of the bean with the value in a cached version of the record. (This cached version resides on the server.) If the values are different, the update sequence is performed. If the values are not different, no updates are performed. This comparison can be costly. At deployment, you can specify the methods that do not modify fields. This allows the container to avoid this comparison.
For more information, see the chapter on deploying EJBs.
BMPs and ejbStore()
For BMP entity beans, each time that you call a method, the container calls the bean's ejbStore() method. It does this because the container cannot make any assumptions about what methods do or do not update the data. As a result, the code in the ejbStore() method can be called more frequently than you might expect. Since calls to the database can have a high performance cost, you should carefully consider how to structure your code.
One technique is to set a flag that indicates whether or not a database update is actually needed. If the update is not needed (because the method did not change any data), you can skip the database access. You can see an example of this in the bean managed entity bean example in the Examples3_EJB database.
Entity bean transactions are declarative and are managed by the container. Entity beans cannot:
Entity bean transactions are always global. A global transaction is one that uses the Java Transaction API (defined in the javax.transaction.UserTransaction package).
Here's how SilverStream manages an entity bean's transaction participation.
If you are familiar with the way SilverStream transactions work, this model is slightly different.
To improve performance, consider making any calls to an entity bean within a transaction context, even if the bean does not require a commit or a rollback. This strategy can limit the reads done on the database.
One way to implement this strategy is to write a session bean that uses bean-demarcated transactions. The session bean can then be used to wrap any entity bean calls within the scope of a javax.transaction.UserTransaction.
Here's how it works when you call a method outside of a transaction:
Here's how it works when you wrap the method calls in a transaction, and set the delay instantiation radio button to false (non-lazy):
You can see the results of this type of this strategy by running the BankDemo located in the Examples3_EJB database. For an explanation of the code, see the EJB section of the online Application Techniques.
You can use the SilverStream IDE to develop and deploy your entity beans, or you can use a third-party IDE to develop the bean, import it into the SilverStream environment and deploy it.
For information about developing SilverStream objects using a third-party IDE, see
Writing External Java Clients.
When you begin your development efforts, you need to decide the following before you start:
Development tasks
To develop an entity bean, you need to:
Deployment tasks
If you have used SilverStream to develop the bean, it's already available to the server. If you developed the bean in a different IDE, then you install it on the server by importing it.
For more information on each of the steps in the deployment cycle, see the chapter on deploying EJBs.
The primary key class typically contains fields that correspond to the primary key columns of the database table that the entity bean represents.
The null constructor allows the home object to create primary key objects as it needs them.
The fields in the primary key class representing the database key must be public so that they are available to the home object (for CMP beans only).
For more examples of primary key classes, see the Examples3_EJB database.
Writing the entity bean's Java class is like developing any standard Java class. Here are the guidelines for the entity bean class:
For information about using the SilverStream IDE to write the entity bean class, see the chapter on the Business Object Designer in the online Tools Guide.
For examples illustrating how to write an entity bean, see the EJB section in the online Application Techniques Guide.
Getting the entity context
One of the container methods that you will generally write code for is the setEntityContext() method. This method is called by the container in the early stages of the beans lifecycle. It is called after creating the instance, but before calling the bean's create() method.
The container calls it so that it can pass information about the current context to the entity bean. All you need to do is save this context in a member variable so that way it is available if you need it later.
First create a member variable like this:
protected EntityContext m_context;
Then, in the setEntityContext() method, save it as shown here:
m_context = entityContext1;
This section describes how to write the implementation of the ejbCreate() method. If you use the standard CMP features, you do not need to write a body for the ejbStore() and the ejbLoad() methods for a bean with container-managed persistence.
In CMP, SilverStream calls ejbLoad() the very first time a business method is invoked. It calls ejbStore() when it submits the changes to the database.
Writing a CMP ejbCreate() method
You do not have to write any ejbCreate() methods in your bean. You only need to write one if your application needs to add records to the database. The ejbCreate() should return null.
The following example shows an ejbCreate method for the EBCompanyBean.
public EBCompanyPrimaryKey ejbCreate(String psCompanyID,
String psCompanyName) throws CreateException, RemoteException
{
m_companyid = psCompanyID;
m_companyname = psCompanyName;
return null;
}
About CMP Finder methods
If the bean uses CMP, then finder methods are:
For more information on mapping CMP Finder methods, see the chapter on the JAR Designer in the online Tools Guide.
To write an entity bean that uses bean managed persistence, you need to write the implementation of the ejbCreate(), the ejbStore() and the ejbLoad() methods. You also need to write finder methods.
For information on writing a bean with BMP, see the Examples3_EJB database and the online Application Techniques guide.
Writing BMP Finder methods
The finder methods represent a way to request an existing row. You can represent that row in many different ways by writing many different finder methods. For example, you might find a customer by last name, by first name, by customer id, by zip code, by country or region. Each of these can be represented by a Finder method.
There is no limit to the number of finder methods that you can define for a single bean class.
If the bean uses BMP, then finder methods are:
Here are the rules for writing finder methods:
The remote interface makes the bean's business methods available to clients. Like the home interface, you do not need to write the code that implements this interface. Instead, at deployment time, the container generates a class that implements this interface. The container then uses this class to respond to business method calls from clients.
Here are the requirements for the remote interface:
For more information about the methods on the remote interface, see the Java2 Enterprise APIs in the online API Reference.
The home interface makes the bean's create and finder methods available to clients. It extends the javax.ejb.EJBHome interface. At deployment time, the container takes this interface and generates a class. The container then uses this class as the factory for creating all instances of the session bean.
For entity beans, every home interface must include a findByPrimaryKey() method.
Here are the requirements for writing the bean's home interface.
For more information about the methods on the home interface, see the Java2 Enterprise APIs in the online API Reference.
You might find that you want to use container-managed persistence for your entity bean, but have some situations where the container is not able to map directly to the target environment. You might have one of the following scenarios:
For these situations, you can still use container-managed persistence by adding some extensions. This allows you to use a combination of CMP and BMP which uses the best features of both persistence models.
Suppose that you have a database field. Its declaration is as a single byte character field. It denotes the customer's gender and can have the value M or F. The EJB implementation you are using requires a boolean member variable m_female. To ensure the correct data conversion, you create a dummy member variable; it is a character and is called m_dbGender. You can use CMP to map the m_dbGender to the database field.
In the ejbLoad() method, you need to write the code to populate the member variable, like this:
m_female = (m_dbGender == `F');
In the ejbStore() method, you need to write the code to populate the database, like this:
m_dbGender =(m_female ?'F':'M');
To overcome the limitation when the bean's container-managed fields do not map directly to database fields, follow this strategy:
You can use this technique for any type of data translation or massaging, including evaluations in/out field expressions, and one-to-many bean references and data aggregation.
In many cases your finder methods in CMP can be expressed as WHERE clauses using the SilverStream Expression Builder tool. Some finder methods cannot be expressed as a simple where clause, typically because:
For any of these cases, you can write your own finder method to perform the complex logic. At deployment time, the finder method should be marked method-style instead of expression. You can write the finder method directly in the bean class, or implement it in a subclass of the bean.
For more information on subclassing beans, see the JAR Designer chapter of the online Tools Guide.
Method-style finder requirements
Regardless of where you implement the method, these are the steps you should follow to write the method-style finder.
The following code snippet illustrates this technique:
public Collection ejbFindByEmployee(EmployeeRemoteI emp)
throws FinderException, RemoteException
{
// Get the employee ID
EmployeePK epk = (EmployeePK) emp.getPrimaryKey();
// Construct the where clause
String where = "Tasks.TaskEmpID=" + epk.m_id;
// Get the EJB home object
AgoEJBEntityHome home = (AgoEJBEntityHome)
m_context.getEJBHome();
// Call the findByExpression method to perform the actual query
(Collection) home.findByExpression(where, null,
home.FIND_COLLECTION, false,0)
}
For more information on writing a SilverStream query, see
Using SilverStream Expressions.
For more information on marking Finder methods as method-style, see the
Deploying EJBs.
How CMP method-style finders differ from BMP finders
The method-style finders that you write to provide complex logic for container-managed beans are different from the Finder methods that you write for BMP beans in the following ways:
In a modified-CMP finder, you must:
The findByExpression() method provides additional built-in capabilities such as:
You can write complex finder methods or perform data translation for container-managed beans even if you do not have their Java source by using this strategy:
For more information on subclassing a bean, see the chapter on the Jar Designer in the online Tools Guide. Keep in mind that subclassing a bean using the JAR Designer:
It does not automatically handle unmappable fields.