站内搜索: 请输入搜索关键词
当前页面: 在线文档首页 > J2EE Tutorial 中文版

第8章 EJB查询语言 - J2EE Tutorial 中文版


第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)无法比较