Skip Headers
Oracle® Application Server TopLink Application Developer's Guide
10g Release 2 (10.1.2)
Part No. B15901-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

EJB Finders

The OracleAS TopLink query framework enables you to construct finders, which are queries that retrieve entity beans. This section describes OracleAS TopLink support for finders, and includes discussions on the following topics and techniques:

Defining Finders in OracleAS TopLink

To define a finder method for an entity bean that uses the OracleAS TopLink query framework, follow these steps:

  1. Declare the finder in the ejb-jar.xml file.

  2. Define the finder method.

    • For EJB 1.1 beans, define the method on the entity bean remote interface.

    • For EJB 2.0 beans, define the method on the entity bean remoteHome or localHome interface.

  3. Use OracleAS TopLink Mapping Workbench to change any options on finders.

  4. If required, create an implementation for the query. Some query options require a query definition in code on a helper class, but most common queries do not.

When you use OracleAS TopLink CMP, define finder methods on the bean Home interface, not in the entity bean itself. OracleAS TopLink CMP provides this functionality and offers several strategies to create and customize finders. The EJB container and OracleAS TopLink automatically generate the implementation.

ejb-jar.xml Finder Options

The ejb-jar.xml file contains the EJB entity bean information of a project, including definitions for any finders used for the beans. To create and maintain the ejb-jar.xml file, use either a text editor or the OracleAS TopLink Sessions Editor.

entity tag

The entity tag encapsulates a definition for an EJB entity bean. Each bean has its own entity tag that contains several other tags that define bean functionality, including bean finders.

Example 6-76 illustrates the structure of a typical finder defined within the ejb-jar.xml file.

Example 6-76 A Simple Finder Within the ejb-jar.xml File

<entity>...    <query>        <query-method>            <method-name>findLargeAccounts</method-name>                <method-params>                <method-param>double</method-param>            </method-params>        </query-method>    <ejb-ql><![CDATA[SELECT OBJECT(account) FROM AccountBean account WHERE       account.balance > ?1]]></ejb-ql>    </query>...</entity>

query Section

The entity tag contains zero or more query elements. Each query tag corresponds to a finder method defined on the bean home or local Home interface.


Note:

You can share a single query between both Home interfaces, as follows:
  • Define the same finder (same name, return type, and parameters) on both Home interfaces.

  • Include a single query element in the ejb-jar.xml file.


Here are the elements defined in the query section of the ejb-jar.xml file:

  • description (optional): Provides a description of the finder.

  • query-method: Specifies the method for a finder or ejbSelect query.

  • method-name: Specifies the name of a finder or select method in the entity bean implementation class.

  • method-params: Contains a list of the fully-qualified Java type names of the method parameters.

  • method-param: Contains the fully-qualified Java type name of a method parameter.

  • result-type-mapping (optional): Specifies how to map an abstract schema type returned by a query for an ejbSelect method. You can map the type to an EJBLocalObject or EJBObject type. Valid values are Local or Remote

  • ejb-ql: Used for all EJB QL finders. It contains the EJB QL query string that defines the finder or ejbSelect query. Leave this element empty for non-EJB QL finders.

Call Finders

Call finders enable you to create queries dynamically and generate the queries at runtime rather than deployment time. Call finders pass an OracleAS TopLink SQLCall or StoredProcedureCall as a parameter and return an Enumeration.

Creating Call Finders

OracleAS TopLink provides the implementation for Call finders. To use this feature in a bean, add the following finder definition to the Home interface of your bean.

public Enumeration findAll(Call call) throws RemoteException, FinderException;

Executing a Call Finder

When you execute a Call finder, OracleAS TopLink creates the call on the client using the OracleAS TopLink interface oracle.toplink.queryframework.Call. This call has three implementors: EJBQLCall, SQLCall and StoredProcedureCall.

Example 6-77 Executing a Call Finder (Select Statement)

