There are two main types of query methods: find methods and select methods. These are discussed in the following sections.
Find methods are invoked by EJB clients (applications or beans) in
order to locate and obtain the remote or local EJB object references
to specific entity beans. For example, you might call the
findByPrimaryKey()
method on the Customer EJB’s home
interface to obtain a reference to a specific Customer bean.
Find methods are always declared in the
local and remote home interfaces of an entity bean. As you have
already learned, every home interface must define a
findByPrimaryKey()
method; this is a type of
single-entity find method. Specifying a single remote or local return
type for a find method indicates that the method locates only one
bean. findByPrimaryKey()
obviously returns only
one remote reference, because there is a one-to-one relationship
between a primary key’s value and an entity. Other
single-entity find methods can also be declared. For example, in the
following code segment the Customer EJB declares several
single-entity find methods, each of which supports a different query:
public interface CustomerHomeRemote extends javax.ejb.EJBHome { public CustomerRemotefindByPrimaryKey
(Integer primaryKey) throws javax.ejb.FinderException, java.rmi.RemoteException; public CustomerRemotefindByName
(String lastName, String firstName) throws javax.ejb.FinderException, java.rmi.RemoteException; public CustomerRemotefindBySSN
(String socialSecurityNumber) throws javax.ejb.FinderException, java.rmi.RemoteException; }
Bean developers can also define multi-entity find methods, which return a collection of EJB objects. The following listing shows a couple of multi-entity find methods:
public interface CustomerHomeLocal extends javax.ejb.EJBLocalHome { public CustomerLocal findByPrimaryKey(Integer primaryKey) throws javax.ejb.FinderException; public CollectionfindByCity
(String city,String state) throws javax.ejb.FinderException; public CollectionfindByGoodCredit
() throws javax.ejb.FinderException; }
To return several references from a find method, you must use a
java.util.Collection
type.[30] A find method that uses this return type may have
duplicates. To avoid duplicates, you can use the keyword
DISTINCT
in the EJB QL statement associated with
the find method. This technique is explained in more detail in Section 8.3.4 later in this chapter.
Multi-entity finds return an empty Collection
if
no matching beans are found.
Enterprise JavaBeans specifies that all query methods (find or
select) must be declared as throwing the
javax.ejb.FinderException
. Find methods that return a
single remote reference throw a FinderException
if
an application error occurs and a
javax.ejb.
ObjectNotFoundException
if a matching bean cannot be found. The
ObjectNotFoundException
is a subtype of
FinderException
and is thrown only by
single-entity find methods.
Every find method declared in the local or remote home interface of a
CMP 2.0 entity bean must have a matching query declaration in the
bean’s deployment descriptor. The following
snippet from the Customer EJB’s deployment descriptor shows
declarations of two find methods,
findByName()
and
findByGoodCredit()
, from the earlier examples:
<query>
<query-method> <method-name>findByName
</method-name> <method-params> <method-param>java.lang.String</method-param> <method-param>java.lang.String</method-param> </method-params> </query-method> <ejb-ql> SELECT OBJECT(c) FROM Customer c WHERE c.lastName = ?1 AND c.firstName = ?2 </ejb-ql></query>
<query>
<query-method> <method-name>findByGoodCredit
</method-name> <method-params/> </query-method> <ejb-ql> SELECT OBJECT(c) FROM Customer c WHERE c.hasGoodCredit = TRUE </ejb-ql></query>
The query elements in the deployment descriptor allow the bean
developer to associate EJB QL statements with specific find methods.
When the bean is deployed, the container attempts to match the find
method declared in each of the query elements with find methods in
the entity bean’s home interfaces. This is done by matching the
values of the
<method-name>
and
<method-params>
elements with method names and
parameter types (ordering is important) in the home interfaces.
When two find methods in the local and remote home interfaces have
the same method name and parameters, the query declaration will apply
to both of the methods. The container will return the proper type for
each query method: the remote home will return one or more remote EJB
objects, and the local home will return one or more local EJB
objects. This allows you to define the behavior of both the local and
remote home find methods using a single
<query>
element, which is convenient if
you want local clients to have access to the same find methods as
remote clients.
The
<ejb-ql>
element specifies the EJB QL
statement for a specific find method. You may have noticed that EJB
QL statements can use input parameters (e.g., ?1
,
?2
, ... ?n
), which are mapped
to the <method-param>
of the find method, as
well as literals (e.g., TRUE
). The use of input
parameters and literals will be discussed in more detail throughout
this chapter.
With the exception of findByPrimaryKey()
methods,
all single-entity and multi-entity find methods must be declared in
<query>
elements in the deployment
descriptor. Query declarations for
findByPrimaryKey()
methods are not necessary and,
in fact, are forbidden. It’s obvious what this method should
do, and you may not try to change its behavior.
Select methods are similar to find methods, but they are more versatile and can be used only internally, by the bean class. In other words, select methods are private query methods; they are not exposed to an entity bean’s clients through the home interfaces.
Another difference between the select and find methods is the transaction context under which they execute. The select method executes in the transaction context of the business or callback method that is using it, while the find methods execute according to their own transaction attributes, as specified by the bean provider.
Select methods are declared as abstract methods using the
naming convention
ejbSelect<
METHOD-NAME
>
.
The following code shows four select methods declared in the
AddressBean
class:
public class AddressBean implements javax.ejb.EntityBean { ... public abstract StringejbSelectCity
(AddressLocal addr) throws FinderException; public abstract SetejbSelectZipCodes
(String state) throws FinderException; public abstract CollectionejbSelectAll
() throws FinderException; public abstract CustomerLocalejbSelectCustomer
(AddressLocal addr) throws FinderException; ...
Select methods can return the values of CMP fields. The
ejbSelectCity(AddressLocal addr)
method, for example, returns a single
String
value, the name of the city referenced by
the Address EJBs.
To return several references from a select method, you must declare
the return type to be either a
java.util.Collection
or
java.util.Set.
[31] A select method that uses a
Set
return type will not have duplicate values,
while a Collection
return type may have
duplicates. Multi-entity selects return an empty
Collection
or Set
if no
matching beans are found. The
ejbSelectZipCodes()
method returns a
java.util.Set
of String
values:
a unique collection of all the Zip Codes declared for the Address
EJBs for a specific state.
Like find methods, select methods can declare zero or more arguments,
which are used to limit the scope of the query. The
ejbSelectZipCodes()
and
ejbSelectCustomer()
methods both declare arguments
used to limit the scope of the results. These arguments are used as
input parameters in the EJB QL statements assigned to the select
methods.
Select methods can return local or remote EJB objects. For
single-entity select methods, the type
is determined by the return type of the
ejbSelect()
method. The
ejbSelectCustomer()
method, for example, returns a local EJB
object, the CustomerLocal
. This method could
easily have been defined to return a remote EJB object by changing
the return type to the Customer bean’s remote interface
(CustomerRemote
).
Multi-entity
select methods, which return a collection of EJB objects, return
local EJB objects by default. However, the bean provider can override
this default behavior using a special element,
the
<result-type-mapping>
element, in the select
method’s <query>
element.
The following portion of an XML deployment descriptor declares two of
the select methods from the above example. Notice that they are
exactly the same as the find method declarations. Find and select
methods are declared in the same part of the deployment descriptor,
within a <query>
element inside an
<entity>
element:
<query>
<query-method> <method-name>ejbSelectZipCodes
</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </query-method> <ejb-ql>SELECT a.homeAddress.zip FROM Address AS a
WHERE a.homeAddress.state = ?1
</ejb-ql></query>
<query>
<query-method> <method-name>ejbSelectAll
</method-name> <method-params/> </query-method> <result-type-mapping>Remote
</result-type-mapping> <ejb-ql>SELECT OBJECT(a) FROM Address AS a
</ejb-ql></query>
The name given in each
<method-name>
element must match one of the
ejbSelect<
METHOD-NAME
>()
methods defined in the bean class. This is different from find
methods of CMP 2.0 beans, which do not have a corresponding
ejbFind
method in the bean class. For find
methods, we use the method name in the local or remote home
interface. Select methods, on the other hand, are not declared in the
local or remote home interface, so we use the
ejbSelect()
method name in the bean class.
Select methods can return local or remote EJB objects. The default is
to return local EJB object types for both single-entity and
multi-entity select methods. However, the bean provider can override
this default behavior using a special element,
<result-type-mapping>
, in the select
method’s <query>
element. The value of
<result-type-mapping>
can be either Remote
or Local
.
A value of Local
indicates that the select method
should return local EJB objects; Remote
indicates
remote EJB objects. If the
<result-type-mapping>
element is not
declared, the default is Local
. For single-entity
select, the actual return type of the ejbSelect()
method must match the <result-type-mapping>
.
For example, if a single-entity ejbSelect()
method
returns an EJBObject
type, the
<result-type-mapping>
must be
Remote
. In the previous example, the
<result-type-mapping>
in the
<query>
element for the
ejbSelectAll()
method is declared as
Remote
, which means the query should return remote
EJB object types (i.e., remote references to the Address
EJB).[32]
Select methods are not limited to the context of any specific entity
bean. They can be used to query across all the entity beans declared
in the same deployment descriptor. Select methods may be used by the
bean class from its ejbHome()
methods, from any
business methods, or from the ejbLoad()
and
ejbStore()
methods. In most cases, select methods
will be called from ejbHome()
or from business
methods in the bean class. The ejbHome()
,
ejbLoad()
, and ejbStore()
methods are covered in more detail in Chapter 11.
The most important thing to remember about select methods is that while they can do anything find methods can and more, they can be used only by the entity bean class that declares them, not by the entity bean’s clients.
[30] In CMP
2.0, java.util.Collection
is the only collection
type supported for multi-entity find methods. EJB 1.1 CMP and EJB 2.0
BMP also support java.util.Enumeration
.
[31] Other collection types, such
as java.util.List
and
java.util.Map
, may be added in future
versions.
[32] This is illustrative. As a developer, it is unlikely (although possible) that you would define a remote interface for the Address EJB, because it is too fine-grained for use by remote clients.