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
 

Query Building Basics

OracleAS TopLink supports several options for creating queries, including:

Expressions

OracleAS TopLink expressions enable you to specify query search criteria based on the object model. OracleAS TopLink translates the resulting query into SQL and converts the results of the query into objects. OracleAS TopLink provides two public classes to support expression:

  • The Expression class represents an expression, which can be anything from a simple constant to a complex clause with boolean logic. You can manipulate, group, and integrate expressions in several ways.

  • The ExpressionBuilder class is the factory for constructing new expressions.

Accessing Methods in Expressions

The OracleAS TopLink expression framework provides methods through the following classes:

  • The Expression class provides most general functions, such as toUpperCase.

  • The ExpressionMath class supplies mathematical methods.

The following code examples illustrate the two classes. Example 6-1 uses the Expression class; while Example 6-2 uses the ExpressionMath class.

Example 6-1 Using the Expression Class

expressionBuilder.get("lastName").equal("Smith");

Example 6-2 Using the ExpressionMath Class

ExpressionMath.abs(ExpressionMath.subtract(emp.get("salary"),
emp.get("spouse").get("salary")).greaterThan(10000)

This division of functionality enables OracleAS TopLink expressions to provide similar mathematical functionality to the Java class, java.lang.Math, but keeps both the Expression and ExpressionMath classes from becoming unnecessarily complex.

Expression Components

A simple expression normally consists of three parts:

  • The attribute, which represents a mapped attribute or query key of the persistent class

  • The operator, which is an expression method that implements boolean logic, such as GreaterThan, Equal, or Like

  • The constant or comparison, which refers to the value used to select the object

In the following code fragment:

expressionBuilder.get("lastName").equal("Smith"); 

  • The attribute is lastName.

  • The operator is equal().

  • The constant is the string ÒSmithÓ.

The expressionBuilder substitutes for the object or objects to be read from the database. In this example, expressionBuilder represents employees.

Expressions Compared to SQL

Expressions offer the following advantages over SQL when you access a database:

  • Expressions are easier to maintain because the database is abstracted.

  • Changes to descriptors or database tables do not affect the querying structures in the application.

  • Expressions enhance readability by standardizing the Query interface so that it looks similar to traditional Java calling conventions. For example, the Java code required to get the street name from the Address object of the Employee class looks like this:

    emp.getAddress().getStreet().equals("Meadowlands");
    
    

    The expression to get the same information is similar:

    emp.get("address").get("street").equal("Meadowlands");
    
    
  • Expressions allow read queries to transparently query between two classes that share a relationship. If these classes are stored in multiple tables in the database, then OracleAS TopLink automatically generates the appropriate join statements to return information from both tables.

  • Expressions simplify complex operations. For example, the following Java code retrieves all Employees that live on "Meadowlands" whose salary is greater than 10,000:

    ExpressionBuilder emp = new ExpressionBuilder();
    Expression exp = emp.get("address").get("street").equal("Meadowlands");
    Vector employees = session.readAllObjects(Employee.class,
      exp.and(emp.get("salary").greaterThan(10000)));
    
    

    OracleAS TopLink automatically generates the appropriate SQL from that code:

    SELECT t0.VERSION, t0.ADDR_ID, t0.F_NAME, t0.EMP_ID, t0.L_NAME, t0.MANAGER_ID, t0.END_DATE, t0.START_DATE, t0.GENDER, t0.START_TIME, t0.END_TIME,t0.SALARY FROM EMPLOYEE t0, ADDRESS t1 WHERE (((t1.STREET = 'Meadowlands')AND (t0.SALARY > 10000)) AND (t1.ADDRESS_ID = t0.ADDR_ID))
    

Boolean Logic

Expressions use standard boolean operators, such as AND, OR, and NOT, and you can combine multiple expressions to form more complex expressions. For example, the following code fragment queries for projects managed by a selected person, with a budget greater than or equal to $1,000,000.

ExpressionBuilder project = new ExpressionBuilder();
Expression hasRightLeader, bigBudget, complex;
Employee selectedEmp = someWindow.getSelectedEmployee();
hasRightLeader = project.get("teamLeader").equal(selectedEmp);
bigBudget = project.get("budget").greaterThanEqual(1000000);
complex = hasRightLeader.and(bigBudget);
Vector projects = session.readAllObjects(Project.class, complex);

Database Functions

OracleAS TopLink supports the following database functions and operators:

  • like()

  • notLike()

  • toUpperCase()

  • toLowerCase()

  • toDate()

  • rightPad()

Database functions allow you to define more flexible queries. For example, the following code fragment matches several last names, including ÒSMARTÓ, ÒSmithÓ, and ÒSmothersÓ:

emp.get("lastName").toUpperCase().like("SM%")

You access most functions through methods such as toUpperCase on the Expression class.

Mathematical Functions

Mathematical functions are available through the ExpressionMath class. Mathematical function support in expressions is similar to the support provided by the Java class java.lang.Math.

For example:

ExpressionMath.abs(ExpressionMath.subtract(emp.get("salary"),emp.get("spouse")
  .get("salary")).greaterThan(10000)

Platform and User Defined Functions

You can use expressions to implement database functions that OracleAS TopLink does not support directly. For simple functions, use the getFunction() operation, in which the argument is the name of a function. For example, note the following expression, which calls a function known as VacationCredit on the database:

emp.get("lastName").getFunction("VacationCredit").greaterThan(42)

This expression produces the following SQL:

SELECT . . . WHERE VacationCredit(EMP.LASTNAME) > 42

You can also create more complex functions and add them to OracleAS TopLink. See "Platform and User-Defined Functions".

Expressions for One-to-One and Aggregate Object Relationships

Expressions can include an attribute that has a one-to-one relationship with another persistent class. A one-to-one relation translates naturally into a SQL join that returns a single row.

For example, the following code fragment accesses fields from an employee's address:

emp.get("address").get("country").like("S%")

This example corresponds to joining the EMPLOYEE table to the ADDRESS table, based on the address foreign key, and checking for the country name. You can nest these relationships infinitely, so it is possible to ask for complex information as follows:

project.get("teamLeader").get("manager").get("manager").get("address").get("street")

Expressions for Complex Relationships

You can query against complex relationships, such as one-to-many, many-to-many, direct collection, and aggregate collection relationships. Expressions for these types of relationships are more complex to build, because the relationships do not map directly to joins that yield a single row per object.

To query across a one-to-many or many-to-many relationship, use the anyOf operation. As its name suggests, this operation supports queries that return all items on the ÒmanyÓ side of the relationship that satisfy the query criteria. For example, note the following code fragment:

emp.anyOf("managedEmployees").get("salary").lessThan(10000);

This code returns employees who manage at least one employee (through a one-to-many relationship) with a salary below $10,000. You can query across a many-to-many relationship using a similar strategy:

emp.anyOf("projects").equal(someProject)

OracleAS TopLink translates these queries to SQL, and SQL joins the relevant tables using a DISTINCT clause to remove duplicates.

For example:

SELECT DISTINCT . . . FROM EMP t1, EMP t2 WHERE
t2.MANAGER_ID = t1.EMP_ID AND t2.SALARY < 10000

Creating Expressions with the Expression Builder

To create Expression objects, use the get() method or its related methods on an Expression or ExpressionBuilder. The ExpressionBuilder acts as a stand-in for the objects you query. To construct a query, send messages to the ExpressionBuilder that correspond to the attributes of the objects. We recommend that you name ExpressionBuilder objects according to the type of objects against which you perform a query.


Note:

An instance of ExpressionBuilder is specific to a particular query. Do not attempt to build another query using an existing builder, because it still contains information related to the first query.

Example 6-3 A Simple Expression Builder Expression

This example uses the query key lastName to reference the field name L_NAME.

Expression expression = new ExpressionBuilder().get("lastName").equal("Young");

Example 6-4 An Expression Using the and() Method

ExpressionBuilder emp = new ExpressionBuilder();
    Expression exp1, exp2;
    exp1 = emp.get("firstName").equal("Ken");
    exp2 = emp.get("lastName").equal("Young");
    return exp1.and(exp2);

Example 6-5 An Expression Using the notLike() Method

Expression expression = new ExpressionBuilder().get("lastName").notLike("%ung");

Using Multiple Expressions

Expressions support subqueries (SQL subselects) and parallel selects. To create a subquery, use a single expression builder. With parallel selects, use multiple expression builders when you define a single query. This enables you to specify joins for unrelated objects at the object level.

Subselects and Subqueries

Some queries compare the results of other, contained queries (or subqueries). SQL supports this comparison through subselects. OracleAS TopLink expressions provide subqueries to support subselects.

Subqueries enable you to define sophisticated expressions that query on aggregated values (counts, min, max) and unrelated objects (exists, in, comparisons). To obtain a subquery, pass an instance of a report query to any expression comparison operation, or use the subQuery operation on expression builder. The subquery is not required to have the same reference class as the parent query, and it must use its own expression builder.

You can nest subqueries, or use them in parallel. Subqueries can also make use of custom SQL.

For expression comparison operations that accept a single value (equal, greaterThan, lessThan), the subquery result must return a single value. For expression comparison operations that accept a set of values (in, exists), the subquery result must return a set of values.

Example 6-6 A Subquery Expression Using a Comparison and Count Operation

This example searches for all employees with more than 5 managed employees.

ExpressionBuilder emp = new ExpressionBuilder();
ExpressionBuilder managedEmp = new ExpressionBuilder();
ReportQuery subQuery =new ReportQuery(Employee.class, managedEmp);
subQuery.addCount();
subQuery.setSelectionCriteria(managedEmp.get("manager") .equal(emp));
Expression exp = emp.subQuery(subQuery).greaterThan(5);

Example 6-7 A Subquery Expression Using a Comparison and Max Operation

This example searches for the employee with the highest salary in the city of Ottawa.

ExpressionBuilder emp = new ExpressionBuilder();
ExpressionBuilder ottawaEmp = new ExpressionBuilder();
ReportQuery subQuery = new ReportQuery(Employee.class, ottawaEmp);
subQuery.addMax("salary");
subQuery.setSelectionCriteria(ottawaEmp.get("address").get("city").equal("Ottawa"));
Expression exp =   emp.get("salary").equal(subQuery).and(emp.get("address").get("city").equal("Ottawa"));

Example 6-8 A Subquery Expression Using a Not Exists Operation

This example searches for all employees that have no projects.

ExpressionBuilder emp = new ExpressionBuilder();
ExpressionBuilder proj = new ExpressionBuilder();
ReportQuery subQuery = new ReportQuery(Project.class, proj);
subQuery.addAttribute("id");
subQuery.setSelectionCriteria(proj.equal(emp.anyOf("projects"));
Expression exp = emp.notExists(subQuery);

Parallel Expressions

Parallel expressions enable you to compare unrelated objects. Parallel expressions require multiple expression builders, but do not require the use of report queries. Each expression must have its own expression builder, and you must use the constructor for expression builder that takes a class as an argument. The class does not have to be the same for the parallel expressions, and you can create multiple parallel expressions in a single query.

Only one of the expression builders is considered the primary expression builder for the query. This primary builder makes use of the zero argument expression constructor, and OracleAS TopLink obtains its class from the query.

Example 6-9 A Parallel Expression on Two Independent Employees

This example queries all employees with the same last name as another employee of different gender, and accounts for the possibility that returned results can be a spouse.

ExpressionBuilder emp = new ExpressionBuilder();
ExpressionBuilder spouse = new ExpressionBuilder(Employee.class);
Expression exp = emp.get("lastName").equal(spouse.get("lastName"))
  .and(emp.get("gender").notEqual(spouse.get("gender"));

Parameterized Expressions and Finders

A relationship mapping differs from a regular query because it retrieves data for many different objects. To enable you to specify these queries, supply arguments when you execute the query. Use the getParameter() and getField() methods to acquire values for the arguments.

A parameterized expression executes searches and comparisons based on variables instead of constants. This approach enables you to build expressions that retrieve context-sensitive information. This technique is useful when you:

  • Customize mappings

  • Create reusable queries

  • Define EJB finders

Parameterized expressions require that the relationship mapping know how to retrieve an object or collection of objects based on its current context. For example, a one-to-one mapping from Employee to Address must query the database for an address based on foreign key information from the Employee table. Each mapping contains a query that OracleAS TopLink constructs automatically based on the information provided in the mapping. To specify expressions yourself, use the mapping customization mechanisms. For more information about the mapping customization mechanisms, see the Oracle Application Server TopLink Mapping Workbench User's Guide.

Expression getParameter()

The getParameter() method returns an expression that becomes a parameter in the query. This method enables you to create a query that employs user input as the search criteria. The parameter must be either the fully qualified name of the field from a descriptor's row, or a generic name for the argument.

Parameters you construct this way are global to the current query, so you can send this message to any expression object.

Example 6-10 Using Expression getParameter() and getField()

ExpressionBuilder address = new ExpressionBuilder();
Expression exp = address.getField
  ("ADDRESS.EMP_ID").equal(address.getParameter("EMPLOYEE.EMP_ID"));
exp = exp.and(address.getField("ADDRESS.TYPE").equal(null));

Expression getField()

The getField() method returns an expression that represents a database field with the given name. Use the Expression getField() method to construct the selection criteria for a mapping. The argument is the fully qualified name of the required field. Because fields are not global to the current query, you must send this method to an expression that represents the table from which this field is derived. See also "Data Queries" .

Example 6-11 The Use of a Parameterized Expression in a Mapping

This example obtains a simple one-to-many mapping from class PolicyHolder to Policy using a nondefault selection criteria. The SSN field of the POLICY table is a foreign key to the SSN field of the HOLDER table.

OneToManyMapping mapping = new OneToManyMapping();
mapping.setAttributeName("policies");
mapping.setGetMethodName("getPolicies");
mapping.setSetMethodName("setPolicies");
mapping.setReferenceClass(Policy.class);

// Build a custom expression here rather than using the defaults
ExpressionBuilder policy = new ExpressionBuilder();
mapping.setSelectionCriteria(policy.getField("POLICY.SSN")).equal(policy.
  getParameter("HOLDER.SSN")));

Example 6-12 A Parameterized Expression in a Custom Query

This example uses an employee's first name to demonstrate how to use a custom query to find the employee.

ExpressionBuilder emp = new ExpressionBuilder();
Expression firstNameExpression;
firstNameExpression = emp.get("firstName").equal(emp.getParameter("firstName"));
ReadObjectQuery query = new ReadObjectQuery();
query.setReferenceClass(Employee.class);
query.setSelectionCriteria(firstNameExpression);
query.addArgument("firstName");
Vector v = new Vector();
v.addElement("Sarah");
Employee e = (Employee) session.executeQuery(query, v);

Example 6-13 Nested Parameterized Expressions

This example demonstrates how to use a custom query to find all employees that live in the same city as a given employee.

ExpressionBuilder emp = new ExpressionBuilder();
Expression addressExpression;
addressExpression = emp.get("address").get("city").equal(emp.getParameter("employee").get("address").get("city"));
ReadObjectQuery query = new ReadObjectQuery(Employee.class);
query.setName("findByCity");
query.setReferenceClass(Employee.class);
query.setSelectionCriteria(addressExpression);
query.addArgument("employee");
Vector v = new Vector();
v.addElement(employee);
Employee e = (Employee) session.executeQuery(query, v);

Platform and User-Defined Functions

Different databases sometimes implement the same functions in different ways. For example, an argument that specifies that data returns in ascending order may be ASC or ASCENDING. To manage differences, OracleAS TopLink recognizes functions and other operators that vary according to the relational database.

Although most platform-specific operators exist in OracleAS TopLink, use the ExpressionOperator class to add your own.

An ExpressionOperator has a selector and a vector of strings:

  • The selector is the identifier (id) by which users refer to the function.

  • The strings are the constant strings used in printing the function. When printed, the strings alternate with the function arguments.

You can also specify whether the operator is prefix or postfix. In a prefix operator, the first constant string prints before the first argument; in a postfix operator, it prints afterwards.

Example 6-14 Creating a New Expression Operator—The toUpperCase Operator

Add the following in a sublass of DatabasePlatform:

ExpressionOperator toUpper = new ExpressionOperator();
toUpper.setSelector();
Vector v = new Vector();
v.addElement("UPPER(");
v.addElement(")");
toUpper.printAs(v);
toUpper.bePrefix();
toUpper.setNodeClass(FunctionExpression.class); 
addOperator(toUpper);

// To add this operator for all database
ExpressionOperator.addOperator(toUpper);
// To add to a specific platform
DatabasePlatform platform = session.getLogin().getPlatform();
platform.addOperator(toUpper);

Example 6-15 Accessing a User-Defined Function

This example illustrates the getFunction() method, called with a vector of arguments.

ReadObjectQuery query = new ReadObjectQuery(Employee.class);
Expression functionExpression = new
  ExpressionBuilder().get("firstName").getFunction(ExpressionOperator.toUpper).
  equal("BOB");
query.setSelectionCriteria(functionExpression);
session.executeQuery(query);

Data Queries

You can use expressions to retrieve data rather than objects. This is a common approach when you work with unmapped information in the database, such as foreign keys and version fields.

Expressions that query for objects generally refer to object attributes, which may in turn refer to other objects. Data expressions refer to tables and their fields. You can combine data expressions and object expressions within a single query. OracleAS TopLink provides two main operators for expressions that query for data: getField(), and getTable().

getField()

The getField() operator enables you to retrieve data from either an unmapped table or an unmapped field from an object. In either case, the field must be part of a table represented by the class of that object; otherwise, OracleAS TopLink raises an exception when you execute the query.

You can also use the getField() operator to retrieve the foreign key information for an object.

Example 6-16 Using getField Against an Object

builder.getField("[FIELD_NAME]").greaterThan("[ARGUMENT]"); 

getTable()

The getTable() operator returns an expression that represents an unmapped table in the database. This expression provides a context from which to retrieve an unmapped field when you use the getField() operator.

Example 6-17 Using getTable() and getField() Together

builder.getTable("[TABLE_NAME]").getField("[FIELD_NAME]").equal("[ARGUMENT]");

A common use for the getTable() and getField() operators is to retrieve information from a link table (or reference table) that supports a many-to-many relationship. Example 6-18 reads a many-to-many relationship that uses a link table and also checks an additional field in the link table. This code combines an object query with a data query, using the employee's manager as the basis for the data query. It also features parameterization for the project ID.

Example 6-18 Using a Data Query Against a Link Table

ExpressionBuilder emp = new ExpressionBuilder();
Expression manager = emp.get("manager"); 
Expression linkTable = manager.getTable("PROJ_EMP");
Expression empToLink = emp.getField("EMPLOYEE   .EMP_ID").equal(linkTable.getField("PROJ_EMP.EMP_ID");
Expression projToLink = linkTable.getField("PROJ_EMP
  .PROJ_ID").equal(emp.getParameter("PROJECT.PROJ_ID"));
Expression extra = linkTable.getField("PROJ_EMP.TYPE").equal("W");
query.setSelectionCriteria((empToLink.and(projToLink)).and(extra));

Query Keys

A query key is an alias for a field name. Instead of referring to a field using a DBMS-specific field name such as F_NAME, query keys allow OracleAS TopLink expressions to refer to the field using class attribute names such as firstName. This offers the following advantages:

  • Query keys enhance code readability when you define OracleAS TopLink expressions.

  • Query keys increase portability by making code independent of the database schema. If you rename a field, you can redefine the query key without changing any code that references it.

  • Unlike interface descriptors that define only common query keys shared by their implementors, aliased fields can have different names in each of the implementor tables.

For more information about query keys with OracleAS TopLink Mapping Workbench, see "Working with Query Keys," in the Oracle Application Server TopLink Mapping Workbench User's Guide.

Automatically-Generated Query Keys

OracleAS TopLink defines direct query keys for all direct mappings and has a special query key type for each mapping. You can use query keys to access fields that do not have direct mappings associated with them, such as the version field used for optimistic locking or the type field used for inheritance.

Example 6-19 Automatically-Generated Query Key in the OracleAS TopLink Expression Framework

Vector employees = session.readAllObjects(Employee.class,
  new ExpressionBuilder().get("firstName").equal("Bob"));

Relationship Query Keys

OracleAS TopLink supports and defines query keys for relationship mappings. You can use query keys to join across a relationship. One-to-one query keys define a joining relationship. To access query keys for relationship mappings, use the get() method in expressions.

Example 6-20 One-to-One Query Key

The following code example illustrates how to use a one-to-one query key within the OracleAS TopLink expression framework.

ExpressionBuilder employee = new ExpressionBuilder();
Vector employees = session.readAllObjects(Employee.class,
  employee.get("address").get("city").equal("Ottawa"));

To access one-to-many and many-to-many query keys that define a distinct join across a collection relationship, use the anyOf() method in expressions.

If no mapping exists for the relationship, you can also define relationship query keys manually. Relationship query keys are not supported directly by OracleAS TopLink Mapping Workbench. To define a relationship query key, specify and write an amendment method, and use the addQueryKey() message to register the query keys.

Example 6-21 Defining One-to-One Query Key Example

The following code defines a one-to-one query key.

/* Static amendment method in Address class, addresses do not know their owners in the object-model, however you can still query on their owner if a user-defined query key is defined */
public static void addToDescriptor(Descriptor descriptor)
{
OneToOneQueryKey ownerQueryKey = new OneToOneQueryKey();
ownerQueryKey.setName("owner");
ownerQueryKey.setReferenceClass(Employee.class);
ExpressionBuilder builder = new ExpressionBuilder();
ownerQueryKey.setJoinCriteria(builder.getField("EMPLOYEE.ADDRESS_
ID").equal(builder.getParameter("ADDRESS.ADDRESS_ID")));
descriptor.addQueryKey(ownerQueryKey);
}

Reference

Table 6-1 and Table 6-2 summarize the most common public methods for ExpressionBuilder and Expression. For more information about the available methods for ExpressionBuilder and Expression, see the Oracle Application Server TopLink API Reference.

Table 6-1 Elements for Expression Builder

Element Method Name
Constructors
ExpressionBuilder()
ExpressionBuilder(Class aClass)
Expression creation methods
get(String queryKeyName)
getAllowingNull(String queryKeyName)
anyOf(String queryKeyName)
anyOfAllowingNone(String queryKeyName)
getField(String fieldName)
in(ReportQuery subQuery)

Table 6-2 Elements for Expression

Element Method Name
Constructors Never use the Expression constructors. Always use an ExpressionBuilder to create a new expression.
Expression operators
equal(Object object)
notEqual(Object object)
greaterThan(Object object)
lessThan(Object object)
isNull()
notNull()
Logical operators
and(Expression theExpression)
not()
or(Expression theExpression)
Key word searching
equalsIgnoreCase(String theValue)
likeIgnoreCase(String theValue)
Aggregate functions (for use with report query)
minimum()
maximum()
Relationship operators
anyOf(String queryKeyName)
anyOfAllowingNone(String queryKeyName)
get(String queryKeyName)
getAllowingNull(String queryKeyName)
getField(String fieldName)

Custom SQL

The expression framework enables you to define complex queries at the object level. If your application requires a more complex query, use SQL or stored procedure calls to create custom database operations.

For more information about stored procedure calls, see "Stored Procedure Calls".

SQL Queries

You can provide a SQL string to any query instead of an expression, but the SQL string must return all data required to build an instance of the queried class. The SQL string can be a complex SQL query or a stored procedure call.

You can invoke SQL queries through the session read methods or through a read query instance.

Example 6-22 A Session Read Object Call Query With Custom SQL

Employee employee = (Employee) session.readObjectCall(Employee.class), new SQLCall("SELECT * FROM EMPLOYEE WHERE EMP_ID = 44");

Example 6-23 A Session Method with Custom SQL

This example queries user and time information.

Vector rows = session.executeSelectingCall(new SQLCall("SELECT USER, SYSDATE FROM DUAL"));

SQL Data Queries

OracleAS TopLink offers the following data-level queries to read or modify data (but not objects) in the database:

  • DataReadQuery: For reading rows of data

  • DirectReadQuery: For reading a single column of data

  • ValueReadQuery: For reading a single value of data

  • DataModifyQuery: For modifying data

Example 6-24 A Direct Read Query with SQL

This example uses SQL to read all employee IDs.

DirectReadQuery query = new DirectReadQuery();
query.setSQLString("SELECT EMP_ID FROM EMPLOYEE");
Vector ids = (Vector) session.executeQuery(query);

Example 6-25 A Data Modify Query with SQL

This example uses SQL to switch the database.

DataModifyQuery query = new DataModifyQuery();
query.setSQLString("USE SALESDATABASE");
session.executeQuery(query);

Stored Procedure Calls

You can provide a StoredProcedureCall object to any query instead of an expression or SQL string, but the procedure must return all data required to build an instance of the class you query.

Example 6-26 A Read All Query With a Stored Procedure

ReadAllQuery readAllQuery = new ReadAllQuery();
call = new StoredProcedureCall();
call.setProcedureName("Read_All_Employees");
call.useNamedCursorOutputAsResultSet("RESULT_CURSOR");
readAllQuery.setCall(call);
Vector employees = (Vector) session.executeQuery(readAllQuery);

Output Parameters

The StoredProcedureCall object allows you to use output parameters. Output parameters enable the stored procedure to return additional information. You can use output parameters to define a readObjectQuery if they return the fields required to build the object.


Note:

Not all databases support the use of output parameters to return data. However, because these databases generally support returning result sets from stored procedures, they do not require output parameters.

Example 6-27 Stored Procedure Call with an Output Parameter

StoredProcedureCall call = new StoredProcedureCall();
call.setProcedureName("CHECK_VALID_POSTAL_CODE");
call.addNamedArgument("POSTAL_CODE");
call.addNamedOutputArgument("IS_VALID", "IS_VALID", Integer.class);
ValueReadQuery query = new ValueReadQuery();
query.bindAllParameters();
query.setCall(call);
query.addArgument("POSTAL_CODE");
Vector parameters = new Vector();
parameters.addElement("L5J1H5");
Number isValid = (Number) session.executeQuery(query,parameters);

Cursor Output Parameters

Oracle databases use output parameters rather than result sets to return data from stored procedures. Cursored output parameters enable you to retrieve the result set in a cursored stream, rather than as a single result set. When you use the Oracle JDBC drivers, configure a StoredProcedureCall object to pass a cursor to OracleAS TopLink as a normal result set.

Example 6-28 Stored Procedure with a Cursored Output Parameter

StoredProcedureCall call = new StoredProcedureCall();
call.setProcedureName("READ_ALL_EMPLOYEES");
call.useNamedCursorOutputAsResultSet("RESULT_CURSOR");
ReadAllQuery query = new ReadAllQuery();
query.setReferenceClass(Employee.class);
query.setCall(call);
Vector employees = (Vector) Session.executequery(Query);

For more information about cursored streams, see "Java Streams".

Output Parameter Event

OracleAS TopLink manages output parameter events for databases that support them. For example, if a stored procedure returns an error code that indicates that the application wants to check for an error condition, OracleAS TopLink raises the session event OutputParametersDetected to allow the application to process the output parameters.

Example 6-29 Stored Procedure with Reset Set and Output Parameter Error Code

StoredProcedureCall call = new StoredProcedureCall();
call.setProcedureName("READ_EMPLOYEE");
call.addNamedArgument("EMP_ID");
call.addNamedOutputArgument("ERROR_CODE");
ReadObjectQuery query = new ReadObjectQuery();
query.setCall(call);
query.addArgument("EMP_ID");
ErrorCodeListener listener = new ErrorCodeListener();
session.getEventManager().addListener(listener);
Vector args = new Vector();
args.addElement(new Integer(44));
Employee employee = (Employee) session.executeQuery(query, args);

Reference

Table 6-3 summarizes the most common public methods for the StoredProcedureCall. For more information about the available methods for the StoredProcedureCall, see the Oracle Application Server TopLink API Reference.

Table 6-3 Elements for Stored Procedure Call

Element Method Name
Selection specification
setProcedureName(String name)
Input parameters
addNamedArgument(String name)
addNamedArgument(String dbName, String javaName)
addNamedArgumentValue(String dbName, Object value)
addUnnamedArgument(String javaName)
addUnnamedArgumentValue(Object value)
Input/Output parameters
addNamedInOutputArgument(String name)
addNamedInOutputArgument(String dbName, String javaName, String javaName, Class type)
addNamedInOutputArgumentValue(String dbName, Object value, String javaName, Class type)
public void addUnnamedInOutputArgument(String inArgumentFieldName, String outArgumentFieldName, Class type)
public void addUnnamedInOutputArgumentValue(Object inArgumentValue, String outArgumentFieldName, Class type)
Output parameters
addNamedOutputArgument(String name)
addNamedOutputArgument(String dbName, String javaName)
addNamedOutputArgument(String dbName, String javaName, Class javaType)
addUnnamedOutputArgument(String javaName)
public void addunnamedOutputArgument(String argumentFieldName, Class type)
Cursor output parameters
useNamedCursorOutputAsResultSet(String argumentName)
useUnnamedCursorOutputAsResultSet()

EJB QL

EJB QL is a query language that is similar to SQL, but differs because it presents queries from an object model perspective and includes path expressions that enable navigation over the relationships defined for entity beans and dependent objects. Although EJB QL is usually associated with Enterprise JavaBeans (EJBs), OracleAS TopLink enables you to use EJB QL with regular Java objects as well. In OracleAS TopLink, EJB QL enables users to declare queries, using the attributes of each abstract entity bean in the object model. This offers the following advantages:

  • You do not need to know the database structure (tables, fields).

  • You can use relationships in a query to provide navigation from attribute to attribute.

  • You can construct queries using the attributes of the entity beans instead of using database tables and fields.

  • EJB QL queries are portable because they are database-independent.

  • You can use SELECT to specify the query reference class (the class or entity bean you are querying against).

Using EJB QL with OracleAS TopLink

OracleAS TopLink support for EJB QL enables you to:

  • Add EJB QL queries to descriptors in OracleAS TopLink Mapping Workbench.

  • Build and use EJB QL dynamically at runtime, using a ReadQuery or the OracleAS TopLink session.

For more information about EJB QL queries with OracleAS TopLink Mapping Workbench, see the Oracle Application Server TopLink Mapping Workbench User's Guide.

ReadAllQuery

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

setEJBQLString("...")

Provide either a SELECT clause or a reference class, and execute the query normally.

Example 6-30 A Simple 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-31 A Simple ReadAllQuery Using EJB QL and Passing Arguments

This example defines the query similarly to Example 6-30, but creates, fills, and passes a vector of arguments to 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");
...
// 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);

Session

You can execute EJB QL directly against the session. This returns a vector of the objects specified by the reference class. Here is the basic API:

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

EJB QL Limitations

OracleAS TopLink supports all the EJB QL specification with the following exceptions:

  • Arithmetic functions

  • LOCATE

  • ESCAPE

  • IS [NOT] EMPTY

  • [NOT] MEMBER [OF]

Query by Example

Query by example enables you to specify queries when you provide sample instances of the persistent objects to be queried.

To define a query by example, provide a ReadObjectQuery or a ReadAllQuery with a sample persistent object instance and an optional query by example policy. The sample instance contains the data to query, and the query by example policy contains optional configuration settings, such as the operators to use and the attributes to consider or ignore.


Note:

Query by example is not available for EJB 2.0 beans.

Defining a Sample Instance

Query by example enables you to query on any attribute that uses a direct mapping or a one-to-one relationship (including those with nesting). It does not support other relationship mapping types.

By default, OracleAS TopLink ignores attributes in the sample instance that contain zero (0), empty strings, and FALSE. To modify the list of values, see "Defining a Query by Example Policy". You can use any valid constructor to create a sample instance or example object. Set only the attributes on which you base the query; set all other attributes to null.

Query by example uses the AND operator to tie the attribute comparisons together.

Example 6-32 Using Query by Example

This example queries the employee Bob Smith.

ReadObjectQuery query = new ReadObjectQuery();
Employee employee = new Employee();
employee.setFirstName("Bob");
employee.setLastName("Smith");
query.setExampleObject(employee);

Employee result = (Employee) session.executeQuery(query);

Example 6-33 Using Query by Example

This example queries across the employee's address.

ReadAllQuery query = new ReadAllQuery();
Employee employee = new Employee();
Address address = new Address();
address.setCity("Ottawa");
employee.setAddress(address);
query.setExampleObject(employee);

Vector results = (Vector) session.executeQuery(query);

Defining a Query by Example Policy

OracleAS TopLink support for query by example includes a query by example policy. You can edit the policy to modify query by example default behavior. You can modify the policy to:

  • Use LIKE or other operations to compare attributes. By default, query by example allows only EQUALS.

  • Modify the set of values query by example ignores (the IGNORE set). The default ignored values are zero (0), empty strings, and FALSE.

  • Force query by example to consider attribute values, even if the value is in the IGNORE set.

  • Use isNull or notNull for attribute values.

To specify a query by example policy, include an instance of QueryByExamplePolicy with the query.

Example 6-34 Query by Example Policy Using Like

This example uses like for Strings and includes only objects whose salary is greater than zero.

ReadAllQuery query = new ReadAllQuery();
Employee employee = new Employee();
employee.setFirstName("B%");
employee.setLastName("S%");
employee.setSalary(0);
query.setExampleObject(employee);
/* Query by example policy section adds like and greaterThan */
QueryByExamplePolicy policy = new QueryByExamplePolicy();
policy.addSpecialOperation(String.class, "like");
policy.addSpecialOperation(Integer.class, "greaterThan");
policy.alwaysIncludeAttribute(Employee.class, "salary");
query.setQueryByExamplePolicy(policy);
Vector results = (Vector) session.executeQuery(query);

Example 6-35 Query by Example Policy Using Key Words

This example uses key words for Strings and ignores -1.

ReadAllQuery query = new ReadAllQuery();
Employee employee = new Employee();
employee.setFirstName("bob joe fred");
employee.setLastName("smith mc mac");
employee.setSalary(-1);
query.setExampleObject(employee);
/* Query by example policy section */
QueryByExamplePolicy policy = new QueryByExamplePolicy();
policy.addSpecialOperation(String.class, "containsAnyKeyWords");
policy.excludeValue(-1);
query.setQueryByExamplePolicy(policy);
Vector results = (Vector) session.executeQuery(query);

Combining Query by Example with Expressions

To create more complex query by example queries, combine query by example with OracleAS TopLink expressions.

Example 6-36 Combining Query by Example with Expressions

ReadAllQuery query = new ReadAllQuery();
Employee employee = new Employee();
employee.setFirstName("Bob");
employee.setLastName("Smith");
query.setExampleObject(employee);
/* This section specifies the expression */
ExpressionBuilder builder = new ExpressionBuilder();
query.setSelectionCriteria(builder.get("salary").between(100000,200000);
Vector results = (Vector) session.executeQuery(query);

Reference

Table 6-4 summarizes the most common public methods for QueryByExample. For more information about the available methods, see the Oracle Application Server TopLink API Reference.

Table 6-4 Elements for Query By Example Policy

Element Method Name
Special operations
addSpecialOperation(Class theClass, String operation)
Forced inclusion
alwaysIncludeAttribute(java.lang.Class exampleClass, java.lang.String attributeName) 

includeAllValues()
Attribute exclusion
excludeValue(Object value)
excludeDefaultPrimitiveValues()
Null equality
setShouldUseEqualityForNulls(boolean flag)