{
    SQLCall call = new SQLCall();
    call.setSQLString("SELECT * FROM EMPLOYEE");
    Enumeration employees = getEmployeeHome().findAll(call);
}

Example 6-78 Executing a Call Finder (Stored Procedure)

{
    StoredProcedureCall call = new StoredProcedureCall();
    call.setProcedureName("READ_ALL_EMPLOYEES");
    Enumeration employees = getEmployeeHome().findAll(call);
}

Expression Finders

To define finder query logic, use OracleAS TopLink expressions. Expression finders support dynamic queries that you generate at runtime rather than deployment time. To use an expression finder, pass the expression as a parameter to a finder that returns an Enumeration.

Example 6-79 Executing an Expression Finder

{
    Expression expression = new 
    ExpressionBuilder().get("firstName").like("J%");
    Enumeration employees = 
    getEmployeeHome().findAll(expression);
}

EJB QL Finders

EJB QL is the standard query language defined in the EJB 2.0 specification. OracleAS TopLink supports EJB QL for both EJB 1.1 and EJB 2.0 beans. EJB QL finders enable you to specify an EJB QL string as the implementation of the query.

EJB QL offers several advantages:

  • It is the EJB 2.0 standard for queries.

  • You can use it to construct most queries.

  • You can implement dependent object queries with it.

The disadvantage of EJB QL is that it is difficult to use when you construct complex queries.

Creating an EJB QL Finder Under EJB 1.1

To create an EJB QL finder under EJB 1.1:

  1. Declare the finder on the remote interface.

  2. Start OracleAS TopLink Mapping Workbench.

  3. Choose the Queries > Finders > Named Queries tab for the bean.

  4. Add a finder and give it a name that matches the method name you declared in Step 1.

  5. Set the required parameters.

  6. Set Query Format to EJB QL, and enter the EJB QL query in the Query String field.

Creating an EJB QL Finder Under EJB 2.0

To create an EJB QL finder under EJB 2.0:

  1. Declare the finder on either the localHome or the remoteHome interface.

  2. Start OracleAS TopLink Mapping Workbench.

  3. Re-import the ejb-jar.xml file to synchronize the project to the file.

    OracleAS TopLink Mapping Workbench synchronizes changes between the project and the ejb-jar.xml file.

The following is an example of a simple EJB QL query that requires one parameter. In this example, the question mark (Ò?Ó) in?1 specifies a parameter.

SELECT OBJECT(employee) FROM Employee employee WHERE (employee.name =?1)

Creating an EJB QL Finder for a CMP Bean

To create an EJB QL finder for a CMP bean:

  1. Declare the finder in the ejb-jar.xml file, and enter the EJB QL string in the ejb-ql tag.

  2. Declare the finder on the Home interface, the localHome interface, or both, as required.

  3. Start OracleAS TopLink Mapping Workbench.

  4. Specify the ejb-jar.xml file location and choose File > Updated Project from the ejb-jar.xml file to read in the finders.

  5. Choose the Queries > Finders > Named Queries tab for the bean.

  6. Add a finder, and give it the same name as the finder you declared on your bean's home. Then add any required parameters.

  7. Select and configure the finder.

The following is an example of a simple EJB QL query that requires one parameter. In this example, the question mark (Ò?Ó) in?1 specifies a parameter.

SELECT OBJECT(employee) FROM Employee employee WHERE (employee.name =?1)

ReadAll Query and EJB QL

To execute a query normally, you supply either a reference class or a SELECT clause.

The basic API for a ReadAll query with EJB QL is:

ReadAllQuery setEJBQLString("...")

Example 6-80 ReadAllQuery Using EJB QL

ReadAllQuery theQuery = new ReadAllQuery();
theQuery.setReferenceClass(EmployeeBean.class);
theQuery.setEJBQLString("SELECT OBJECT(emp) FROM EmployeeBean emp");
…
Vector returnedObjects = (Vector)aSession.executeQuery(theQuery);

