Find
methods have been a part of the
Enterprise JavaBeans specification since EJB 1.0. These methods are
defined on the entity bean’s local and remote home interfaces
and are used for locating entity beans. All entity beans must have a
findByPrimaryKey()
method, which takes the primary key of the
entity bean as an argument and returns a reference to an entity bean.
For example, the Cruise EJB defines the standard primary key find
method in its home interface as follows:
public CruiseHomeLocal extends javax.ejb.EJBLocalHome { public Integer create(String name,ShipLocal ship); public CruiseLocal findByPrimaryKey(Integer key); }
In addition to the mandatory findByPrimaryKey()
method, entity bean developers may define as many custom
find
methods as they like. For example, the Cruise EJB might define a
method, such as 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;
}
The option of defining custom find methods is nothing new, but until
EJB 2.0 there was no standard way of defining how the find methods
should work. The behavior of the
findByPrimaryKey()
method is obvious: find the
entity bean with the same primary key. However, the behavior of
custom find methods is not always obvious, so additional information
is needed to tell the container how these methods should behave. EJB
1.1 didn’t provide any standard mechanism for declaring the
behavior of custom find methods, so vendors came up with their own
query languages and methods. 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 in EJB 2.0.
EJB QL is a declarative query language that is 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 in EJB 2.0.
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 by the container, the EJB QL statements are typically examined and translated into data access code optimized for that container’s 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 for bean developers to describe the behavior of query methods in an abstract fashion, making queries 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 fairly rich and flexible query language that empowers developers at development time, 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, you can see that 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 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 the find method of the remote and/or local home
interfaces, 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 will be 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. The
<abstract-schema-name>
elements must have
unique names; 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.
In Chapter 7, you learned that the abstract
persistence schema of an entity bean is defined by its
<cmp-field>
and
<cmr-field>
elements. The abstract schema
name is also an important part of the abstract persistence schema.
EJB QL statements are always expressed in terms of the abstract
persistence schemas of entity beans. EJB QL uses the abstract schema
names to identify entity bean types, the container-managed
persistence (CMP)
fields to identify specific entity bean data, and the
container-managed relationship (CMR) fields to create paths for
navigating between entity beans.