Skip Headers
Oracle TopLink Developer's Guide
10g Release 3 (10.1.3)
B13593-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
 

Using EJB Finders

This section describes how to use EJB finders in TopLink, including the following:

Creating a Finder

In general, to create a finder for an entity bean that uses the TopLink query framework, you must define, declare, and configure it.

For predefined finders (see "Predefined Finders"), you do not need to explicitly create a finder.

For default finders (see "Default Finders"), you only need to define the finder method.

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

  1. Define the finder method.

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

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

    For CMP beans, define the method on the entity bean's Home interface.

    For default finders (see "Default Finders"), you must define the finder as follows:

    • <RETURN-TYPE> findBy<CMP-FIELD-NAME>(<CMP-FIELD-TYPE>)

    • the first letter of <CMP-FIELD-NAME> must be capitalized

    • <RETURN-TYPE> may be a single bean type, an Enumeration (EJB 1.1), or Collection (EJB 2.0).

    For example:

    EmployeeBean (Integer id, String name)
    EmployeeHome ..{
       Employee findById(Integer id) throws...;
       Collection findByName(String name) throws...;
    } 
    
    

    Note:

    If you are using default finders (see "Default Finders"), you are finished. TopLink will implement the finder for you at run time.

  2. Declare the finder in the ejb-jar.xml file (see "ejb-jar.xml Finder Options").

  3. Start TopLink Workbench.

  4. Click the project icon in the Navigator and select: Selected > Update Project from ejb-jar.xml to read in the finders.

  5. Go to the Queries > Named Queries tab for the bean (see "Using Named Queries").

  6. Select and configure the finder.


    Notes:

    For predefined finders findOneByQuery and findManyByQuery, the client creates a query at run time and passes it as a parameter to the finder. Because of this, do not configure query options on these finders. Instead, configure options on the query passed into the finder. For more information about predefined finders, see "Predefined Finders".

  7. 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 TopLink CMP, define finder methods on the bean's Home interface, not in the entity bean itself. TopLink CMP provides this functionality and offers several strategies to create and customize finders. The EJB container and TopLink automatically generate the implementation.

ejb-jar.xml Finder Options

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

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 99-10 illustrates the structure of a typical finder defined within the ejb-jar.xml file.


Note:

Use a combination of an escape character and a double-quote ( \" ) when defining your query using EJB QL. For more information on correct query syntax, see a note at the end of Configuring Named Query Selection Criteria.

Example 99-10 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>

The entity tag contains zero or more query elements. Each query tag corresponds to a finder method defined on the bean's 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.

Using Call Finders

Call finders let you create queries dynamically and generate the queries at run time rather than deployment time. Call finders pass a TopLink SQLCall or StoredProcedureCall as a parameter, and return an Enumeration.

Creating Call Finders

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, TopLink creates the call on the client using the TopLink interface oracle.toplink.queryframework.Call. This call has three implementors: EJBQLCall, SQLCall and StoredProcedureCall.

Example 99-11 Executing a Call Finder (Select Statement)

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

Example 99-12 Executing a Call Finder (Stored Procedure)

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

Note:

Warning: Allowing an unverified SQL string to be passed into methods (for example: setSQLString method) makes your application vulnerable to SQL injection attacks.

Using DatabaseQuery Finders

TopLink provides a predefined finder that takes a DatabaseQuery such as a ReadAllQuery. 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 ReadAllQuery finder, create the query on the client, as Example 99-13 shows.

Example 99-13 A ReadAllQuery Finder

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

Using Named Query Finders

You can implement an EJB finder method (including TopLink predefined finders) as a named query. For more information, see "Using Named Queries". You execute such a finder as you would any other.

Using Primary Key Finders

TopLink provides a predefined finder (findByPrimaryKey) that takes a primary key as an Object.

Example 99-14 Executing a Primary Key Finder

{
    Employee employee = getEmployeeHome().findByPrimaryKey(primraryKey);
}

Using Expression Finders

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

Example 99-15 Executing an Expression Finder

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

Using EJB QL Finders

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


Note:

Use a combination of an escape character and a double-quote ( \" ) when defining your query using EJB QL. For more information on correct query syntax, see a note at the end of Configuring Named Query Selection Criteria.

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 EJB QL.

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

To create an EJB QL finder under EJB 1.1 specification, use this procedure:

  1. Declare the finder on the Remote interface.

  2. Start TopLink Workbench.

  3. Go to 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.

To create an EJB QL finder under EJB 2.0 specification, use this procedure:

  1. Declare the finder on either the LocalHome or the RemoteHome interface.

  2. Start TopLink Workbench.

  3. Reimport the ejb-jar.xml file to synchronize the project to the file.

    TopLink 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)

To create an EJB QL finder for a CMP bean, use this procedure:

  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 TopLink 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 > 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)

Using SQL Finders

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

