Skip Headers

Oracle TopLink Developer's Guide 10g Release 3 (10.1.3) B13593-01 |
| Home | Solution Area | Contents | Index

Previous | Next |

# Using EJB Finders

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

- Creating a Finder

- Using Call Finders

- Using DatabaseQuery Finders

- Using Named Query Finders

- Using Primary Key Finders

- Using Expression Finders

- Using EJB QL Finders

- Using SQL Finders

- Using Redirect Finders

- Using the ejbSelect Method

## 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.