Skip Headers
Oracle® Containers for J2EE Enterprise JavaBeans Developer's Guide
10g Release 3 (10.1.3)
B14428-02
  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
 

16 Using EJB 2.1 Query API

This chapter describes:

For more information, see:


Note:

For an example OC4J EJB QL application, see: http://www.oracle.com/technology/sample_code/tech/java/ejb_corba/ejbql/Readme.html.

Implementing an EJB 2.1 EJB QL Finder Method

The following procedure describes how to implement an EJB 2.1 EJB QL finder method.

Before implementing a finder method, consider the predefined and default finders that OC4J provides (see "Predefined TopLink Finders" and "Default TopLink Finders").

For more information, see "Understanding Finder Methods".

  1. Define the finder method in the home interface (see "Using Java").

    If you are exposing only predefined or default finders (see "Predefined TopLink Finders" and "Default TopLink Finders"), you are done.

    If you are exposing a custom finder, proceed to step 2.

  2. Configure the ejb-jar.xml file (see "Using Deployment XML").


    Note:

    You can do this manually as described here or you can use the TopLink Workbench (see "Using TopLink Workbench") to automate this step and to take advantage of advanced TopLink finder configuration.

    1. For each entity bean that you plan to reference in your EJB QL query, configure the <entity> element <abstract-schema-name> sub-element.

      The <abstract-schema-name> sub-element defines the name that identifies the entity bean in the EJB QL statement. For example, given an entity bean class named EmpBean, if you define its <abstract-schema-name> as Employee, then in your EJB QL statement, when you use the name Employee, the container will map that name to the EmpBean entity bean (see Example 16-2).

    2. Define a <query> element for each finder method that you exposed in the EJB home interface.


      Note:

      Do not define a <query> element for predefined or default finders, including findByPrimaryKey.

      The <query> element has the following sub-elements:

      • <description>: optional explanatory text

      • <query-method>: describes the finder method and includes the following sub-elements:

        <method-name>: identifies the finder method. Configure this element with the same method name as defined in the home interface.

        <method-params>: if the finder takes arguments, define this element and for each argument, define a <method-param> sub-element that gives the argument type. The type and order of arguments must match that specified by this finder's signature.

      • <ejb-ql>: contains the EJB QL statement for this method.

        You can define a full query or just the conditional statement (the WHERE clause).

        If the finder method returns a Collection, to ensure that no duplicates are returned, specify the DISTINCT keyword in the EJB QL statement.

        To use parameters (as specified by <method-params>) in your EJB QL, use the <integer>? notation where <integer> begins with 1. For example, ?1 corresponds to the first <method-param> element, ?2 corresponds to the second <method-param> element, and so on (see the findAllByEmpName finder in Example 16-2).

        To define an EJB QL statement that relates this EJB with another, you must first define the appropriate container-managed relationship. The findByDeptNo finder in Example 16-2 requires the relationship with <ejb-relation-name> Employee-Departments. For more information, see "Configuring an EJB 2.1 CMP Entity Bean Container-Managed Relationship Field".

Using Java

Example 16-1 shows a remote home interface called EmpBeanHome .

Example 16-1 Finder Methods in an EJB 2.1 CMP Entity Bean Remote Home Interface

package cmpapp;

import javax.ejb.*;
import java.rmi.*;

public interface EmpBeanHome extends EJBHome
{
    public EmpBean create(Integer empNo, String empName) throws CreateException;

    /**
     * Finder methods. These are implemented by the container. We can
     * customize the functionality of these methods in the deployment
     * descriptor through EJB-QL.
     **/

// Predefined Finders: <query> element in ejb-jar.xml not required

    public Topic findByPrimaryKey(Integer key) throws FinderException;
    public Collection findManyBySQL(String sql, Vector args) throws FinderException

// Default Finder: <query> element in ejb-jar.xml not required

    public Topic findByEmpNo(Integer empNo) throws FinderException;

// Custom Finders: <query> element is required in ejb-jar.xml

    public Collection findAllRegionalEmployees(Integer empNo) throws FinderException;
    public Collection findAllByEmpName(String empName) throws FinderException;
    public Topic findByDeptNo(Integer deptNo) thorws FinderException
    public Collection findAllBetweenSalaries(Integer lowSalary, Integer highSalary);

}