Example 6-81 ReadAllQuery Using EJB QL and Passing Arguments

This code creates, populates, and passes a vector of arguments into the executeQuery method

// First define the query
ReadAllQuery theQuery = new ReadAllQuery();
theQuery.setReferenceClass(EmployeeBean.class);
theQuery.setEJBQLString("SELECT OBJECT(emp) FROM EmployeeBean emp WHERE emp.firstName = ?1");
theQuery.addArgument("1");
...
// Next define the Arguments
Vector theArguments = new Vector();
theArguments.add("Bob");
...
// Finally execute the query passing in the arguments
Vector returnedObjects = (Vector)aSession.executeQuery(theQuery, theArguments);

EJB QL Session Queries

When you execute EJB QL directly against the session, it returns a vector of the objects specified by the reference class. The basic API is as follows:

aSession.readAllObjects(<ReferenceClass>, <EJBQLCall>)

Example 6-82 EJB QL Session Query

/* <EJBQLCall> is the EJBQL string to be executed and <ReferenceClass> is the return class type */
// Call ReadAllObjects on a session.
Vector theObjects = (Vector)aSession.readAllObjects(EmployeeBean.class, new EJBQLCall( "SELECT OBJECT (emp) from EmployeeBean emp));

SQL Finders

You can use custom SQL code to specify finder logic. SQL enables you to implement logic that may not be possible to express with OracleAS TopLink expressions or EJB QL.

Creating a SQL Finder

To create a SQL finder:

  1. Declare the finder in the ejb-jar.xml file, and leave the ejb-ql tag empty.

  2. Start OracleAS TopLink Mapping Workbench.

  3. Specify the ejb-jar.xml file location and choose File > Updated Project from the ejb-jar.xml file to read in the finders.

  4. Choose the Queries > Named Queries tab for the bean.

  5. Select the finder, check the SQL radio button, and enter the SQL string.

  6. Configure the finder.

The following is an example of a simple SQL finder that requires one parameter. In this example, the hash character, '#', is used to bind the argument projectName within the SQL string.

SELECT * FROM EJB_PROJECT WHERE (PROJ_NAME = #projectName)

Dynamic Finders

OracleAS TopLink provides several predefined finders you can use to execute dynamic queries, in which the logic is determined by the user at runtime. The OracleAS TopLink runtime reserves the names for these finders; they cannot be reused for other finders.

The predefined finders are:

EJBObject findOneByEJBQL(String ejbql, Vector args)
Collection findManyByEJBQL(String ejbql, Vector args)
EJBObject findOneBySQL(String sql, Vector args)
Collection findManyBySQL(String sql, Vector args)
EJBObject findOneByQuery(DatabaseQuery query, Vector args)
Collection findManyByQuery(DatabaseQuery query, Vector args)

Note:

With EJB 2.0, if the finder is located on a local home, then replace EJBObject with EJBLocalObject in finders that contain findOneby.

You can also use each of these finders without a vector of arguments. For example, EJBObject findOneByEJBQL(String ejbql) is a valid dynamic finder, but you must replace the return type of EJBObject with your bean's component interface.

Creating a Dynamic Finder

To create a dynamic finder:

  1. Declare the finder in the ejb-jar.xml file, and leave the ejb-ql tag empty.

  2. Declare the finder on the Home interface, the localHome interface, or both, as required.

  3. Start OracleAS TopLink Mapping Workbench.

  4. Specify the ejb-jar.xml file location and choose File > Updated Project from the ejb-jar.xml file to read in the finders.

  5. Go to the Queries > Named Queries tab for the bean.

  6. Select and configure the finder.


Notes:

If the advanced query options in "Advanced Finder Options" are not required, then you need only complete steps 1 and 2.

Do not configure any query options for the findOneByQuery and findManyByQuery dynamic finders, because the client creates the query at runtime and passes it as a parameter to the finder. Set any required system options on that query.


Using findAll

In addition to the preceding dynamic finder, OracleAS TopLink provides a default findAll query that returns all the beans of a given type. As with other dynamic finders, the OracleAS TopLink runtime reserves the name findAll.

For more information about defining and configuring the finder, see "Creating a Dynamic Finder".

Using findByPrimaryKey

OracleAS TopLink creates the findByPrimaryKey finder to a bean class when the class initializes. You can configure the findByPrimaryKey finder with the various OracleAS TopLink query options.

Because the EJB 2.0 specification requires the container to implement the findByPrimaryKey call on each bean Home interface, do not delete this finder from a bean.

ReadAll Finders

ReadAll finders enable you to create dynamic queries that you generate at runtime rather than deployment time. To use a ReadAll finder, pass an OracleAS TopLink ReadAllQuery as a parameter to a finder that returns an Enumeration.

Creating READALL Finders

OracleAS TopLink provides an implementation for ReadAll finders. To use this feature in a bean, add the following finder definition to the Home interface of your bean.

public Enumeration findAll(ReadAllQuery query) throws RemoteException, FinderException;

To execute a ReadAll finder, create the query on the client.

Example 6-83 A ReadAll Finder

{
    ReadAllQuery query = new ReadAllQuery(Employee.class);
    query.addJoinedAttribute("address");
    Enumeration employees = getEmployeeHome().findAll(query);
}

Choosing the Best Finder Type for Your Query

To optimize performance, choose the finder type that best suits your needs.

Using the OracleAS TopLink Expression Framework

Using OracleAS TopLink expressions offers the following advantages:

  • Version controlled, standardized queries to Java code

  • Ability to simplify most complex operations

  • A more complete set of querying features than is available through EJB QL

Because expressions enable you to specify finder search criteria based on the object model, they are frequently the best choice for constructing your finders.

For more information about implementing finders using OracleAS TopLink expressions, see "Expression Finders".

Using Redirect Finders

Redirect finders enable you to implement a finder that is defined on an arbitrary helper class as a static method. When you invoke the finder, OracleAS TopLink redirects the call to the specified static method.

Redirect queries are complex and require an extra helper method to define the query. However, because they support complex logic, they are often the best choice when you need to implement logic unrelated to the bean on which the redirect method is called.

Using SQL

Using SQL to define a finder offers the following advantages:

  • SQL enables you to implement logic that cannot be expressed when you use EJB QL or the OracleAS TopLink expression framework.

  • It allows for the use of a stored procedure instead of OracleAS TopLink generated SQL.

  • There may be cases in which custom SQL will improve performance.

SQL finders also have the following disadvantages:

  • Writing complex custom SQL statements requires a significant maintenance effort if the database tables change.

  • The hard coded SQL limits portability to other databases.

  • No validation is performed on the SQL String. Errors in the SQL will not be detected until runtime.

  • The use of SQL for a function other than SELECT may result in unpredictable errors.

ejbSelect

The ejbSelect method is a query method intended for internal use within an entity bean instance. Specified on the abstract bean itself, the ejbSelect method is not directly exposed to the client in the home or component interface. Defined as abstract, each bean can include zero or more such methods.

Select methods have the following characteristics:

  • The method name must have ejbSelect as its prefix.

  • It must be declared as public.

  • It must be declared as abstract.

  • The throws clause must specify the javax.ejb.FinderException, although it may also specify application-specific exceptions as well.

  • Under EJB 2.0, the result-type-mapping tag in the ejb-jar.xml file determines the return type for ejbSelects. Set the flag to Remote to return EJBObjects; set it to Local, to return EJBLocalObjects.

The format for an ejbSelect method definition looks like this:

public abstract type ejbSelect<METHOD>(...);

The ejbSelect query return type is not restricted to the entity bean type on which the ejbSelect is invoked. Instead, it can return any type corresponding to a container-managed relationship or container-managed field.

Although the select method is not based on the identity of the entity bean instance on which it is invoked, it can use the primary key of an entity bean as an argument. This creates a query that is logically scoped to a particular entity bean instance.

To create an ejbSelect:

  1. Declare the ejbSelect in the ejb-jar.xml file, enter the EJB QL string in the ejb-ql tag, and specify the return type in the result-type-mapping tag (if required).

  2. Declare the ejbSelect on the abstract bean class.

  3. Start OracleAS TopLink Mapping Workbench.

  4. Specify the ejb-jar.xml file location, and choose File > Updated Project from the ejb-jar.xml file to read in the finders.

  5. Choose the Queries > Named Queries tab for the bean.

  6. Select and configure the ejbSelect query.

Advanced Finder Options

The default finder configuration is appropriate for most applications. However, finders also allow for several advanced configuration options.

Caching Options

You can apply various configurations to the underlying query to achieve the correct caching behavior for the application. Several ways are available to control the caching options for queries. For most queries, you can set caching options with OracleAS TopLink Mapping Workbench. For more information, see ÒCaching objectsÓ in the Oracle Application Server TopLink Mapping Workbench User's Guide.

You can set the caching options on a per-finder basis. Table 6-8 lists the valid values.

Table 6-8 Finder Caching Options

This Setting . . .  Causes Finders to . . .  When the Search Involves a Finder That . . . 
ConformResultsInUnitOfWork (default) Check the Unit of Work cache before querying the session cache or the database. The results of the finder always conform to uncommitted new objects, deleted objects, and changed objects. Returns either a single bean or a collection.
DoNotCheckCache Query the database, bypassing the OracleAS TopLink internal caches. Returns either a single bean or a collection.
CheckCacheByExactPrimaryKey Check the session cache for the object. Contains only a primary key, and returns a single bean.
CheckCacheByPrimaryKey Check the session cache for the object. Contains a primary key (and may contain other search parameters), and returns a single bean.
CheckCacheThenDatabase Search the session cache before accessing the database Returns a single bean.
CheckCacheOnly Search against the session cache, but not the database. Returns either a single bean or a collection.

For more information about the OracleAS TopLink queries as well as the OracleAS TopLink Unit of Work and how it integrates with JTS, see Chapter 7, "Transactions".


Note:

To apply caching options to finders with manually created (findOneByQuery, findManyByQuery) queries, use the OracleAS TopLink API.

Disable Cache for Returned Finder Results

By default, OracleAS TopLink adds all returned objects to the session cache. However, if you know the set of returned objects is large, and you want to avoid the expense of storing these objects, you can disable this behavior. To override the default configuration, implement the dontMaintainCache() call on the query, or disable returned object caching for the query in OracleAS TopLink Mapping Workbench.

For more information about disabling caching for returned finder results, see the Oracle Application Server TopLink Mapping Workbench User's Guide.

Refreshing Finder Results

A finder may return information from the database for an object whose primary key is already in the cache. When set to true, the Refresh Cache option (in OracleAS TopLink Mapping Workbench) causes the query to refresh the nonprimary key attributes of the object with the returned information. This occurs on findByPrimaryKey finders as well as all expression and SQL finders for the bean.

If you build a query in Java code, you can set this option by including the refreshIdentityMapResult() method. This method automatically cascades changes to privately owned parts of the beans. If you require different behavior, then configure the query using a dynamic finder instead.


Caution:

When you invoke this option from within a transaction, the refresh overwrites object attributes, including any that have not yet been written to the database.


If your application includes an OptimisticLock field, then use the refresh cache option in conjunction with the onlyRefreshCacheIfNewerVersion() option. This ensures that the application refreshes objects in the cache only if the version of the object in the database is newer than the version in the cache.

For finders that have no refresh cache setting, the onlyRefreshCacheIfNewerVersion() method has no effect.

Managing Large Result Sets with Cursored Streams

Large result sets can be resource intensive to collect and process. To give the client more control over the returned results, configure OracleAS TopLink finders to use cursors. This combines OracleAS TopLink CursoredStream with the ability of the database to cursor data, and breaks up the result set into smaller, more manageable pieces.

The behavior of a finder including a cursored stream differs from other finder as follows:

  • Only the elements requested by the client are sent to the client.

  • Nothing is cached on the client in the CursoredEnumerator.

  • If you use the transactional attribute REQUIRED for your entity bean, then you must wrap all reads in a UserTransaction begin() and commit() to ensure that reads beyond the first page of the cursor have a transaction in which to work.

Building the Query

You can configure any finder that returns a java.util.Enumeration (under EJB 1.1) or a java.util.Collection (under EJB 2.0) to use a cursor. When you create the query for the finder, add the useCursoredStream() option to enable cursoring.

Example 6-84 Cursored Stream in a Finder

ReadAllQuery raq = new ReadAllQuery();
ExpressionBuilder bldr = new ExpressionBuilder();
raq.setReferenceClass(ProjectBean.class);
raq.useCursoredStream();
raq.addArgument("projectName");
raq.setSelectionCriteria(bldr.get("name").
like(bldr.getParameter("projectName")));
descriptor.getQueryManager().addQuery ("findByNameCursored", query);

Executing the Finder from the Client in EJB 1.1

OracleAS TopLink offers additional elements for traversing finder results. These elements include:

  • hasMoreElements(): Returns a boolean indicating whether there are any more elements in the result set.

  • nextElement(): Returns the next available element.

  • nextElements(int count): Retrieves a Vector of at most count elements from the available results, depending on how many elements remain in the result set.

  • close(): Closes the cursor on the server. The client must send this message, or the database connection does not close.

Example 6-85 illustrates client-code executing a cursored finder.

Example 6-85 Cursored Finder Under EJB 1.1

import oracle.toplink.ejb.cmpwls11. CursoredEnumerator;
//... other imports as necessary
getTransaction().begin();
CursoredEnumerator cursoredEnumerator = (CursoredEnumerator)getProjectHome()  .findByNameCursored("proj%");

Vector projects = new Vector();
for (int index = 0; index < 50; i++) {
Project project = (Project)cursoredEnumerator.nextElement();
projects.addElement(project);
}
// Rest all at once ...
Vector projects2 = cursoredEnumerator.nextElements(50);
cursoredEnumerator.close();
getTransaction().commit();

Executing the Finder from the Client in EJB 2.0

As with EJB 1.1, OracleAS TopLink offers additional elements for traversing finder results under EJB 2.0. These elements include:

  • isEmpty(): As with java.util.Collection, isEmpty() returns a boolean indicating whether the Collection is empty.

  • size(): As with java.util.Collection, size() returns an integer indicating the number of elements in the Collection.

  • iterator(): As with java.util.Collection, iterator() returns a java.util.Iterator for enumerating the elements in the Collection.

OracleAS TopLink also offers an extended protocol for oracle.toplink.ejb.cmp.wls.CursoredIterator (based on java.util.Iterator):

  • close(): Closes the cursor on the server. The client must send this message to close the database connection.

  • hasNext(): Returns a boolean indicating whether any more elements are in the result set.

  • next(): Returns the next available element.

  • next(int count): Retrieves a Vector of at most count elements from the available results, depending on how many elements remain in the result set.

Example 6-86 illustrates client code executing a cursored finder.

Example 6-86 Cursored Finder Under EJB 2.0

//import both CursoredCollection and CursoredIterator
import oracle.toplink.ejb.cmp.wls.*;
//... other imports as necessary
getTransaction().begin();
CursoredIterator cursoredIterator = (CursoredIterator) getProjectHome().findByNameCursored("proj%").iterator();
Vector projects = new Vector();
for (int index = 0; index < 50; i++) {
Project project = (Project)cursoredIterator.next();
projects.addElement(project);
}
// Rest all at once ...
Vector projects2 = cursoredIterator.next(50);
cursoredIterator.close();
getTransaction().commit();