Oracle TopLink Developer's Guide
10g Release 3 (10.1.3) B13593-01 |
|
![]() Previous |
![]() Next |
This section describes how to use EJB finders in TopLink, including the following:
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:
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. |
Declare the finder in the ejb-jar.xml
file (see "ejb-jar.xml Finder Options").
Start TopLink Workbench.
Click the project icon in the Navigator and select: Selected > Update Project from ejb-jar.xml to read in the finders.
Go to the Queries > Named Queries tab for the bean (see "Using Named Queries").
Select and configure the finder.
Notes: For predefined findersfindOneByQuery 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".
|
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.
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 bothHome interfaces, as follows:
|
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 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
.
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;
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.
|
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.
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.
TopLink provides a predefined finder (findByPrimaryKey
) that takes a primary key as an Object
.
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.
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:
Declare the finder on the Remote
interface.
Start TopLink Workbench.
Go to the Queries > Finders > Named Queries tab for the bean.
Add a finder and give it a name that matches the method name you declared in Step 1.
Set the required parameters.
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:
Declare the finder on either the LocalHome
or the RemoteHome
interface.
Start TopLink Workbench.
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:
Declare the finder in the ejb-jar.xml
file, and enter the EJB QL string in the ejb-ql
tag.
Declare the finder on the Home
interface, the LocalHome
interface, or both, as required.
Start TopLink Workbench.
Specify the ejb-jar.xml
file location and choose File > Updated Project from the ejb-jar.xml
file to read in the finders.
Go to the Queries > Finders > Named Queries tab for the bean.
Add a finder, and give it the same name as the finder you declared on your bean's home. Then add any required parameters.
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)
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:
Declare the finder in the ejb-jar.xml
file, and leave the ejb-ql
tag empty.
Start TopLink Workbench.
Specify the ejb-jar.xml
file location and choose File > Updated Project from the ejb-jar.xml
file to read in the finders.
Go the Queries > Named Queries tab for the bean.
Select the finder, select the SQL radio button, and enter the SQL string.
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)
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:
Declare the finder in the ejb-jar.xml
file, and leave the ejb-ql
tag empty.
Declare the finder on the Home
interface, the localHome
interface, or both, as required.
Create an amendment method.
For more information, see "Configuring Amendment Methods".
Start TopLink Workbench.
Choose Advanced Properties > After Load from the menu for the bean.
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); } [...] }
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:
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).
Declare the ejbSelect on the abstract bean class.
Start TopLink Workbench.
Click the project icon in the Navigator, and select: Selected > Update Project from ejb-jar.xml to read in the finders.
Go the Queries > Named Queries tab for the bean.
Select and configure the ejbSelect method.