第8章 EJB查询语言
Dale Green著
Iceshape Zeng译
企业JavaBean查询语言(EJB QL)定义CMP的查找和Select方法的查询动作。EJB QL在SQL92子集的基础上作了一些扩展,以允许在实体Bean抽象模式中定义的关系上定义查询,它的查询范围跨越同一个EJB
JAR文件中的关联实体Bean的抽象模式。
EJB QL查询在实体Bean的部署描述符中被定义,通常部署工具会将这些查询转化为底层数据库可执行的目标SQL语句。因此CMP实体Bean有更好的可移植性——它的代码不依赖于特定的底层数据库实现。
本章的例子沿用第6章使用的例子。
本章内容:
术语
简单语法
查询例子
简单查找方法的查询
跨越实体Bean关系查找方法的查询
其它条件查找方法的查询
Select方法的查询
全部语法
BNF范式
EJB QL的BNF文法
FROM子句
Path表达式
WHERE子句
SELECT子句
EJB QL的限制
一.术语
下面列了本章用到的术语:
☆ 抽象模式(Abstract schema):实体Bean部署描述符的一部分,定义持久性子段和关系子段
☆ 抽象模式名(Abstract schema name):EJB QL中引用的逻辑名字,每一个CMP实体Bean指定一个唯一的抽象模式名
☆ 抽象模式类型(Abstract schema type):所有的EJB QL表达式都归结到一定的类型。如果一个表达式是抽象模式名,缺省地它的类型是定义这个抽象模式名的实体Bean的Local接口。
☆ BNF范式(Backus-Naur Form):描述高级语言语法的符号。本章的语法都用BNF范式表示。
☆ 关联查询(Navigation):在EJB QL表达式中跨越关系查询。关联操作符是一个句点
☆ Path表达式(Path expression):一个可以根据路径找到关系实体Bean的表达式
☆ 持久性字段(Persistent field):CMP实体Bean中的一个虚拟字段,它存储在数据库中。
☆ 关系字段(Relationship field):CMP实体Bean中的一个虚拟字段,它标志关系的另一方实体Bean。
二.简单语法
本节简要的描述EJB QL的语法一遍你可以进入下一节查询例子。如果想全面了解语法可以转到第三节全部语法。
一个EJB QL查询有三个子句:SELECT、FROM和WHERE。SELECT和FROM子句是必需的,WHERE子句可选。下面是一个符合高级BNF范式语法的EJB
QL查询:
EJB QL ::= select_clause from_clause [where_clause]
SELECT子句定义查询返回的对象或者值,返回类型是一下上种之一:Local接口、Remote接口和持久性字段。
FROM子句声明一个或多个同位变量来定义查询范围,这些变量会在SELECT和WHERE子句中被引用。一个同位变量表示一下元素之一:
☆ 实体Bean的抽象模式名
☆ 一个一对多关系中“多”方的集合成员
WHERE子句是约束查询返回对象和值的条件表达式。虽然可选但是大部分查询都有一个WHERE子句。
三.查询例子
本节用到的例子都来自第6章的RosterApp应用程序的PlayerEJB实体Bean。要查看RosterApp中个企业Bean之间的关系参考图6-1。
简单查找方法的查询
如果你不熟悉EJB QL语言,下面的简单查询将是一个很好的开始:
例1:
SELECT OBJECT(p)
FROM Player p
查询结果:所有的运动员
对应查找方法:findall()
解释:FROM子句声明一个同位变量p,省略可选关键字AS。上面语句的FROM子句也可以写成:
FROM Player AS p
元素Player是PlayerEJB的抽象模式名。因为findall方法在LocalPlayerHome接口中定义,所以这个查询返回LocalPlayer类型的对象。
关于同位变量的更多信息参考下一节。
例2:
SELECT DISTINCT OBJECT(p)
FROM Player p
WHERE p.position = ?1
查询结果:位置等于查找方法传入的位置参数运动员。
查找方法:findByPosition(String position)
解释:在SELECT子句中,OBJECT关键字必须在像p这样的一个单独的同位变量前。
DISTINCT关键字过滤调重复的数据。
WHERE子句检查找到的运动员的位置来约束返回结果。?1表示findByPosition方法的参数。
关于传入参数、DISTINCT关键字和OBJECT关键字的详细信息参考下一节。
例3:
SELECT DISTINCT OBJECT(p)
FROM Player p
WHERE p.position = ?1 AND p.name = ?2
返回结果:在给定位置并且叫给定名字的运动员
查找方法:findByPositionAndName(String position,String name)
解释:position和name都是PlayerEJB的持久性字段。WHERE子句比较这两个字段和findByPositionAndName方法的传入参数。EJB
QL用一个问号后跟一个整数来表示方法的传入参数。第一个参数表示为:?1,第二个参数表示成:?2,以此类推。
跨越实体Bean关系查找方法的查询(关联查询)
在EJB QL语言中,一个表达式可以跨越实体Bean关系的另一方进行查询。这些表达式是EJB QL和SQL之间的主要区别,EJB QL跨越关联的实体Bean,而SQL连接多个表。
例4:
SELECT DISTINCT OBJECT(p)
FROM Player p, IN (p.teams) AS t
WHERE t.city = ?1
返回结果:属于在指定城市的组的运动员
查找方法:findByCity(String city)
解释:FROM子句声明了两个同位变量:p和t。p跟Player同义,表示PlayerEJB实体Bean。t表示关系中的另一方TeamEJB。t的声明引用了前面声明的p。IN关键字表明teams是一个TeamEJB的集合。p.teams表达式关联PlayerEJB和TeamEJB,表达式中的句点是关联操作。
在WHERE子句中,city前的句点是一个限定符,不是关联操作符。严格来讲,关联表达式只能使用关系字段,不能使用持久性字段。访问持久性字段时,表达式中的句点作为限定符使用。
关联表达式不可以越过(或更严格的限定)集合类型的关联字段。在表达式的语法中,一个集合值字段是一个终结符。因为teams字段是集合类型,在WHERE子句中不能写成p.teams.city,这是非法的表达式。
详细描述参考下一节的路径表达式。
例5
SELECT DISTINCT OBJECT(p)
FROM Player p, IN (p.teams) AS t
WHERE t.league = ?1
返回结果:属于特定社团(league)的所有运动员。
查找方法:findByLeague(LocalLeague league)
解释:这个查询跨越了两个关系。p.teams跨越PlayerEJB-TeamEJB关系,t.league跨越TeamEJB-LeagueEJB关系。
在其他例子中,传入参数都是String对象,而这个例子的参数是LocalLeague接口类型,它在WHERE的比较表达式中匹配league关系字段。
例6
SELECT DISTINCT OBJECT(p)
FROM Player p, IN (p.teams) AS t
WHERE t.league.sport = ?1
返回结果:参加了指定运动项目的运动员
查找方法:findBySport(String sport)
解释:sport是LeagueEJB的持久性字段。要访问sport字段,查询必须先关联PlayerEJB到TeamEJB(p.teams)然后关联TeamEJB到LeagueEJB(t.league)。因为league关系字段不是集合类型,它可以在后面接sport持久性字段。
其它条件查找方法的查询
每一个WHERE子句都必须指定一个条件表达式,这样的条件表达式有很多种。在前面的例子中,条件表达式都是检查相等的比较表达式。下面会给出一些其他类型的条件表达式。关于条件表达式的详尽描述请参考下一节的WHERE子句内容。
例7
SELECT OBJECT(p)
FROM Player p
WHERE p.teams IS EMPTY
返回结果:不属于任何组的所有运动员
查找方法:findNotOnTeam()
解释:PlayerEJB的关系字段teams是集合类型,如果运动员不属于任何组,则teams集合为空,而条件表达式返回TRUE。参考下一节的空集合比较表达式
例8
SELECT DISTINCT OBJECT(p)
FROM Player p
WHERE p.salary BETWEEN ?1 AND ?2
返回结果:薪水在指定范围内的运动员
查找方法:findBySalaryRange(double low,double high)
解释:BETWEEN表达式中有三个数学表达式:一个持久性字段(p.salary)和两个传入参数(?1和?2)。可以用下面的表达式替换BETWEEN表达式:
p.salary >= ?1 AND p.salary <= ?2
参考下一节的BETWEEN表达式。
例9
SELECT DISTINCT OBJECT(p1)
FROM Player p1, Player p2
WHERE p1.salary > p2.salary AND p2.name = ?1
返回结果:返回薪水高于指定名字的运动员的所有运动员
查找方法:findByHigherSalary(String name)
解释:FROM子句声明了Player类型的两个同位变量(p1和p2)。因为WHERE子句需要比较两个运动员(p1和p2)的薪水,所以这里需要两个同为变量。(实际上就是自连接查询)。参考下一节同位变量。
Select方法的查询
下面的例子是Select方法的查询,和查找方法不同,Select方法可以返回持久性字段和其他实体Bean。
例10
SELECT DISTINCT t.league
FROM Player p, IN (p.teams) AS t
WHERE p = ?1
返回结果:指定运动员加入的所有社团
Select方法:ejbSelectLeagues(LocalPlayer player)
解释:该查询的返回类型是LeagueEJB实体Bean的抽象模式,该抽象模式映射到LocalLeagueHome接口。因为t.league不是一个单独的同为变量,所以OBJECT关键字省略。参考下一节SELECT子句。
例11
SELECT DISTINCT t.league.sport
FROM Player p, IN (p.teams) AS t
WHERE p = ?1
返回结果:指定运动员参与的所有运动项目
Select方法:ejbSelectSports(LocalPlayer player
解释:该查询返回LeagueEJB的持久性字段sport的集合。
四.全部语法
本节讨论EJB规范定义的EJB QL语法。下面的大部分资料解释规范,有些还是直接引用规范的内容。
BNF范式
表8-1列出了本章用到的BNF符号
|
表8-1 BNF符号
|
|
符号
|
解释
|
|
::=
|
左边的元素由右边的元素构造
|
|
*
|
该符号前面的元素可以出现0或多次
|
|
{...}
|
花括号里的元素是同种语义效果
|
|
[...]
|
方括号里的元素是可选的
|
|
|
|
左右两个表达式任选其一(或的意思)
|
|
粗体单词
|
关键字(尽管它们都大写,实际上关键字是大小写不敏感的)
|
|
空白
|
可能是空格,退格或者接续行
|
EJB QL语法的BNF定义
下面是这些语法的定义:
EJB QL ::= select_clause from_clause [where_clause]
from_clause ::= FROM identification_variable_declaration
[,
identification_variable_declaration]*
identification_variable_declaration ::=
collection_member_declaration |
range_variable_declaration
collection_member_declaration ::=
IN (collection_valued_path_expression) [AS] identifier
range_variable_declaration ::=
abstract_schema_name [AS]
identifier
single_valued_path_expression ::=
{single_valued_navigation |
identification_variable}.cmp_field |
single_valued_navigation
single_valued_navigation ::=
identification_variable.[single_valued_cmr_field.]*
single_valued_cmr_field
collection_valued_path_expression ::=
identification_variable.[single_valued_cmr_field.]*
collection_valued_cmr_field
select_clause ::= SELECT [DISTINCT]
{single_valued_path_expression |
OBJECT(identification_variable)}
where_clause ::= WHERE conditional_expression
conditional_expression ::= conditional_term |
conditional_expression OR
conditional_term
conditional_term ::= conditional_factor |
conditional_term AND
conditional_factor
conditional_factor ::= [ NOT ] conditional_test
conditional_test ::= conditional_primary
conditional_primary ::=
simple_cond_expression |
(conditional_expression)
simple_cond_expression ::=
comparison_expression |
between_expression |
like_expression |
in_expression |
null_comparison_expression
|
empty_collection_comparison_expression |
collection_member_expression
between_expression ::=
arithmetic_expression [NOT]
BETWEEN
arithmetic_expression AND
arithmetic_expression
in_expression ::=
single_valued_path_expression
[NOT] IN
(string_literal [, string_literal]* )
like_expression ::=
single_valued_path_expression
[NOT] LIKE
pattern_value [ESCAPE escape-character]
null_comparison_expression ::=
single_valued_path_expression IS [NOT] NULL
empty_collection_comparison_expression ::=
collection_valued_path_expression IS [NOT] EMPTY
collection_member_expression ::=
{single_valued_navigation |
identification_variable |
input_parameter}
[NOT] MEMBER
[OF] collection_valued_path_expression
comparison_expression ::=
string_value { =|<>}
string_expression |
boolean_value { =|<>}
boolean_expression} |
datetime_value { = |
<> | > | < } datetime_expression |
entity_bean_value { = |
<> } entity_bean_expression |
arithmetic_value
comparison_operator
single_value_designator
arithmetic_value ::= single_valued_path_expression |
functions_returning_numerics
single_value_designator ::= scalar_expression
comparison_operator ::=
= | > | >= | < |
<= | <>
scalar_expression ::= arithmetic_expression
arithmetic_expression ::= arithmetic_term |
arithmetic_expression { + |
- } arithmetic_term
arithmetic_term ::= arithmetic_factor |
arithmetic_term { * | / }
arithmetic_factor
arithmetic_factor ::= { + |- } arithmetic_primary
arithmetic_primary ::= single_valued_path_expression |
literal | (arithmetic_expression)
|
input_parameter |
functions_returning_numerics
string_value ::= single_valued_path_expression |
functions_returning_strings
string_expression ::= string_primary | input_expression
string_primary ::= single_valued_path_expression | literal |
(string_expression) |
functions_returning_strings
datetime_value ::= single_valued_path_expression
datetime_expression ::= datetime_value | input_parameter
boolean_value ::= single_valued_path_expression
boolean_expression ::= single_valued_path_expression |
literal | input_parameter
entity_bean_value ::=
single_valued_navigation |
identification_variable
entity_bean_expression ::= entity_bean_value | input_parameter
functions_returning_strings ::=
CONCAT(string_expression,
string_expression) |
SUBSTRING(string_expression, arithmetic_expression,
arithmetic_expression)
functions_returning_numerics::=
LENGTH(string_expression) |
LOCATE(string_expression,
string_expression[,
arithmetic_expression]) |
ABS(arithmetic_expression)
|
SQRT(arithmetic_expression)
FROM子句
FROM子句声明同位变量来定义查询的对象。语法:
from_clause
::= FROM identification_variable_declaration [,
identification_variable_declaration]*identification_variable_declaration ::=
collection_member_declaration |
range_variable_declarationcollection_member_declaration ::= IN
(collection_valued_path_expression) [AS] identifier
range_variable_declaration ::= abstract_schema_name [AS] identifier
标识符
标识符是一个字符序列。头一个字符必须是符合Java变成语言(以下简称Java)的标识符规则的开始字符(字母、$和_),后面的字符要是Java标识符规则的非开始字符(字母、数字、$和_)。(参考J2SE文档中Character类的isJavaIdentifierStart和isJavaIdentifierPart方法的说明。)问号(?)是EJB
QL的保留字,不能出现在标识符中。跟Java变量不同的是,EJB QL标识符大小写不敏感。
标识符不能是如下的EJB QL关键字(20个):
|
AND
|
AS
|
BETWEEN
|
DISTINCT
|
|
EMPTY
|
FALSE
|
FROM
|
IN
|
|
MEMBER
|
NOT
|
NULL
|
OBJECT
|
|
OF
|
OR
|
SELECT
|
TRUE
|
|
IS
|
LIKE
|
UNKNOWN
|
WHERE
|
这些关键字也是SQL的保留字。以后EJB SQL关键字可能会扩展包含另一些SQL保留字,所以EJB规范建议不要使用其它的SQL保留字作为EJB
QL的标识符。
同位变量
同位变量是FROM字句中声明的标识符,尽管SELECT和WHERE子句会引用这些变量,但不能声明它们。所有的同为变量都必须在FROM子句中声明。
因为同位变量也是标识符,所以它有和标识符一样的命名约定和约束。例如,同为变量也是大小写不敏感的也不能使用EJB QL关键字。另外,在给定的EJB
JAR文件里,同位变量也不能是其实体Bean的名字和抽象模式名。
FROM子句可以声明多个同位变量,它们之间用逗号隔开。一个声明可以引用前面(左边)声明过的同位变量。如下变量t引用前面声明的p:
FROM Player p, IN (p.teams) AS t
同位变量就算不被WHERE子句引用,它的声明仍然可以影响查询结果。比较下面的两个例子:
1.SELECT OBJECT(p)
FROM Player p
该查询返回所有的运动员。
2.SELECT OBJECT(p)
FROM Player p, IN (p.teams) AS t
因为这里声明了同位变量t,它返回加入了组的运动员
下面的查询返回和上面2相同的结果,但是它的WHERE子句更容易读懂:
SELECT OBJECT(p)
FROM Player p
WHERE p.teams IS NOT EMPTY
同位变量总是表示一个引用,它的类型是声明中使用的表达式的类型。声明可以分为两种:范围变量和集合成员。
范围变量声明
你可以指定一个范围变量以将同位变量声明为一个抽象模式类型。就是说一个同位变量具有实体Bean的抽象模式类型。下面的例子中,同位变量p代表抽象模式Player:
FROM Player p
一个范围变量声明可以包含可选的AS操作符:
FROM Player AS p
大多是情况下,要获得目标对象,查询可以通过路径表达式跨域实体关系。但是不能通过跨越关系获得的目标对象,你只能用范围变量声明来表示一个查询起点(根)。
例如,查询要比较同一个抽象模式中的多个对象,FROM子句必须为该抽象模式声明多个对应的同位对象(上节例9):
FROM Player p1, Player p2
集合成员声明
在一对多关系中,“多”的一方在关系中由实体Bean的集合组成。一个同位变量可以代表集合的成员。为了访问集合成员,变量声明中的路径表达式跨越抽象模式中的实体关系。(路径表达式将在本节后面部分讲到。)因为路径表达式可以嵌套,所以这种关联可以跨越多个关系。(上节例6)
集合成员声明时必须包含IN操作符,但可以省略AS操作符。
下面的例子中,抽象模式名为Player的实体Bean有一个关系字段:teams,同位变量t代表teams集合中的单个成员:
FROM Player p, IN (p.teams) AS t
路径表达式
由于多种原因,使路径表达式成为EJB QL语法中的重要成员。首先它们定义跨越抽象模式中的关系的路径,这些路径定义不仅影响查询范围还同时影响查询结果。其次它们可以出现在EJB
QL查询的三种主要子句(SELECT、WHERE和FROM)的任何一种子句中。最后尽管很多EJB QL是SQL的子集,但是路径表达式确实SQL里没有的一种扩展。
语法
路径表达式有两种类型:单值表达式和集合表达式。下面是这两种表达式的语法:
single_valued_path_expression
::=
{single_valued_navigation |
identification_variable}.cmp_field |
single_valued_navigation
single_valued_navigation ::=
identification_variable.[single_valued_cmr_field.]*
single_valued_cmr_field
collection_valued_path_expression ::=
identification_variable.[single_valued_cmr_field.]*
collection_valued_cmr_field
在上面的语法定义中,cmp_field表示持久性字段,cmr_field表示关系字段.。single_valued限定关系字段是一对一或者一对多关系单一值的一方。Collection_valued表示关系字段是集合值的一方。
句点(.)在路径表达式中有两种作用。如果句点出现在持久性字段前,那么它表示在字段和同位变量值键的限定符,如果在关系字段前,表示一个关联操作符。
例子
下面的这个查询中,WHERE子句包含一个单值路径表达式。P是一个同位变量,salary是Player的持久性字:
SELECT DISTINCT OBJECT(p)
FROM Player p
WHERE p.salary BETWEEN ?1 AND ?2
接着的这个例子中,WHERE子句也包含一个单值路径表达式,但跨越多个关系。t是一同位变量,league是一个单值关系字段(关系字段中单一值的一方),sport是league的持久性字段:
SELECT DISTINCT OBJECT(p)
FROM Player p, IN (p.teams) AS t
WHERE t.league.sport = ?1
最后的这个例子中,WHERE子句包含一个集合路径表达式。P是同位变量,teams表示集合关系字段:
SELECT DISTINCT OBJECT(p)
FROM Player p
WHERE p.teams IS EMPTY
表达式类型
表达式的类型是表达式结束元素代表的对象的类型。可以使一下任何一种:
☆ 持久性字段
☆ 单值关系字段
☆ 集合关系字段
例如,因为salary持久性字段的类型是double,则p.salary表达式的类型也是double。而p.teams表达式的结束元素是teams,它是一个集合关系字段,所以这个表达式的类型是Team的抽象模式类型集合,因为Team是TeamEJB实体Bean的抽象模式名,实际上这个类型映射为实体Bean的Local接口:LocalTeam。关于抽象模式的类型映射参考返回类型部分。
关联查询
路径表达式使查询可以跨越关系中的两个实体Bean。表达式的结束元素决定是否允许这种关联,如果一个表达式包含单值关系字段,那么查询可以继续跨越该字段的关联实体。然而查询不能跨越持久性字段和集合关系值段建立关联。例如p.teams.league.sport是一个非法表达式,因为teams是一个集合关系字段。要获得sport字段,可以在FROM子句中为teams声明一个同为变量t:
FROM Player AS p, IN (p.teams) t
WHERE t.league.sport = 'soccer'
WHERE子句
WHERE子句定义限制查询返回结果的条件表达式。查询返回从数据库中读出的使条件表达式为TRUE的所有值。尽管WHERE子句很常用,但它并不是必需的。如果WHERE子句被省略,查询就返回所有值。下面是WHERE子句的高级语法定义:
where_clause ::= WHERE conditional_expression
常量元素
WHERE子句有三种常量:字符串、数字和布尔型。
字符串常量
字符串常量使用单引号括起来的字符序列:
'Duke'
和Java字符串类(String)一样,EJB QL的字符串常量使用Unicode字符编码。
数字常量
WHERE子句支持两种类型的数字常量:精确数字和近似值。
一个精确的数字常量是没有小数点的整数,如65、-233、+12这些。用Java语法描述,精确数字常量支持Java的long类型的表示范围。
一个近似值数字常量是用科学计数法表示的数字,像57.、-85.7、+3.5这样的数字。用Java浮点数描述,近似值数字常量支持double类型的表示范围。
布尔常量
布尔常量只有两个:TRUE和FALSE。大小写不敏感。
传入参数
传入参数用问号(?)后跟一个整数表示。例如第一个参数表示为?1,第二个参数表示为:?2,依次类推。
以下是传入参数的使用规则:
☆ 只能在WHERE子句中使用传入参数
☆ 在条件表达式中限制只能和单值路径表达式比较
☆ 必须用从1开始的整数编号而且不能大于对应的查找或者Select方法中的参数个数
☆ 类型必须和相应查找或者Select方法中的对应参数类型匹配
条件表达式
WHERE子句由条件表达式组成,条件表达式符合一般的比较运算和布尔表达式的运算顺序,同优先级的从左到右运算,用括好可以改变默认的运算顺序。下面是条件表达式的语法定义:
conditional_expression
::= conditional_term |
conditional_expression OR
conditional_term
conditional_term ::= conditional_factor |
conditional_term AND
conditional_factor
conditional_factor ::= [ NOT ] conditional_test
conditional_test ::= conditional_primary
conditional_primary ::=
simple_cond_expression |
(conditional_expression)
simple_cond_expression ::=
comparison_expression |
between_expression |
like_expression |
in_expression |
null_comparison_expression |
empty_collection_comparison_expression |
collection_member_expression
运算符和它们的优先级
表8-2按优先级递减的顺序列出了EJB QL的运算符:
|
表 8-2 EJB QL操作符
|
|
类型
|
预算符
|
|
关联查询
|
. (句点)
|
|
算术
|
+ -(一元)
* / (乘除)
+ - (加减)
|
|
比较
|
=
>
>=
<
<=
<> (不等于)
|
|
逻辑
|
NOT
AND
OR
|
BETWEEN表达式
BETWEEN表达式判断一个算术表达式的值是否在某个范围内。语法定义如下:
between_expression ::=
arithmetic_expression [NOT] BETWEEN
arithmetic_expression AND arithmetic_expression
下面的两个表达式等价:
p.age BETWEEN 15 AND 19
p.age >= 15 AND p.age <= 19
下面的两个表达式也等价:
p.age NOT BETWEEN 15 AND 19
p.age < 15 OR p.age > 19
如果算术表达式有一个空值(NULL),BETWEEN表达式的值不可预料。
IN表达式
IN表达式判断一个字符串是否属于一个字符串常量的集合。语法如下:
in_expression ::=
single_valued_path_expression
[NOT] IN (string_literal [, string_literal]* )
其中的单值路径表达式必须是一个字符串类型。如果单值路径表达式的值为(NULL),IN表达式的值不可预料。
在下面的例子中,如果country是UK,IN表达式值是TRUE。如果country是Peru则表达式值为FALSE:
o.country IN ('UK', 'US', 'France')
LIKE表达式
LIKE表达式判断一个通配符模式和一个字符串是否匹配。语法如下:
like_expression ::=
single_valued_path_expression [NOT] LIKE pattern_value [ESCAPE escape-character]
其中单值路径表达式是字符串类型,如果为空(NULL),LIKE表达式的值不可预料。Pattern_value是一个可以包含通配符的字符串常量。EJB
QL的通配符是下划线(_)和百分号(%)。下划线表示任意单个字符,百分号表示任意字符序列(字符串)。ESCAPE子句指定要从pattern_value的通配符中排除的字符。
表8-3给出了一些LIKE表达式的例子。TRUE和FALSE列表示单值路径表达式的值是列内容时LIKE表达式的值是TRUE或者FALSE。
|
表 8-3 LIKE 表达式例子
|
|
表达式
|
TRUE
|
FALSE
|
|
address.phone LIKE '12%3'
|
'123'
'12993'
|
'1234'
|
|
asentence.word LIKE 'l_se'
|
'lose'
|
'loose'
|
|
aword.underscored LIKE '\_%' ESCAPE '\'
|
'_foo'
|
'bar'
|
|
address.phone NOT LIKE '12%3'
|
1234
|
'123'
'12993'
|
判断空值(NULL)表达式
此种表达式判断一个单值路径表达式是否是空值。通常用来判断一个单值关系字段是否被赋值。如果单值路径表达式运算是遇到空值则它的值为空。表达式语法:
null_comparison_expression ::=
single_valued_path_expression IS [NOT] NULL
判断集合为空表达式
此种表达式判断集合路径表达式中是否没有元素。就是说它检查一个集合关系字段是否被赋值。语法:
empty_collection_comparison_expression ::=
collection_valued_path_expression IS [NOT] EMPTY
如果集合路径表达式的值是空,则判断表达式得到一个空值。(If the collection-valued path expression
is NULL, then the empty collection comparison expression
has a NULL value.这句话显然在我们的预料之外,如果这个判断语句的值如果不是布尔型……)
判断集合成员表达式
表达式判断给定值是否是集合的成员。该值和集合成员必须是相同的类型。语法:
collection_member_expression ::=
{single_valued_navigation | identification_variable |
input_parameter}
[NOT] MEMBER [OF] collection_valued_path_expression
如果集合路径表达式的值未知,则该判断表达式的值也未知。如果集合路径表达式代表一个空集合,则判断表达式的值为FALSE。
函数表达式
EJB QL提供一些字符串和数学函数,表8-4和8-5列出了这些函数。其中start和length参数都是int类型,它们指示String参数中的位置.number参数可以是int、float和double中的任一类型。
|
表 8-4 字符串函数
|
|
函数声明
|
返回类型
|
|
CONCAT(String, String)
|
String
|
|
SUBSTRING(String, start, length)
|
String
|
|
LOCATE(String, String [, start])
|
int
|
|
LENGTH(String)
|
int
|
|
表 8-5 数学函数
|
|
函数声明
|
返回类型
|
|
ABS(number)
|
int, float,
or double
|
|
SQRT(double)
|
double
|
空值(NULL)
如果引用目标不在稳定的存储空间中,则该目标为空。对包含空值的条件表达式,EJB QL采用SQL92定义的语义,简要概括该语义如下:
☆ 如果一个比较操作或者算术操作有一个未知的值,则表达式为空
☆ 如果一个路径表达式有空值参与运算,则表达式为空
☆ IS NULL表达式遇到NULL值返回TRUE,IS NOT NULL遇到空值返回FALSE
☆ 布尔运算符和条件表达式的值使用下面的表提供的三种逻辑值(T:TRUE,F:FALSE,U:UNKNOW)
|
表 8-6 AND 操作
|
|
AND
|
T
|
F
|
U
|
|
T
|
T
|
F
|
U
|
|
F
|
F
|
F
|
F
|
|
U
|
U
|
F
|
U
|
|
表 8-7 OR 操作
|
|
OR
|
T
|
F
|
U
|
|
T
|
T
|
T
|
T
|
|
F
|
T
|
F
|
U
|
|
U
|
T
|
U
|
U
|
|
表 8-8 NOT 操作
|
|
NOT
|
|
|
T
|
F
|
|
F
|
T
|
|
U
|
U
|
|
表 8-9 条件判断
|
|
条件判断
|
T
|
F
|
U
|
|
表达式值是TRUE
|
T
|
F
|
F
|
|
表达式值是FALSE
|
F
|
T
|
F
|
|
表达式的值是U
|
F
|
F
|
T
|
相等
EJB QL中只有同种类型的值可以进行比较。精确和近似数字例外,它们可以比较,在他们比较时,按照Java语言的数学运算进行隐式转换。
EJB QL把这些参加比较的值当作Java对象类型来对待,而不是它们在底层数据库中代表的类型。例如如果一个持久性字段只能是整形或者空值,则它必须被指派给一个Integer对象,而不是一个原始int类型。因为Java对象可以为空而原始类型不能为空,所以这种指派是必需的。
两个字符串只有在它们只包含相同的字符序列时才相等,例如’abc’和’abc ‘就不相等(后者包含一个空个结束)。
同一抽象模式类型的两个实体Bean只有它们的主键值相等时才相等。
SELECT子句
SELECT子句定义查询返回的对象或值的类型。语法:
select_clause ::= SELECT [DISTINCT]
{single_valued_path_expression |
OBJECT(identification_variable)}
返回类型
查询的返回类型必须匹配查询对应的查找或者Select方法的返回类型。
查找方法的查询,返回类型是定义查找方法的实体Bean的抽象模式类型,该抽象模式类型映射到实体Bean的Remote或者Local接口。如果Remote
Home接口定义的该查找方法,则返回类型是Remote接口或它的集合);如果是Local Home接口定义的该查找方法,则返回类型是Local接口或它的集合。例如PlayerEJB的LocalPlayerHome接口定义了查找方法findall:
public Collection findAll() throws FinderException;
findall方法的EJB QL查询返回LocalPlayer接口的集合:
SELECT OBJECT(p)
FROM Player p
Select方法的查询,返回类型可能是以下之一:
☆ Select方法所属实体Bean的抽象模式类型
☆ 实体关系中另一个实体Bean的抽象模式类型(缺省情况下抽象模式类型映射到实体Bean的Local接口,尽管不常用,你可以在部署描述符中指定映射到Remote接口。)
☆ 持久性字段
例如PlayerEJB实体Bean,包含ejbSelectSport方法,返回一个代表sport的String对象的集合,sport是LeagueEJB的持久性字段。(上节例11)
SELECT子句中不能出现集合表达式。如在下面的例子中,SELECT子句中使用p.teams是非法的,因为它是一个集合。而用t(IN(p.teams)
AS t)就是合法的,因为它代表teams的单一成员:
SELECT t
FROM Player p, IN (p.teams) AS t
DISTINCT和OBJECT关键字
DISTINCT关键字排除返回值中的重复值。如果查询返回一个java.util.Collection的对象,它允许出现重复值,你可以使用DISTINCT关键字来排除重复值。而当一个方法返回java.util.Set的对象,则DISTINCT关键字就多余了,因为java.util.Set不允许有重复值。
OBJECT关键字必须在单独的同位变量前面,但是不能出现在一个单值路径表达式前。如果同位变量是单值路径表达式的一部分,那么它不是单独的。
五.EJB QL的限制
EJB QL由一些局限:
☆ 不支持注释
☆ Date和Time的值都用Java的long类型表示成毫秒。一个为了产生毫秒值,你也需要使用java.util.Calendar类
☆ 通常CMP不支持继承,因此不同类型的实体Bean(CMP)无法比较
|