Using Deployment XML

Example 16-2 shows the ejb-jar.xml for the finders declared in the home interface that Example 16-1 shows.

Example 16-2 ejb-jar.xml For EJB 2.1 EJB QL Finders

<enterprise-beans>
    <entity>
        <display-name>EmpBean</display-name>
        <ejb-name>EmpBean</ejb-name>
        ...
        <abstract-schema-name>Employee</abstract-schema-name>
        <cmp-field><field-name>empNo</field-name></cmp-field>
        <cmp-field><field-name>empName</field-name></cmp-field>
        <cmp-field><field-name>salary</field-name></cmp-field>
        <primkey-field>empNo</primkey-field>
        <prim-key-class>java.lang.Integer</prim-key-class>
        ...
        <query>
            <description>Regional employees have empNo greater than 10000</description>
            <query-method>
                    <method-name>findAllRegionalEmployees</method-name>
                    <method-params></method-params>
            </query-method>
            <ejb-ql>SELECT OBJECT(e) FROM Employee e WHERE e.empNo > 10000</ejb-ql>
        </query>
        <query>
            <description>Find all employees with the given name</description> 
            <query-method>
                <method-name>findAllByEmpName</method-name>
                <method-params>
                    <method-param>java.lang.String</method-param>
                </method-params>
            </query-method>
            <ejb-ql>SELECT OBJECT(e) FROM Employee e WHERE e.empName = ?1</ejb-ql>
        </query>
        <query>
            <description>Relationship finder</description>
            <query-method>
                <method-name>findByDeptNo</method-name>
                <method-params>
                    <method-param>java.lang.Integer</method-param>
                </method-params>
            </query-method>
            <ejb-ql>
              SELECT DISTINCT OBJECT(e) From Employee e, IN (e.dept) AS d WHERE d.deptNo = ?1
           </ejb-ql>
        </query>
        <query>
            <description>Find all employees with salaries in the given range</description> 
            <query-method>
                <method-name>findAllBetweenSalaries</method-name>
                <method-params>
                    <method-param>java.lang.Integer</method-param>
                    <method-param>java.lang.Integer</method-param>
                </method-params>
            </query-method>
            <ejb-ql>
                SELECT  OBJECT (e) FROM Employee e WHERE e.salary BETWEEN ?1 and ?2
            </ejb-ql>
        </query>
    ...
    </entity>
...
</enterprise-beans>
<relationships>
    <ejb-relation>
        <ejb-relation-name>Employee-Departments</ejb-relation-name>
        <ejb-relationship-role>
            <ejb-relationship-role-name>Employee-has-Departments</ejb-relationship-role-name>
            <multiplicity>One</multiplicity>
            <relationship-role-source>
                <ejb-name>Department</ejb-name>
            </relationship-role-source>
            <cmr-field>
                <cmr-field-name>dept</cmr-field-name>
                <cmr-field-type>java.lang.Integer</cmr-field-type>
            </cmr-field>
        </ejb-relationship-role>
    <ejb-relation>
...
<relationships>

Using TopLink Workbench

Using the TopLink Workbench, you can configure your toplink-ejb-jar.xml file with a custom TopLink finder and update your ejb-jar.xml file.

For more information, see:

Implementing an EJB 2.1 EJB QL Select Method

The following procedure describes how to implement an EJB 2.1 EJB QL select method.

For more information, see "Understanding Select Methods".

  1. Define the select method as a public, abstract method of your abstract entity bean class (see "Using Java").

  2. In the ejb-jar.xml file (see "Using Deployment XML"):

    1. For each entity bean that you plan to reference in your EJB QL query, configure the <entity> element <abstract-schema-name> sub-element.

      The <abstract-schema-name> sub-element defines the name that identifies the entity bean in the EJB QL statement. For example, given an entity bean class named EmpBean: if you define your <abstract-schema-name> as Employee, then in your EJB QL statement, when you use the name Employee, the container will map that name to the EmpBean entity bean ().

    2. Define a <query> element for each select method that you exposed in the EJB home interface.

      You can define a full query or just the conditional statement (the WHERE clause).

      If the select method returns a Collection, to ensure that no duplicates are returned, specify the DISTINCT keyword in the EJB QL statement.

      The <query> element has two main elements:

      • The <method-name> element identifies the select method: configure this element with the same name as defined in the bean class.

      • The <ejb-ql> element contains the EJB QL statement for this method.

    3. If the query returns a Collection of CMR values, decide on the interface type you want returned:

      The ejb-jar.xml file <result-type-mapping> element determines the return type for select methods. Set the flag to Remote to return EJBObjects; set it to Local to return EJBLocalObjects.