To create a SQL finder, use this procedure:

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

  2. Start TopLink 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. Go the Queries > Named Queries tab for the bean.

  5. Select the finder, select 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 number sign character ( # ) is used to bind the argument projectName within the SQL string:

SELECT * FROM EJB_PROJECT WHERE (PROJ_NAME = #projectName)

Using Redirect Finders

Redirect finders let you specify a finder in which the implementation is defined as a static method on an arbitrary helper class. When you invoke the finder, it redirects the call to the specified static method.

For more information about redirect queries, see "Redirect Queries".

The finder can have any arbitrary parameters. If the finder includes parameters, TopLink packages them into a Vector and passes them to the redirect method.

Redirect finders offer several advantages. Because you define the redirect finder implementation independently from the bean that invokes it, you can build the redirect finder to accept any type and number of parameters. This lets you create a generic redirect finder that accepts several different parameters and return types, depending on input parameters.

A common strategy for using redirect finders is to create a generic finder that does the following:

  • Includes logic to perform several tasks

  • Reads the first passed parameter to identify the type of finder requested and select the appropriate logic

The redirect method contains the logic required to extract the relevant data from the parameters and uses it to construct a TopLink query.

The main disadvantage of redirect finders is that they are complex and can be difficult to configure. They also 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.

To create a redirect finder, use the following procedure:

  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. Create an amendment method.

    For more information, see "Configuring Amendment Methods".

  4. Start TopLink Workbench.

  5. Choose Advanced Properties > After Load from the menu for the bean.

  6. Specify the class and name of the static method to enable the amendment method for the descriptor.

The amendment method then adds a query to the descriptor's query manager, as follows:

ReadAllQuery query = new ReadAllQuery();
query.setRedirector(new MethodBaseQueryRedirector (examples.ejb.cmp20.advanced.
  FinderDefinitionHelper.class,"findAllEmployeesByStreetName"));
descriptor.getQueryManager().addQuery ("findAllEmployeesByStreetName", query);

The redirect method must return either a single entity bean (object) or a Vector. Here are the possible method signatures:

public static Object redirectedQuery(oracle.toplink.sessions.Sessions, Vector args)

and

public static Vector redirectedQuery(oracle.toplink.sessions.Sessions, Vector args)

When you implement the query method, ensure that the method returns the correct type. For methods that return more than one bean, set the return type to java.util.Vector. TopLink converts this result to java.util.Enumeration (or Collection) if required.


Note:

The redirect method also interprets a TopLink session as a parameter. For more information about a TopLink session, see Part XVI, "TopLink Sessions".

At run time, the client invokes the finder from the entity bean home and packages the arguments into the args vector in order of appearance from the finder method signature. The client passes the vector to the redirect finder, which uses them to execute a TopLink expression.

Example 99-16 A Simple Redirect Query Implementation

public class RedirectorTest {
    private Session session;
    private Project project;
    public static void main(String args[]) {

       RedirectorTest test = new RedirectorTest();

       test.login();

            try {
            // Create the arguments to be used in the query
                Vector arguments = new Vector(1);
                arguments.add("Smith");

            // Run the query
                Object o = test.getSession()
                .executeQuery(test.redirectorExample(), arguments);
                o.toString();
            }
            catch (Exception e) {
                System.out.println("Exception caught -> " + e);
                e.printStackTrace();
            }
    }

    public ReadAllQuery redirectorExample() {

       // Create a redirector
       MethodBasedQueryRedirector redirector = new MethodBasedQueryRedirector();

       // Set the class containing the public static method
       redirector.setMethodClass(RedirectorTest.class);

       // Set the name of the method to be run
       redirector.setMethodName("findEmployeeByLastName");

       // Create a query and add the redirector previously created 
       ReadAllQuery readAllQuery = new ReadAllQuery(Employee.class);
       readAllQuery.setRedirector(redirector);
       readAllQuery.addArgument("lastName");

       return readAllQuery;
    }
    // Call the static method
    public static Object findEmployeeByLastName(oracle.toplink.sessions
      .Session
    session, Vector arguments) {

       // Create a query
       ReadAllQuery raq = new ReadAllQuery();
       raq.setReferenceClass(Employee.class);
       raq.addArgument("lastName");

       // Create the selection criteria
       ExpressionBuilder employee = new ExpressionBuilder();
       Expression whereClause =
       employee.get("lastName").equal(arguments.firstElement());

       // Set the selection criteria
       raq.setSelectionCriteria(whereClause);

       return (Vector)session.executeQuery(raq, arguments);
    }
[...]
}

Using the ejbSelect Method

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 specification, the result-type-mapping tag in the ejb-jar.xml file determines the return type for ejbSelect methods. Set the flag to Remote to return EJBObjects; set it to Local to return EJBLocalObjects.

The format for an ejbSelect method definition should be similar to the following:

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 ejbSelect 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 method, use this procedure:

  1. Update the ejb-jar.xml file as follows:

    • Declare the ejbSelect method.

    • Enter the EJB QL string in the ejb-ql tag.

    • Specify the return type in the result-type-mapping tag (if required).

  2. Declare the ejbSelect on the abstract bean class.

  3. Start TopLink Workbench.

  4. Click the project icon in the Navigator, and select: Selected > Update Project from ejb-jar.xml to read in the finders.

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

  6. Select and configure the ejbSelect method.