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) to
obtain 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. Specifying a
single remote or local return type for a find method indicates that
the method locates only one bean. findByPrimaryKey( )
obviously returns a single remote reference, because
there is a one-to-one correspondence 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.[22] A
find method that uses this return type may have duplicates. To avoid
duplicates, use the keyword DISTINCT
in the EJB QL
statement associated with the find method. Multi-entity finds return
an empty Collection
if no matching beans are
found.
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
that is thrown only by
single-entity find methods.
With the exception of findByPrimaryKey( )
methods,
all find methods must be declared in <query>
elements in the bean’s
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. The following snippet from the Customer
EJB’s deployment descriptor shows declarations of
two find methods, findByName( )
and findByGoodCredit( )
:
<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 AS 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 AS c WHERE c.hasGoodCredit = TRUE </ejb-ql></query>
The
<query>
elements 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. To do so, it matches 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 have the same method name and parameters, the
query declaration applies to both methods. (This situation occurs
when similar find methods are in the local home and remote home
interfaces.) The container returns the proper type for each query
method: the remote home returns remote EJB objects, and the local
home returns local EJB objects. You can therefore 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. EJB QL statements can use input
parameters (e.g., ?1
, ?2
, ...
?n
), which are mapped to the
<method-param>
elements of the find method,
as well as literals (e.g., TRUE
).
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 interfaces.
Select and find methods also execute in different transaction contexts. 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
>
.
Here are four select methods declared in the
AddressBean
class:
public class AddressBean implements javax.ejb.EntityBean { ... public abstract StringejbSelectMostPopularCity
( ) 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
ejbSelectMostPopularCity( )
method, for example, returns a single
String
value, the name of the city referenced by
the most Address EJBs.
To return several references from a select method, you must declare
the return type to be either a Collection
or a
Set
.[23] Which type to return depends on whether
you want to allow duplicate values. By definition, a
Set
never contains duplicates, while a
Collection
may have duplicates. Multi-entity
selects return an empty Collection
or
Set
if no matching beans are found. For example,
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 arguments that limit
the scope of the query. For example, the ejbSelectZipCodes( )
and ejbSelectCustomer( )
methods
declare arguments that 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.
Whether a single-entity select method
returns a local or a remote object 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 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, you can override this behavior
by using the
<result-type-mapping>
element in the select
method’s <query>
element.
The following snippet from an XML deployment descriptor declares two select methods. Notice that they are exactly the same as the find method declarations:
<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 in CMP, which use the names of select methods defined by
the bean class.
By default, the <result-type-mapping>
element in the value of
<result-type-mapping>
can be either
Remote
or Local
.
Local
indicates that the select method should
return local EJB objects; Remote
indicates remote
EJB objects. For a single-entity select, the actual return type of
the ejbSelect( )
method must match the
<result-type-mapping>
. In the previous
example, the <result-type-mapping>
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).[24]
Select methods can be used to query all the entity beans declared in
the same deployment descriptor. Select methods may be called by a
bean’s ejbHome( )
methods, by any
business methods, or by the ejbLoad( )
and
ejbStore( )
methods. In most cases, select methods
will be called by ejbHome( )
or by business
methods in the bean class.
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.
[22] In The
java.util.Collection
is the only collection type
supported for multi-entity find methods in CMP.
[23] Other collection types, such
as java.util.List
and
java.util.Map
, may be added in future
versions.
[24] 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.