EJB QL is expressed in terms of the abstract persistence schema of an entity bean: its abstract schema name, CMP fields, and CMR fields. EJB QL uses the abstract schema names to identify beans, the CMP fields to specify values, and the CMR fields to navigate across relationships.
To discuss EJB QL, we will make use of the relationships among the Customer, Address, CreditCard, Cruise, Ship, Reservation, and Cabin EJBs defined in Chapter 7. Figure 8-1 is a class diagram that shows the direction and cardinality (multiplicity) of the relationships among these beans.
The simplest EJB QL statement has no
WHERE
clause and only one abstract schema type.
For example, you could define a query method to select all Customer
beans:
SELECT OBJECT( c ) FROM Customer AS c
The FROM
clause determines which entity bean
types will be included in the select statement (i.e., provides the
scope
of the select). In this case, the FROM
clause
declares the type to be Customer
, which is the
abstract schema name of the Customer EJB. The AS
c
part of the clause assigns c
as the identifier of the Customer EJB. This is similar to SQL, which
allows an identifier to be associated with a table. Identifiers can
be any length and follow the same rules that are applied to field
names in the Java programming language. However, identifiers cannot
be the same as existing <ejb-name>
or
<abstract-schema-name>
values. In addition,
identification variable names are not
case-sensitive, so an identifier of customer
would
be in conflict with an abstract schema name of
Customer
. For example, the following statement is
illegal because Customer
is the abstract schema
name of the Customer EJB:
SELECT OBJECT( customer ) FROM Customer AS customer
The
AS
operator is optional (its assumed) and is used
in many, but not all, of the examples in this chapter. The following two
statements are equivalent:
SELECT OBJECT(c) FROM Customer AS c SELECT OBJECT(c) FROM Customer c
The SELECT
clause determines the type of values
that will be returned. In this case, it’s the Customer entity
bean, as indicated by the c
identifier.
The OBJECT()
operator is required when the
SELECT
type is a solitary identifier for an entity
bean. The reason for this requirement is pretty vague (and in the
author’s opinion, the specification would have been better off
without it), but it is required whenever the
SELECT
type is an entity bean identifier. The
OBJECT()
operator is not used if the
SELECT
type is expressed using a
path, which is discussed below.
EJB QL allows SELECT
clauses to return any CMP or single CMR field. For example, we can
define a simple select statement to return the last names of all of
Titan’s customers, as follows:
SELECT c.lastName FROM Customer AS c
The SELECT
clause uses a simple path to select the
Customer EJB’s lastName
CMP field as the
return type. EJB QL uses the CMP and CMR field names declared in
<cmp-field>
and
<cmr-field>
elements of the deployment
descriptor. This navigation leverages the same syntax as the Java
programming language, specifically the dot (.) navigation operator.
For example, the previous EJB QL statement is based on the Customer
EJB’s deployment descriptor:
<ejb-jar> <enterprise-beans> <entity> <ejb-name>CustomerEJB</ejb-name> <home>com.titan.customer.CustomerHomeRemote</home> <remote>com.titan.customer.CustomerRemote</remote> <ejb-class>com.titan.customer.CustomerBean</ejb-class> <persistence-type>Container</persistence-type> <prim-key-class>java.lang.Integer</prim-key-class> <reentrant>False</reentrant><abstract-schema-name>Customer</abstract-schema-name>
<cmp-version>2.x</cmp-version> <cmp-field><field-name>id</field-name></cmp-field><cmp-field><field-name>lastName</field-name></cmp-field>
<cmp-field><field-name>firstName</field-name></cmp-field>
You can also use CMR field types in simple select statements. For example, the following EJB QL statement selects all the CreditCard EJBs from all the Customer EJBs:
SELECT c.creditCard FROM Customer c
In this case, the EJB QL statement uses a path to navigate from the
Customer EJBs to their creditCard
relationship
fields. The creditCard
identifier is obtained from
the <cmr-field>
name used in the
relationship element that describes the Customer-CreditCard
relationship:
<enterprise-beans> <entity> <ejb-name>CustomerEJB
</ejb-name> ...<abstract-schema-name>Customer</abstract-schema-name>
</entity> </enterprise-beans> ... <relationships> <ejb-relation> <ejb-relation-name>Customer-CreditCard</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> Customer-has-a-CreditCard </ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>CustomerEJB
</ejb-name> </relationship-role-source><cmr-field>
<cmr-field-name>creditCard</cmr-field-name>
</cmr-field>
</ejb-relationship-role> <ejb-relationship-role> ...
Paths can be as long as required. It’s common to use paths that
navigate over one or more CMR fields to end at either a CMR or CMP
field. For example, the following EJB QL statement selects all the
city
CMP fields of all the Address EJBs in each
Customer EJB:
SELECT c.homeAddress.city FROM Customer c
In this case, the path uses the abstract schema name of the Customer
EJB, the Customer EJB’s homeAddress
CMR
field, and the Address EJB’s city
CMP field.
Using paths in EJB QL is similar to navigating through object
references in the Java language.
To illustrate more complex paths, we’ll need to expand the class diagram. Figure 8-2 shows that the CreditCard EJB is related to a CreditCompany EJB that has its own Address EJB.
Using these relationships, we can specify a more complex path that navigates from the Customer EJB to the CreditCompany EJB to the Address EJB. The following EJB QL statement selects all the addresses of all the credit card companies:
SELECT c.creditCard.creditCompany.address FROM Customer AS c
The EJB QL statement could also navigate all the way to the Address bean’s CMP fields. For example, the following statement selects all the cities in which the credit card companies that distribute credit cards used by Titan’s customers are based:
SELECT c.creditCard.creditCompany.address.city FROM Customer AS c
Note that these EJB QL statements return address
CMR fields or city
CMP fields only for those
credit card companies responsible for cards owned by Titan’s
customers. The address information of any credit card companies whose
cards are not currently used by Titan’s customers won’t
be included in the results.
Paths cannot navigate beyond CMP fields. For example, imagine that
the Address EJB uses a ZipCode
class as its
zip
CMP field:
public class ZipCode implements java.io.Serializable { public int mainCode; public int codeSuffix; ... }
It would be illegal to attempt to navigate to one of the
ZipCode
class’s instance fields:
// this is illegal
SELECT c.homeAddress.zip.mainCode
FROM Customer AS c
CMP fields cannot be further decomposed and navigated by paths. All CMP fields are considered opaque.
The paths used in SELECT clauses of EJB QL statements must always end
with a single type. They may not end with a
collection-based relationship field. For
example, the following is not legal because the CMR field
reservations
is a collection-based relationship
field:
// this is illegal SELECT c.reservations FROM Customer AS c
In fact, it’s illegal to navigate across a collection-based relationship field. The following EJB QL statement is also illegal, even though the path ends in a single-type relationship field:
SELECT c.reservations.cruise FROM Customer AS c
If you think about it, this limitation makes sense. You cannot use a
navigation operator (.) in Java to access elements of a
java.util.Collection
object either. For example,
you cannot do the following (assume
getReservations()
returns a
java.util.Collection
type):
// this is illegal in the Java programming language customer.getReservations().getCruise();
Referencing the elements of a collection-based relationship field is
possible in EJB QL, but it requires the use of an
IN
operator and an identification assignment in
the FROM
clause, which are discussed next.
Many relationships between entity beans
are
collection-based, and being able to
access and select from these relationships is important. We’ve
seen that it is illegal to select elements directly from a
collection-based relationship. To overcome this limitation, EJB QL
introduces the IN
operator, which allows an
identifier to represent individual elements in a collection-based
relationship field.
The following query uses the IN
operator to select
the elements from a collection-based relationship. It returns all the
reservations of all the customers:
SELECT OBJECT( r )
FROM Customer AS c, IN( c.reservations ) AS r
The IN
operator assigns the individual elements in
the reservations
CMR field to the identifier
r
. Once we have an identifier to represent the
individual elements of the collection, we can reference them directly
and even select them in the EJB QL statement. We can also use the
element identifier in path expressions. For example, the following
EJB QL statement will select every cruise for which Titan’s
customers have made reservations:
SELECT r.cruise
FROM Customer AS c, IN( c.reservations ) AS r
The identifiers assigned in the FROM
clause are
evaluated from left to right. Once you declare an identifier, you can
use it in subsequent declarations in the FROM
clause. Notice that the identifier c
, which was
declared first, was subsequently used in the IN
operator to define the identifier r
.
The OBJECT()
operator is used for single
identifiers in the select statement and not for path expressions.
While this convention makes little sense, it is nonetheless required
by the EJB 2.0 specification. As a rule of thumb, if the select type
is a solitary identifier of an entity bean, it must be wrapped in an
OBJECT()
operator. If the select type is a path
expression, this is not necessary.
Identification chains, in which subsequent identifications depend on
previous identifications, can become very long. The following EJB QL
statement uses two IN
operators to navigate two
collection-based relationships and a single CMR relationship. While
not necessarily useful, this statement demonstrates how a query can
use IN
operators across many relationships:
SELECT cbn.ship FROM Customer AS c, IN ( c.reservations ) AS r, IN( r.cabins ) AS cbn
Please refer to Workbook Exercise 8.1, Simple EJB QL Statements. This workbook is available free, in PDF format, at http://www.oreilly.com/catalog/entjbeans3/workbooks.
The DISTINCT
keyword ensures that the query does not
return
duplicates. This
is especially valuable when applied to EJB QL statements used by find
methods. Find methods in CMP 2.0 have only one return type,
java.util.Collection
, which may return duplicates.
However, if the keyword DISTINCT
is used, the
query results of the find method will not contain duplicates.
For example, the following find method and its associated query will return duplicates:
// the find method declared in the remote or local home interface public java.util.Collection findAllCustomersWithReservations() // the EJB QL statement associated with the find method SELECT OBJECT( cust ) FROM Reservation res, IN (res.customers) cust
The previous find method and associated EJB QL statement will return
all Customer EJBs with reservations, but if a Customer EJB has more
than one reservation, there will be duplicate references to that
Customer EJB in the result Collection
. Using the
DISTINCT
keyword will ensure that each Customer
EJB is represented only once in the result
Collection
:
SELECT DISTINCT OBJECT( cust ) FROM Reservation res, IN (res.customers) cust
The DISTINCT
keyword can also be used with
select methods. It works the same
way for select methods that have a return type of
Collection
. If the select method’s return
type is java.util.Set
, the distinct (no
duplicates) result will be returned whether the
DISTINCT
keyword is used or not.
The Set
type is explicitly defined as having no
duplicates. Using the Set
return type in
combination with the DISTINCT
keyword is
redundant, but it is not illegal.
You can also use
literal values in
EJB QL to narrow the scope of the elements selected. This is
accomplished through the WHERE
clause, which
behaves in much the same way as the WHERE
clause
in SQL.
For example, you could define an EJB QL statement to select all the
Customer EJBs that use a specific brand of credit card. The literal
in this case is a String
literal. Literal strings
are enclosed by single quotes. Literal values that include a single
quote, like the restaurant name “Wendy’s,” use two
single quotes to escape the quote: 'Wendy''s'
. The
following statement returns customers that use the American Express
credit card:
SELECT OBJECT( c ) FROM Customer AS c
WHERE c.creditCard.organization = 'American Express'
Path expressions are always used in the WHERE
clause in the same way they’re used in the
SELECT
clause. When making comparisons with a
literal, the path expression must evaluate to a CMP field; you
can’t compare a CMR field with a literal.
In addition to literal strings, literals can be exact numeric values
(long
types) and approximate numeric values
(double
types). Exact numeric literal values are
expressed using the Java integer literal syntax
(321
, -8932
,
+22
). Approximate numeric literal values are
expressed using Java floating point literal syntax in scientific
(5E3
, -8.932E5
) or decimal
(5.234
, 38282.2
) notation.
For example, the following EJB QL statement selects all the ships that weigh 100,000.00 metric tons:
SELECT OBJECT( s )
FROM Ship AS s
WHERE s.tonnage = 100000.00
Boolean literal values use TRUE
and
FALSE
. Here’s an EJB QL statement that
selects all the customers who have good credit:
SELECT OBJECT( c ) FROM Customer AS c
WHERE c.hasGoodCredit = TRUE
Query methods (find and select methods) that use EJB QL statements
may specify
method arguments.
Input parameters
allow those method arguments to be mapped to EJB QL statements and
are used to narrow the scope of the query. For example, the
ejbSelectByCity()
method is designed to select all the
customers that reside in a particular city and state:
public abstract class CustomerBean implements javax.ejb.EntityBean { ... public abstract Collection ejbSelectByCity(String city,String state) throws FinderException; ... }
The EJB QL statement for this method would use the
city
and state
arguments as
input parameters:
SELECT OBJECT( c ) FROM Customer AS c WHERE c.homeAddress.state =?2
AND c.homeAddress.city =?1
Input parameters use a ?
prefix followed by the
argument’s position, in order of the query method’s
parameters. In this case, city
is the first
argument listed in the ejbSelectByCity()
method
and state
is the second. When a query method
declares one or more arguments, the associated EJB QL statement may
use some or all of the arguments as input parameters.
Input parameters are not limited to simple CMP field types; they can
also be EJB object references. For example, the following find
method, findByShip()
, is declared in the Cruise
bean’s local home interface:
public interface CruiseLocalHome extends javax.ejb.EJBLocalHome { public Collection findByShip( ShipLocal ship ) throws FinderException; }
The EJB QL statement associated with this method would use the
ship
argument to locate all the cruises scheduled
for the specified Ship bean:
SELECT OBJECT( crs ) FROM Cruise AS crs
WHERE crs.ship = ?1
When an EJB object is used as an input parameter, the container bases the comparison on the primary key of the EJB object. In this case, it searches through all the Cruise EJBs looking for references to a Ship EJB with the same primary key value as the one the Ship EJB passed to the query method.
The
WHERE
clause is composed
of conditional expressions that reduce the scope of the query and
limit the number of items selected. Several conditional and logical
operators can be used in expressions; they are listed below in order
of precedence. The operators at the top of the list have the highest
precedence and are evaluated first:
EJB QL statements are declared in XML deployment descriptors. XML uses the greater than (>) and less than (<) characters as delimiters for tags, so using these symbols in the EJB QL statements will cause parsing errors unless CDATA sections are used. For example, the following EJB QL statement causes a parsing error, because the XML parser interprets the > symbol as an incorrectly placed XML tag delimiter:
<query>
<query-method>
<method-name>findWithPaymentGreaterThan</method-name>
<method-params>
<method-param>java.lang.Double</method-param>
</method-params>
</query-method>
<ejb-ql>
SELECT OBJECT( r ) FROM Reservation r
WHERE r.amountPaid >
?1
</ejb-ql>
</query>
To avoid this problem, you must place the EJB QL statement in a CDATA section:
<query> <query-method> <method-name>findWithPaymentGreaterThan</method-name> <method-params> <method-param>java.lang.Double</method-param> </method-params> </query-method> <ejb-ql><![CDATA[
SELECT OBJECT( r ) FROM Reservation r WHERE r.amountPaid>
300.00]]>
</ejb-ql> </query>
The CDATA section takes the form <![CDATA[
literal-text
]]>
.
When an XML processor encounters a CDATA section, it doesn’t
attempt to parse the contents enclosed by the CDATA section; instead,
the parser treats the contents as literal text.[33]
The arithmetic operators allow a query to
perform arithmetic in the process of doing a comparison. In EJB QL,
arithmetic operators can be used only in the WHERE
clause, not in the SELECT
clause.
The following EJB QL statement returns references to all the Reservation EJBs that will be charged a port tax of more than $300.00:
SELECT OBJECT( r ) FROM Reservation r
WHERE (r.amountPaid * .01
) > 300.00
The rules applied to arithmetic operations are the same as those used
in the Java programming language, where numbers are
widened or promoted in the
process of performing a calculation. For example, multiplying a
double
and an int
value
requires that the int
first be promoted to a
double
value. (The result will always be that of
the widest type used in the calculation, so multiplying an
int
and a double
results in a
double
value.)
String
, boolean
, and EJB object
types cannot be used in arithmetic operations. For example, using the
addition operator with two String
values is
considered an illegal operation. There is a special function for
concatenating String
values, which is covered later
in Section 8.3.19.
Logical
operators such as
AND
,
OR
, and NOT
operate
the same way in EJB QL as their corresponding logical operators in
SQL.
Logical operators evaluate only Boolean expressions, so each operand
(i.e., each side of the expression) must evaluate to
true
or false
. Logical
operators have the lowest precedence so that all the expressions can
be evaluated before they are applied.
The AND
and OR
operators may
not, however,behave like their Java language
counterparts &&
and ||
.
EJB QL does not specify whether the righthand operands are evaluated
conditionally. For example, the &&
operator in Java evaluates its righthand operand
only if the lefthand operand is
true
. Similarly, the ||
logical
operator evaluates the righthand operand only if
the lefthand operand is false
. We can’t make
the same assumption for the AND
and
OR
operators in EJB QL. Whether these operators
evaluate righthand operands depends on the native query language into
which the statements are translated. It’s best to assume that
both operands are evaluated on all logical operators.
NOT
simply reverses the Boolean result of its
operand; expressions that evaluate to the Boolean value of
true
become false
, and vice
versa.
Comparison
operators, which use the symbols
=,
>, >=,
<, <=, and
<>, should be familiar to you.
The following statement selects all the Ship EJBs whose
tonnage
CMP field is greater than or equal to
80,000 tons but less than or equal to 130,000 tons:
SELECT OBJECT( s ) FROM Ship s WHERE s.tonnage >= 80000.00 AND s.tonnage <= 130000.00
Only the = and <> (not equal) operators may be used on
String
, boolean
, and EJB object
references. The greater-than and less-than symbols (>, >=,
<, <=) can be used only on numeric values. It would be illegal,
for example, to use the greater-than or less-than symbols to compare
two String
s. There is no mechanism to compare
String
s in this way in EJB QL.
While
it’s legal to compare an exact numeric value
(short
, int
,
long
) to an approximate numeric value
(double
, float
), all other
equality comparisons must compare the same types. You cannot, for
example, compare a String
value of
123
to the Integer
literal
123
. However, you can compare two
String
types for equality.
You can also compare EJB objects for equality, but these too must be of the same type. To be more specific, they must both be EJB object references to beans from the same deployment. As an example, the following method finds all the Reservation EJBs made by a specific Customer EJB:
public interface ReservationHomeLocal extends EJBLocalHome { public Collection findByCustomer(CustomerLocal customer) throws FinderException; ... }
The matching EJB QL statement uses the customer
argument as an input parameter:
SELECT OBJECT( r ) FROM Reservation r, IN ( r.customers ) cust WHERE cust = ?1
It’s not enough for the EJB object used in the comparison to
implement the CustomerLocal
interface; it must be
of the same bean type as the Customer EJB used in the
Reservation’s customers
CMR field. In other
words, they must be from the same deployment. Once it’s
determined that the bean is the correct type, the actual comparison
is performed on the beans’ primary keys. If they have the same
primary key, they are considered equal.
You cannot use java.util.Date
objects in equality
comparisons. To compare dates you must use the
long
millisecond value of the date, which means
that the date must be persisted in a long
CMP
field and not a java.util.Date
CMP field. The
input value or literal must also be a long
value.
The
BETWEEN
clause is an
inclusive operator specifying a range of values. In this example, we
use it to select all ships weighing between 80,000 and 130,000 tons:
SELECT OBJECT( s ) FROM Ship s
WHERE s.tonnage BETWEEN
80000.00 AND 130000.00
The BETWEEN
clause may be used only on numeric
primitives (byte
, short
,
int
, long
,
double
, float
) and their
corresponding java.lang.Number
types
(Byte
, Short
,
Integer
, etc.). It cannot be used on
String
, boolean
, or EJB object
references.
Using the NOT
logical operator in conjunction with
BETWEEN
excludes the range specified. For example,
the following EJB QL statement selects all the ships that weigh less
than 80,000 tons or greater than 130,000 tons but excludes everything
in between:
SELECT OBJECT( s ) FROM Ship s
WHERE s.tonnage NOT BETWEEN
80000.00 AND 130000.00
The net effect of this query is the same as if it had been executed with comparative symbols, like this:
SELECT OBJECT( s ) FROM Ship s WHERE s.tonnage < 80000.00 OR s.tonnage > 130000.00
The
IN
conditional operator
used in the WHERE
clause is not the same as the
IN
operator used in the FROM
clause. In the WHERE
clause, IN
tests for membership in a list of literal string values and can be
used only with operands that evaluate to string values. For example,
the following EJB QL statement uses the IN
operator to select all the customers who reside in a specific set of
states:
SELECT OBJECT( c ) FROM Customer c
WHERE c.homeAddress.state IN
('FL', 'TX', 'MI', 'WI', 'MN')
Applying the NOT
operator to this expression
reverses the selection, excluding all customers who reside in the
list of states:
SELECT OBJECT( c ) FROM Customer c
WHERE c.homeAddress.city NOT IN
('FL', 'TX', 'MI', 'WI', 'MN')
If the field tested is null
, the value of the
expression is “unknown”, which means it cannot be
predicted.
The
IS NULL
comparison
operator allows you to test whether a path expression is
null
. For example, the following EJB QL statement
selects all the customers who do not have home addresses:
SELECT OBJECT( c ) FROM Customer c
WHERE c.homeAddress IS NULL
Using the NOT
logical operator, we can reverse the
results of this query, selecting all the customers who do have home
addresses:
SELECT OBJECT( c ) FROM Customer c
WHERE c.homeAddress IS NOT NULL
When null
fields appear in comparison operations
such as IN
and BETWEEN
, they
can have side effects. In most cases, evaluating a
null
field in a comparison operation (other than
IS
NULL
) produces in an
UNKNOWN
result. Unknown evaluations throw the
entire EJB QL result set into question; since we cannot predict the
outcome of the EJB QL statement, it is unreliable. One way to avoid
this situation is to require that fields used in the expressions have
values. This requires careful programming. To ensure that an entity
bean field is never null
, you must initialize the
field when the entity is created. For primitive values, this not a
problem; they have default values, so they cannot be
null
. Other fields, such as single CMR fields and
object-based CMP fields such as String
, must be
initialized in the ejbCreate()
and
ejbPostCreate()
methods.
The
IS
EMPTY
operator allows the query to test if a
collection-based
relationship is empty. Remember from Chapter 7
that a collection-based relationship will never be
null
. If a collection-based relationship field has
no elements, it will return an empty Collection
or
Set
.
Testing whether a collection-based relationship is empty has the same
purpose as testing whether a single CMR field or CMP field is
null
: it can be used to limit the scope of the
query and items selected. For example, the following query selects
all the cruises that have not booked any reservations:
SELECT OBJECT( crs ) FROM Cruise crs
WHERE crs.reservations IS EMPTY
The NOT
operator reverses the result of
IS
EMPTY
. The following query
selects all the cruises that have at least one reservation:
SELECT OBJECT( crs ) FROM Cruise crs
WHERE crs.reservations IS NOT EMPTY
It is illegal to use IS
EMPTY
against collection-based relationships that have been assigned an
identifier in the FROM
clause:
// illegal query
SELECT OBJECT( r )
FROM Reservation r, IN( r.customers ) c
WHERE
r.customers IS NOT EMPTY AND
c.address.city = 'Boston'
While this query appears to be good insurance against
UNKNOWN
results, it’s not. In fact,
it’s an illegal EJB QL statement, because the
IS
EMPTY
operator cannot be
used on a collection-based relationship identified in an
IN
operator in the FROM
clause.
Because the relationship is specified in the IN
clause, only those Reservation EJBs that have a nonempty
customers
field will be included in the query; any
Reservation EJB that has an empty CMR field will be excluded because
its customers
elements cannot be assigned the
c
identifier.
The
MEMBER
OF
operator is a powerful tool for determining
whether an EJB object is a member of a specific
collection-based relationship.
The following query determines whether a particular Customer
(specified by the input parameter) is a member of any of the
Reservation-Customer relationships:
SELECT OBJECT( crs )
FROM Cruise crs, IN (crs.reservations) res, Customer cust
WHERE
cust = ?1
AND
cust MEMBER OF
res.customers
Applying the NOT
operator to MEMBER OF
has the reverse effect, selecting all the cruises on
which the specified customer does not have a reservation:
SELECT OBJECT( crs )
FROM Cruise crs, IN (crs.reservations) res, Customer cust
WHERE
cust = ?1
AND
cust NOT MEMBER OF
res.customers
Checking whether an EJB object is a member of an empty collection
always returns false
.
The
LIKE
comparison
operator allows the query to select String
type
CMP fields that match a specified pattern. For example, the following
EJB QL statement selects all the customers with hyphenated names,
like “Monson-Haefel” and “Berners-Lee”:
SELECT OBJECT( c ) FROM Customer c WHERE c.lastName LIKE '%-%'
You can use two special characters when establishing a comparison
pattern: %
(percent) stands for any sequence of
characters, and
_
(underscore) stands
for any single character. You can use %
and
_
characters at any location within a string
pattern. If a %
or _
actually
occurs in the string, you can escape it with the
character. The NOT
logical operator reverses the
evaluation so that matching patterns are
excluded.
The following examples show how the LIKE clause would evaluate
String
type CMP fields:
phone.number LIKE '617%'
True for “617-322-4151” |
False for “415-222-3523” |
cabin.name LIKE 'Suite _100'
True for “Suite A100” |
False for “Suite A233” |
phone.number NOT LIKE '608%'
True for “415-222-3523” |
False for “608-233-8484” |
someField.underscored LIKE '\_%'
True for “_xyz” |
False for “abc” |
someField.percentage LIKE '\%%'
True for “% XYZ” |
False for “ABC” |
The LIKE
operator cannot be
used with input parameters. This is an important
point that is confusing to many new EJB developers. The
LIKE
operator compares a String
type CMP field to a String
literal. As it is
currently defined, it cannot be used in a comparison with an input
parameter, because an input parameter is, by definition, unknown
until the method is invoked. Only the input parameter’s type is
known at deployment time. How would you compare a CMP field, whose
value varies, with an arbitrary input parameter using a comparison
pattern? It’s just not possible. The comparison pattern is
composed of special comparison characters (% and _ ) as well as
regular characters. The comparison pattern must be known at
deployment time in order to match it against the variable CMP fields
at runtime.
EJB QL has six functional expressions that allow for
simple String
manipulation and two basic numeric
operations. The String
functions are:
CONCAT(String1, String2)
Returns the String
that results from concatenating
String1
and String2
.
LENGTH(String)
Returns an int
indicating the length of the string.
LOCATE(String1, String2 [, start])
Returns an int
indicating the position at which
String1
is found within
String2
. If it’s present,
start
indicates the character position in
String2
at which the search should start.
SUBSTRING(String1, start, length)
Returns the String
consisting of length characters
taken from String1
, starting at the position given
by start
.
The start
and
length
parameters indicate positions in a
String
as integer values. You can use these
expressions in the WHERE
clause to help refine the
scope of the items selected. Here is an example of how the
LOCATE
and LENGTH
functions
might be used:
SELECT OBJECT( c ) FROM Customer c WHERELENGTH(c.lastName)
> 6 ANDLOCATE( c.lastName, 'Monson')
> -1
This EJB QL statement selects all the customers with
Monson
somewhere in their last name, but specifies
that the name must be longer than 6 characters. Therefore,
“Monson-Haefel” and “Monson-Ares” evaluate to
true
, but “Monson” returns
false
because it has only 6 characters.
The arithmetic functions in EJB QL are:
Please refer to Workbook Exercise 8.2, Complex EJB QL Statements. This workbook is available free, in PDF format, at http://www.oreilly.com/catalog/entjbeans3/workbooks.
[33] To learn more about XML and the use of CDATA sections, see XML in a Nutshell by Elliotte Rusty Harold and W. Scott Means (O’Reilly).