Using Java

Example 16-3 shows an abstract entity bean class called UserAccountBean for an EJB 2.1 CMP entity bean with select methods.

Example 16-3 EJB 2.1 CMP Entity Bean Implementation With Select Methods

package oracle.otnsamples.ejbql;

import javax.ejb.*;
import java.util.*;

public abstract class UserAccountBean implements EntityBean
{
    /* ----------------------------------------
    * Non-Persistent State
    * -------------------------------------- */

    protected EntityContext ctx;

    /* ------------------------------------------------------
    * Begin abstract get/set methods. Container-managed
        persistence fields are specified in the ejb-jar.xml 
        deployment descriptor.
    * ------------------------------------------------------- */

    public abstract Long getAccountnumber();
    public abstract void setAccountnumber(Long newAccountnumber);
 
    public abstract Long getCreditlimit();
    public abstract void setCreditlimit(Long newCreditlimit);
 
    /**
     * Select methods. These are implemented by the container. We can
     * customize the functionality of these methods in the deployment
     * descriptor through EJB-QL.
     *
     * These methods are NOT exposed in the bean's home interface.
     **/

    public abstract Long ejbSelectCreditLimit(Long accountnumber) throws FinderException;
    public abstract Collection ejbSelectByTopAccounts() throws FinderException;
 
    /* ------------------------------------------------------
    * Begin buisness logic methods that use select methods.
    * 
    * These methods are exposed in the bean's home interfaces.
    * ------------------------------------------------------- */

    /**
     * Method to perform post-processing operations on all the
     * UserAccounts retrieved by calling ejbSelectByTopAccounts. This
     * method further process the retrieved UserAccounts and checks
     * for the Accounts with TopCredits (credit limits) and returns the
     * collection of input number of UserAccounts.
     * Post-processing information within the EJB container itself
     * has the following two advantages: 
     *     1) It improves performance as the application can now leverage 
     *            the advantage of the vast resources available to the server.
     *     2) The data-processing code should go into the business logic
     *            and not the Web-tier. This helps in maintaining the code.
     * Consider these advantages when deciding between ejbFind and 
     * ejbSelect methods.
     *
     * @return Collection of <input number of> Top (credited) UserAccounts
     */
    public Collection ejbHomeTopAccounts(String accountNumbers) throws FinderException
    {
        // Invoke the ejbSelect method and get all the Account Information.
        Collection collection = this.ejbSelectByTopAccounts();
        ...
        return topAccounts;
    }
 
    /**
     * Method to call ejbSelectCreditLimit and return the credit limit value
     * for the input accountnumber without post-processing.
     * Please note that this method returns a Long instead of a collection
     * that is returned normally by the EJB container. This is a major 
     * advantage of ejbSelect methods. Using these methods, we can return
     * an object from 'within' the CMP instead of 'the' CMP. This way, the 
     * application uses the server and the EJB container resources more 
     * effeciently.
     *
     * @return Credit Limit of the input UserAccount
     */
    public Long ejbHomeCreditLimit(Long accountnumber) throws FinderException
    {
        // Return the Credit Limit of the specified Account
        return this.ejbSelectCreditLimit(accountnumber);
    }
    ...
}

Using Deployment XML

Example 16-4 shows the ejb-jar.xml for the select methods defined in the abstract entity bean class that Example 16-3 shows.

