This material is from the book JBuilder Developer’s Guide , written by Saleem Siddiqui, Michael Landy, and Jeff Swisher, published by Sams Publishing.
© Copyright Sams Publishing. All rights reserved.
Using the EJB 1.1 specifications, container managed persistence beans were
not very powerful. In most cases, bean developers went quickly beyond the
capabilities of CMP and had to convert to use bean managed persistence.
Many developers shied away from using entity beans altogether. The EJB 2.0
quickly addressed many of these issues. This now allows the bean developer
to implement most persistence requirements using container managed persistence.
The four features that facilitate this are the following:
-
EJB query language
-
Finder methods
-
Relationship mapping of multiple entity beans
-
Business methods implemented within the home interface
The Enterprise JavaBeans Query Language
The Enterprise JavaBeans Query Language (EJB QL) specification defines
a query language to be used within finder methods of an entity bean with
container managed persistence. Rather than develop a completely new query
language, the specification is based on a subset of SQL92. The EJB QL gives
you the features to allow navigation over the relationships defined in an
entity bean's abstract schema.
Your EJB QL queries will be contained within your deployment descriptor
of the entity bean. The container will then translate these queries into
the target language of the underlying data store. For example, EJB QL will
be translated to true SQL for JDatastore. Using this translation
allows entity beans using container managed persistence to be portable.
In other words, the code is not tied to a specific type of data store or
application server vendor.
EJB Query Restrictions
EJB QL has a few restrictions:
-
Commenting is not supported within EJB QL.
-
Date and time values are always represented in milliseconds and contained
within a Java long. -
Container managed persistence does not support inheritance. In other
words, you cannot compare two entity beans of different types with each
other.
Query Syntax
An EJB QL query has three components associated with it: SELECT,
FROM, and WHERE. The SELECT and FROM
clauses are the only required portions of EJB QL; the WHERE clause
is optional. For example, SELECT OBJECT(e) FROM Employee e selects
all the instances contained within the Employee entity.
The SELECT component defines the values or objects that will be
returned by the created query. The return values can either be a local interface
or a remote interface contained within an entity. The FROM component
defines the scope of the query. It may declare one or more entities. Finally,
the WHERE component contains a conditional expression that restricts
the values retrieved by the query. As mentioned earlier, this portion of
the query is optional; it is normally required to meet most entity finder
requirements.
Examples Described
SELECT OBJECT(e) FROM Employee e
This method returns all the instances of employee contained within the
entity. In this case, we refer to the Employee entity with an alias
e to make the definition of the query shorter.
SELECT DISTINCT OBJECT(e) FROM Employee e WHERE e.empNo = ?1
The query returns an employee instance specified by an empNo.
This query is typically used to find an instance by either a primary key
or alternate key. The DISTINCT keyword can be used to remove duplicates
from the query but this should not happen if you are using a primary key.
SELECT DISTINCT OBJECT(e) FROM Employee e, IN (e.salaryHistory)
as s WHERE s.Country
= ?1
This query navigates to related beans using the defined relationship. The
e variable relates to the Employee entity bean, and the
s variable represents the related bean instances SalaryHistory.
The IN keyword specifies that SalaryHistory is a collection
of beans related to the Employee entity. The query then navigates
the relationship to identify all the salary histories within a specific
country.
SELECT DISTINCT OBJECT(e) FROM Employee e WHERE e.salary BETWEEN ?1
AND ?2
The employees whose salaries fall within a given range are returned. The
BETWEEN keyword returns all salaries within the given range. This
expression is useful when using range finder methods.
Expressions and Functions
Just like SQL92 specifications of which EJB QL specifications is a subset,
EJB QL describes the functionality of the expressions and functions. The
specification does not include a full list of functions like that of SQL92
but simply a subset that should fit most requirements (see Table 1).
Table 1 Expressions and Functions Contained Within EJB QL
Type |
Description |
Standard comparisons |
Just like SQL, you have the operations =, >, >=, <, <=, |
Arithmetic |
+, -, *, / |
Logical |
NOT, AND, OR |
Between |
The BETWEEN expression determines whether a value falls |
In |
The IN expression determines whether a value is contained |
Like |
The LIKE expression evaluates whether a string matches a |
Null |
The NULL comparison expression evaluates whether an attribute |
EJB QL also includes several functions, both arithmetic and string, listed
in Table 2. Most EJB vendors, including Borland's Application Server,
allow you to define and implement your own custom functions.
Table 2 Functional Expressions
Function Syntax |
Description |
CONCAT(String, String) |
Concatenate two strings together and return into a third. |
SUBSTRING(String, start, length) |
Return a substring based on the start and length passed in. |
LOCATE(String, String [, start]) |
Locate a string within another and return its location. |
LENGTH(String) |
Return the length of a string. |
ABS(number) |
Return the absolute version of the number. |
SQRT(double) |
Return the square root of a number. |
Finder Methods
The ability to find an entity is a key requirement of all entity beans.
The implementation of finder methods, within EJB specification 1.1, required
us to quickly move to bean managed persistence rather than use the simpler
container managed persistence beans. Using EJB QL in conjunction with finder
methods within a container managed persistent bean, you can meet most requirements
for finding an individual or collection of entities.
We'll continue to look at our Employee entity and add a more
complex finder other than findByPrimaryKey(). The requirement we
need to implement is the capability to find employees based on a salary
range. The following steps are required to build this finder method implementation:
-
Right-click on the Employee entity and choose Add, Finder.
The results of which display the finder editor. -
Add the finder properties required to accomplish the given task.
-
Set the following properties (see Figure
1): -
Method name: findBySalaryRange
-
Return type: java.util.Collection
-
Input parameters: int low, int high
-
Home interface: local home
-
Query: SELECT OBJECT(e) FROM Employee e WHERE e.Salary BETWEEN
?1 AND ?2 -
Save and compile your project.
Figure 1
Finder editor within the EJB Designer.
The deployment descriptor now contains the information for this finder
method (see Listing 1). When the bean is deployed to the container,
it translates the information contained within the deployment descriptor
EJB QL to standard SQL for JDatastore.
Listing 1 Portion of the Deployment Descriptor for Defining a Finder
Method with EJB QL
<query> <query-method> <method-name>findBySalaryRange</method-name> <method-params> <method-param>int</method-param> <method-param>int</method-param> </method-params> </query-method> <ejb-ql>SELECT OBJECT(e) FROM Employee e WHERE e.Salary BETWEEN ?1 AND ?2</ejb-ql> </query>
Relationship Mapping
As stated earlier the introduction of relationships in EJB 2.0 specifications
makes a huge difference. These relationship mappings allow for not only
providing the mechanics for managing relationships, but also the capability
to model and implement complex business relationships with unidirectional
and bidirectional traversal.
Each entity bean typically is not isolated in itself; it relates to other
entities within our system. For example, the Employee entity we
have been working with relates to many other entities within our system
such as the salary history. To demonstrate relationships, we will start
with one-to-many and move to more complex relationships, such as many-to-many.
One-to-Many Relationships
We can use a simple example for a one-to-many relationship. Using the sample
database provided with JBuilder, each employee has a lengthy salary history
that we want to make available through the instance (see Figure
2).
Figure 2
Model of employee to salary history.
The process for creating this one-to-many relationship within JBuilder
is accomplished by using the EJB Designer. The relationship ultimately
is exposed via a local interface defined on the Employee entity
bean. Ultimately, you would access this local interface by way of a session
façade bean, but to make the example simple, we will use the remote
interface with a test client.
-
Expand the EmployeeData source and verify that the SALARY_HISTORY
table is contained within the source's definition. -
Right-click on the SALARY_HISTORY table and select Create
Entity Bean. The bean then appears in the EJB Designer. Make sure
that the version property is set to EJB 2.0 compliant. -
Creating an EJB relationship is accomplished by right-clicking on
the parent entity. In this class, right-click on our Employee
entity and select Add, Relationship. An arrow used to graphically
represent our relationship appears within the EJB Designer. -
Drag the end of the relationship arrow onto the SalaryHistory
entity. -
Select the newly created method that contains the relationship. The
name assigned by JBuilder's EJB Designer is salaryHistory. -
The Relationship Property editor appears to allow you to change the
behavior of the relationship (see Figure
3). -
For the relationship properties, Multiplicity should be set to one-to-many,
and Navigability should be set to unidirectional. The Navigability
is set to unidirectional because it does not make sense to access
Employee entity information through the SalaryHistory
entity. -
Click on the Edit Table Reference button to open the Table Reference
editor (see Figure 4). We will
use this editor to provide the link/keys between the two entities. -
Adding a relationship is important because it indicates all the important
keys that define the relationship between parent and child entities.
Double-click on the empNo in the Employee entity
and drag it onto the empNo of the SalaryHistory
entity. Click OK. -
You should have a new attribute that contains the relationship between
the Employee and the employee's salary history. Using
the property editor, shown in Figure
3, make sure that the return type of the salaryHistory
method within the Employee entity is java.util.Collection.
Figure 3
Relationship Property editor for the Employee to SalaryHistory
relationship.
Figure 4
Table Reference editor for the Employee to SalaryHistory
relationship.
Many-to-Many Relationships
A many-to-many relationship appears frequently in relationship database
designs. It is usually implemented through the use of a resolution table
because most relational database servers do not support this many-to-many
relationship directly, although object modeling supports this relationship
well. Although we can create this same resolution entity within our container,
why not implement a many-to-many relationship that more accurately represents
our actual instances?
For example, our employee system contains a many-to-many relationship
implemented through a resolution table (see Figure
5).
Figure 5
Employee relational data model.
Let's now create a many-to-many relationship using the existing
employeeData source. The relationship will be exposed via local
interfaces of the Employee and Project entity beans.
To access these interfaces, we will use the local interfaces of the
beans created. The following tasks help us create the required relationships
and deployment descriptor for these entity beans:
-
Right-click on the PROJECT table within the defined data
module within the EJB Designer and select Create CMP 2.0 Entity
Bean. -
Create the many-to-many relationship between the Employee
and Project entity beans using the EJB Designer. This is
accomplished by right-clicking on the Employee bean and
selecting Add, Relationship; then drop the other end of the relationship
on the Project entity. -
Select the newly created relationship entity called Project,
and the relationship editor is created (see Figure
6): -
Relationship name: employee-project
-
Multiplicity: many to many
-
Navigability: bidirectional
-
Field name: project
-
Return type: java.util.Collection
-
Getters/setters: local
-
Click on Edit Table Reference; this launches the Table Reference
editor. -
Click on Add Cross Table (see Figure
7). After you make the appropriate selections, the Add Cross
Table button becomes available. -
Select the EMPLOYEE_PROJECT table as the cross table (see
Figure 8). -
Drag EMPLOYEE EMP_NO to the EMPLOYEE_PROJECT EMP_NO
and drag EMPLOYEE_PROJECT PROJ_ID to PROJECT PROJ_ID
(see Figure 9). -
Click OK and compile and save your project.
Figure 6
Relationship editor for a many-to-many relationship.
Figure 7
Table Reference editor to establish a many-to-many relationship.
Figure 8
Table Reference editor to establish a many-to-many relationship using
a cross table.
Figure 9
Build the relationship between the resolution table and the Employee
and Project tables with the connected keys.
Home Business Methods
One of the new changes for the specification is the addition and support
for collection methods and business methods contained within the home
interface. For example, we might want to calculate the total current
salary of all employees. The process for building this is simple:
-
Add a new method to the Employee entity bean calling it
calculateTotalSalary. -
Enter the return type to be a java.math.BigDecimal
and the target interface should be local home. -
Create another finder method with the following parameters:
-
Finder name: findAll
-
Return type: java.util.Collection
-
Parameter: leave empty
-
Method interface: local home
-
Query: SELECT OBJECT(e) FROM Employee AS e
-
Create a select method with the following properties:
-
Select name: selectAll
-
Return type: java.util.Collection
-
Parameter: leave empty
-
Result type mapping: local
-
Query: SELECT OBJECT(e) FROM Employee AS e
-
Most of the code for the Employee entity has been generated
by the EJB Wizard. The piece we need to add is the implementation
of CalculateTotalSalary. -
Locate the EmployeeBean class and double-click to view
the source. -
Locate the ejbHomeCalculateTotalSalary() method in the
class. -
Implement the method as follows:
public java.math.BigDecimal ejbHomeCalculateTotalSalary() { float res = 0; try { java.util.Iterator iter = ejbSelectAll().iterator(); while(iter.hasNext()){ Employee emp = (Employee)iter.next(); res = res + emp.getSalary().floatValue(); } } catch (FinderException ex) { throw new javax.ejb.EJBException(ex); } return new java.math.BigDecimal(new Float(res).toString()); }
About the Authors
Saleem Siddiqui is a technical architect and trainer with Dunn Solutions Group. He is also a Sun Certified Developer and a Borland Certified JBuilder Instructor. At Dunn, he provides consulting services and business application development.
Michael Landy is Director of Business Applications for Dunn Solutions Group directing the strategic solutions for clients.
Jeff Swisher is a technical manager for the Dunn Solutions Group business applications. He works as a programmer, trainer, architect, and instructional designer. He is a Sun Certified Java Developer and a Borland Certified Instructor in JBuilder.
Source of this material
This material is from Chapter 23: Developing Entity Beans from the book JBuilder Developer’s Guide (ISBN: 0-672-32427-X) written by Saleem Siddiqui, Michael Landy, and Jeff Swisher, published by Sams Publishing. |
To access the full Table of Contents for the book.
Other Chapters from Sams Publishing:
The Java Database Control in BEA Weblogic