Find
methods have
been a part of the Enterprise JavaBeans specification since EJB 1.0.
These methods are defined on the entity bean’s home
interfaces and are used for locating entity beans. All home
interfaces must have a findByPrimaryKey( )
method, which takes the primary key of
the entity bean as an argument and returns a remote or local
reference to that entity bean. For example, the Cruise EJB defines
this find method in its home interface as:
public CruiseHomeLocal extends javax.ejb.EJBLocalHome {
public Integer create(String name,ShipLocal ship)
throws CreateException;
public CruiseLocal findByPrimaryKey(Integer key)
throws FinderException;
}
In addition to the mandatory findByPrimaryKey( )
method, home interfaces can define as many custom
find
methods as needed. For example, the Cruise EJB might define a method
called findByName( )
for locating a Cruise with a
specific name:
public CruiseHomeLocal extends javax.ejb.EJBLocalHome { public Integer create(String name,ShipLocal ship) throws CreateException; public CruiseLocal findByPrimaryKey(Integer key) throws FinderException; public CruiseLocal findByName(String cruiseName) throws FinderException; }
It’s not obvious to the container how a custom find method should behave. In EJB 1.0 and 1.1, vendors came up with their own query languages and methods to specify the behavior of these other solutions. Consequently, the custom methods generally were not portable, and guesswork was required on the part of the deployer to determine how to properly execute queries against them. EJB 2.0 introduced the Enterprise JavaBeans Query Language (EJB QL)—a standard query language for declaring the behavior of custom find methods—and the new select methods. Select methods are similar to find methods, but they are more flexible and are visible to the bean class only. Find and select methods are collectively referred to as query methods. EJB 2.1 enhances EJB QL by adding aggregate functions, the ORDER BY clause, and other new features. The differences in EJB QL between EJB 2.1 and EJB 2.0 are clearly stated throughout this chapter.
EJB QL is a declarative query language similar to the Structured Query Language (SQL) used in relational databases, but it is tailored to work with the abstract persistence schema of entity beans. EJB QL queries are defined in terms of the abstract persistence schema of entity beans and not the underlying data store, so they are portable across databases and data schemas. When an entity bean’s abstract bean class is deployed, the EJB QL statements are translated into data access code optimized for a specific data store. At runtime, query methods defined in EJB QL usually execute in the native language of the underlying data store. For example, a container that uses a relational database for persistence might translate EJB QL statements into standard SQL 92, while an object-database container might translate the same EJB QL statements into an object query language.
EJB QL makes it possible to define queries that are portable across databases and EJB vendors. The EJB QL language is easy for developers to learn, yet precise enough to be interpreted into native database code. It is a rich and flexible query language that empowers developers, while executing in fast native code at runtime. However, EJB QL is not a silver bullet and is not without its problems, as we’ll see later in this chapter.
EJB QL
statements are declared in <query>
elements
in an entity bean’s deployment descriptor. In the
following listing, the findByName( )
method defined in the Cruise bean’s local home
interface has its own query element and EJB QL statement:
<ejb-jar ...> <enterprise-beans> <entity> <ejb-name>CruiseEJB</ejb-name> ... <reentrant>False</reentrant><abstract-schema-name>Cruise</abstract-schema-name>
<cmp-version>2.x</cmp-version> <cmp-field> <field-name>name</field-name> </cmp-field> <primkey-field>id</primkey-field><query>
<query-method>
<method-name>findByName</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</query-method>
<ejb-ql>
SELECT OBJECT(c) FROM Cruise AS c
WHERE c.name = ?1
</ejb-ql>
</query>
</entity> </enterprise-beans> </ejb-jar>
The <query>
element contains two primary
elements. The <query-method>
element
identifies a particular find method, and the
<ejb-ql>
element declares the EJB QL
statement. The <query>
element binds the EJB
QL statement to the proper find method. Don’t worry
too much about the EJB QL statement just yet; we’ll
cover that in detail starting in the next section.
Every entity bean that is referenced in an EJB QL statement must have
a special designator called an abstract schema
name
, which is declared by the
<abstract-schema-name>
element. Each element
must declare a unique name. These names must be unique: no two entity
beans may have the same abstract schema name. In the entity element
that describes the Cruise EJB, the abstract schema name is declared
as Cruise
. The <ejb-ql>
element contains an EJB QL statement that uses this identifier in its
FROM
clause.