Example 16-4 ejb-jar.xml For EJB 2.1 EJB QL Select Methods

  <enterprise-beans>
    <entity>
      <description>Entity Bean ( CMP )</description>
      <display-name>UserAccount</display-name>
      <ejb-name>UserAccount</ejb-name>
      <local-home>oracle.otnsamples.ejbql.UserAccountLocalHome</local-home>
      <local>oracle.otnsamples.ejbql.UserAccount</local>
      <ejb-class>oracle.otnsamples.ejbql.UserAccountBean</ejb-class>
      <persistence-type>Container</persistence-type>
      <prim-key-class>java.lang.Long</prim-key-class>
      <abstract-schema-name>UserAccount</abstract-schema-name>
      <cmp-field>
        <field-name>accountnumber</field-name>
      </cmp-field>
      <cmp-field>
        <field-name>creditlimit</field-name>
      </cmp-field>
      <primkey-field>accountnumber</primkey-field>
      <query>
        <description>Selects all accounts and post-process to find top accounts</description>
        <query-method>
          <method-name>ejbSelectByTopAccounts</method-name>
        </query-method>
        <ejb-ql>select distinct object(ua) from UserAccount ua</ejb-ql>
      </query>
      <query>
        <description>Retrieves the Credit Limit for an Account</description>
        <query-method>
          <method-name>ejbSelectCreditLimit</method-name>
          <method-params>
            <method-param>java.lang.Long</method-param>
          </method-params>
        </query-method>
        <ejb-ql>
            select ua.creditlimit from UserAccount ua where ua.accountnumber = ?1
        </ejb-ql>
      </query>
    </entity>
  </enterprise-beans>

Using TopLink Workbench

Using the TopLink Workbench, you can configure your toplink-ejb-jar.xml file with a custom TopLink ejbSelect and update your ejb-jar.xml file.

For more information, see: "Creating a Finder" in the Oracle TopLink Developer's Guide

OC4J EJB 2.1 EJB QL Extensions

Although EJB 2.1 does not support square root, date, time, and timestamp types, OC4J provides proprietary EJB QL extensions to support these types in EJB 2.1, as follows:


Note:

These types are fully supported in EJB 3.0 EJB QL.

Example 16-5 Using the EJB 2.1 EJB QL Extension for SQRT

<query> 
  <query-method> 
    <method-name>ejbSelectDoubleTypeSqrt</method-name> 
    <method-params> 
      <method-param>double</method-param> 
    </method-params> 
  </query-method> 
  <result-type-mapping>Remote</result-type-mapping> 
  <ejb-ql> 
    SELECT OBJECT(a) FROM Dept a WHERE a.deptDoubleType = SQRT(?1) 
  </ejb-ql> 
</query> 

Example 16-6 Using the EJB 2.1 EJB QL Extension for java.util.Date

<query> 
  <query-method> 
   <method-name>ejbSelectDate</method-name> 
   <method-params> 
    <method-param>java.util.Date</method-param> 
   </method-params> 
  </query-method> 
  <result-type-mapping>Remote</result-type-mapping> 
  <ejb-ql> 
    SELECT OBJECT(a) FROM Dept a WHERE a.deptDate = ?1 
   </ejb-ql> 
</query> 

Example 16-7 Using the EJB 2.1 EJB QL Extension for java.sql.Date

<query> 
  <query-method> 
   <method-name>ejbSelectSqlDate</method-name> 
   <method-params> 
    <method-param>java.sql.Date</method-param> 
   </method-params> 
  </query-method> 
  <result-type-mapping>Remote</result-type-mapping> 
  <ejb-ql> 
    SELECT OBJECT(a) FROM Dept a WHERE a.deptSqlDate = ?1 
  </ejb-ql> 
</query> 

Example 16-8 Using the EJB 2.1 EJB QL Extension for java.sql.Time

<query> 
  <query-method> 
   <method-name>findByTimestamp</method-name> 
   <method-params> 
    <method-param>java.sql.Time</method-param> 
   </method-params> 
  </query-method> 
  <result-type-mapping>Remote</result-type-mapping> 
  <ejb-ql> 
    SELECT OBJECT(a) FROM Dept a WHERE a.deptTime = ?1 
  </ejb-ql> 
</query> 

Example 16-9 Using the EJB 2.1 EJB QL Extension for java.sql.Timestamp

<query> 
  <query-method> 
   <method-name>findByTimestamp</method-name> 
   <method-params> 
    <method-param>java.sql.Timestamp</method-param> 
   </method-params> 
  </query-method> 
  <result-type-mapping>Remote</result-type-mapping> 
  <ejb-ql> 
    SELECT OBJECT(a) FROM Dept a WHERE a.deptTimestamp = ?1 
  </ejb-ql> 
</query>