UML软件工程组织

详解Enterprise JavaBeans查询语言之二
来源:www.linuxaid.com.cn 作者:Dale Green
标识变量

一个标识变量就是在FROM子句中声明的一个标识符。尽管SELECT子句和WHERE子句中可以引用标识变量,但是不可以声明它。所有的标识变量都只能在FROM子句中声明。

因为一个标识变量就是一个标识符,所以它与标识符具有同样的命名约定和约束。例如,一个标识变量是对大小写不敏感的,它不可以与一个EJB QL关键字相同。(更多的命名规则请参见上一段。)同样,在一个给定的EJB JAR文件中,一个标识命名也不能与任何entity bean的命名或抽象模式名重复。

FROM子句可以包含用逗号隔开的多个声明。一个声明可以引用另一个在前面(左边)已经声明的标识变量。在下面的FROM子句中,变量t引用了之前声明的变量p:


FROM Player p, IN (p.teams) AS t



即使一个标识变量没有在WHERE子句中引用,它的声明也可以影响到查询的结果。我们可以来比较下面的两个查询。下面的查询返回所有的队员,不论他们是否属于一个运动队:


SELECT OBJECT(p) 
FROM Player p



与此相反,因为下一个查询声明了t标识变量,它可以获得属于一个运动队的所有队员:


SELECT OBJECT(p) 
FROM Player p, IN (p.teams) AS t



下面的查询返回了与上一个查询相同的结果,但是WHERE子句的存在使得这个查询更容易理解:


SELECT OBJECT(p) 
FROM Player p 
WHERE p.teams IS NOT EMPTY



一个标识变量总是指向一个单独的值,它的类型是声明中使用的表达式。有两个类型的声明:范围变量和集合成员。

范围变量声明

要将一个标识变量声明为一个抽象模式类型,你必须指定一个范围变量申明。换句话说,一个标识变量可以包括一个entity bean的抽象模式类型。在下面的例子中,一个名为p的标识变量表示了一个名为Player的抽象模式:


FROM Player p



一个范围变量声明可以包括可选的AS操作符:


FROM Player AS p



在绝大多数情况下,为了获得对象,查询会使用路径表达式以跨越关联关系。但是对于那些不能通过跨越获得的对象,你可以使用一个范围变量声明以指定一个起点(或root)。

如果查询对同一抽象模式名的多个值进行比较,那么FROM子句需要为这个抽象模式声明多个标识变量:


FROM Player p1, Player p2



集合成员声明

在一个一对多的关联关系中,多端由一个entity bean的集合组成。一个标识变量可以反映这个集合中的一个成员。要访问一个集合成员,变量声明中的路径表达式将跨越抽象模式中的关联关系。(在下面我们将详细介绍路径表达式。)因为一个路径表达式可以基于另一个路径表达式,所以可以实现对几个关联关系的跨越。

一个集合成员声明必须包含IN操作符,不过它可以省略可选的AS操作符。

在下面的例子中,抽象模式名为Player的entity 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和collection-valued。下面是路径表达式的语法:


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子句包含了一了single-valued表达式。p是一个标识变量,而salary是Player的一个持续化字段。


SELECT DISTINCT OBJECT(p) 
FROM Player p 
WHERE p.salary BETWEEN ?1 AND ?2



下一个例子的WHERE子句也包含了一个single-valued表达式。t是一个标识变量,league是一个single-valued关联字段,而sport是league的一个持续化字段。


SELECT DISTINCT OBJECT(p) 
FROM Player p, IN (p.teams) AS t 
WHERE t.league.sport = ?1



在下面的查询中,WHERE子句包含了一个collection-valued表达式。p是一个标识变量,而teams是一个collection-valued关联字段。


SELECT DISTINCT OBJECT(p) 
FROM Player p 
WHERE p.teams IS EMPTY



表达式类型

一个表达式的类型就是最后的元素所对应的对象的类型,它可以有以下几种:

1、持续化字段

2、Single-valued关联字段

3、Collection-valued关联字段

例如,表达式p.salary的类型是double,这是因为最后的持续化字段(salary)的类型为double。

在表达式p.teams中,最后的元素是一个collection-valued关联字段(teams)。那么这个表达式的值就是一个名为Team的抽象模式类型的集合。因为Team是TeamEJB entity bean的抽象模式命名,所以这个类型映射到bean的local接口LocalTeam。

跨越

路径表达式的存在使得查询可以跨越到相关的entity bean。一个表达式中最后的元素决定了是否可以进行遗址。如果一个表达式包含了一个single-valued关联字段,那么可以继续跨越到与该字段相关的对象。

然而,一个表达式不能作超过一个持续化字段或是一个collection-valued关联字段的跨越。例如,表达式p.teams.league.sport就是非法的,因为teams是一个collection-valued关联字段。要访问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



常量

有三种类型的常量:字符串型、数值型和布尔型。

字符串型常数

一个字符串型常量用一组单引号引出:

'Duke'

如果一个字符串本身就包含一个单引号,你可以通过使用两个单引号来表示它:

'Duke''s'

和一个Java String一样,一个EJB QL中的字符串常量使用Unicode字符编码。

数值型常量

有两种类型的数值型常量:精确型和近似型。

一个精确型数值常量是一个没有小数点的数字,例如65、-233和+12。使用Java整数的语法,精确型数值常量可以支持Java long范围内的数字。

一个近似型数值常量是一个使用科学记数法的数字,例如57.、-85.7和+2.1。使用Java浮点常量的语法,近似型数值常量可以支持Java double范围内的数字。

布尔型常量

一个布尔型常量是TRUE或FALSE。这些关键字是对大小写不敏感的。

输入参数

一个输入参数标志为问号(?)后加整数。例如,第一个输入参数是?1,第二个是?2,依此类推。输入参数必须遵守以下规则:

1、它们只可以应用于一个WHERE子句中。

2、它们的使用只限于一个条件表达式中的single-valued路径表达式。

3、它们必须是有限的,并以整数1开始。

4、WHERE子句中输入参数的数目不可以超过相应的finder方法或select方法中的输入参数的数目。

5、WHERE子句中输入参数的类型必须与相应的finder方法和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



BETWEEN表达式

一个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表达式的语法:


in_expression ::= 
    single_valued_path_expression 
    [NOT] IN (string_literal 
	[, string_literal]* )



上述的single-valued path expression必须有一个String值。如果该single-valued path expression有一个NULL值,那么IN表达式的值未知。

在下面的例子中,如果国家是UK,那么表达式是TRUE。如果国家是Peru,则表达式是FALSE。


o.country IN ('UK', 'US', 'France')



LIKE表达式

一个LIKE表达式确定一个通配符模型是否匹配一个字符串。下面是语法:


like_expression ::= 
    single_valued_path_expression 
    [NOT] LIKE pattern_value 
	[ESCAPE escape-character]
  上述的single-valued path



expression必须有一个String值。如果这个值是NULL,那么LIKE表达式的值未知。通配符模型是一个可以包含通配符的字符串常量。下划线(_)表示任何一个单独的字符。百分号(%) 表示零个或多个字符。ESCAPE子句指定了一个通配符模型中的一个转义字符。

NULL比较表达式

一个NULL比较表达式检验一个single-valued路径表达式是否有一个NULL值。通常,这个表达式用来检验一个single-valued关联关系是否被设定。如果一个路径在运算过程中包含了一个NULL值,那么它将返回NULL值。下面是一个NULL比较表达式的语法:


null_comparison_expression 
::= 
    single_valued_path_expression 
	IS [NOT] NULL



空集比较表达式

一个空集比较表达式检验一个collection-valued路径表达式是否包含元素。换句话说,它检验一个collection-valued关联关系是否被建立。下面是语法:


empty_collection_comparison_expression
::= collection_valued_path_expression IS 
[NOT] EMPTY



如果collection-valued路径表达式是NULL,那么空集比较表达式的值也为NULL。

集合成员表达式

集合成员表达式确定一个值是否是集合中的成员。这个值必须与集合成员是同一类型。表达式的语法如下:


collection_member_expression
::= 
    {single_valued_navigation 
	| identification_variable | 
    input_parameter} 
    [NOT] MEMBER [OF]
	collection_valued_path_expression



如果collection-valued路径表达式是未知的,那么集合成员表达式的结果也是未知的。如果collection-valued路径对应一个空集,那么集合成员表达式的结果是FALSE。

函数表达式

EJB QL包含几个字符串和算术函数,在下面的表中列出了这几个函数。在表8-4中,start和length参数的类型是int。它们对应了String参数中的位置。在表8-5中,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值

如果索引所指向的在持续化存储中无法找到,那么这就是NULL。对于包含NULL的条件表达式,EJB QL沿用SQL92中的规定。简单地说,有如下规定:

1、如果一个比较或算术操作包含一个未知值,它产生一个NULL值。

2、如果一个路径表达式包含一个NULL值,它返回一个NULL值。

3、在进行IS NULL检验时,NULL持续化字段或NULLsingle-valued关联字段的结果为TRUE。反之,在进行IS NOT NULL检验时结果为FALSE。

4、布尔操作

等同性规定

在EJB QL中,只有同一类型的值可以进行比较。但是,这个规则有一个例外:精确型数值与近似型数值之间可以进行比较。在这样的比较中,所需的类型转换遵守Java的有关规定。

EJB QL对数值进行比较时,将它们视为Java类型,而不是它们在底层数据存储中的持续化类型。例如,如果一个持续化字段既可以是整型也可以是NULL,那么它必须定义为一个Integer对象,而不是一个int简单变量。只是因为只有Java对象才能为NULL,而一个简单变量不可以。

两个字符串只有在它们包含完全相等的字符序列时才被视为相等。这时你注意空格的存在变得很重要;例如,字符串'abc'和'abc '就是不相等的。

两个具有相同抽象模式类型的entity bean只有在它们的主键的值相同时才被视为相等。

SELECT子句

SELECT子句定义了查询返回的对象或值的类型。SELECT子句的语法如下:


select_clause ::= SELECT [DISTINCT] 
    {single_valued_path_expression | 
    OBJECT(identification_variable)}



返回类型

SELECT子句定义的返回类型必须与这个查询为之定义的finder方法或select方法匹配。对于finder方法查询,SELECT子句的返回类型是定义这个finder方法的entity bean的抽象模式类型。

这个抽象模式类型映射到一个remote接口或local接口。如果是bean的remote home接口定义了这个finder方法,返回类型就是remote接口(或remote接口的结果集)。同样的,如果local home接口定义了这个finder方法,返回类型就是local接口(或local接口的结果集)。例如,PlayerEJB entity bean的LocalPlayerHome接口定义了findall方法:


public Collection findAll()
throws FinderException;



findall方法的EJB QL查询返回LocalPlayer接口类型的结果集:


SELECT OBJECT(p) 
FROM Player p



对于select方法查询,SELECT子句的返回类型可以是以下情况中的一种:

1、包含这个select方法entity bean的抽象模式。

2、相关entity bean的抽象模式。(默认的情况是每一个这样的抽象模式类型映射到entity bean的local接口,尽管不常见,但是在这种情况下,你可能需要通过在部署描述中指定一个remote接口以重载这个默认的映射。)

3、一个持续化字段

例如,PlayerEJB entity bean实现的ejbSelectSports方法返回一个相应于sport的String对象的结果集。sport就是LeagueEJB entity bean的一个持续化字段。参见示例 11.

一个SELECT子句不能指定一个collection-valued表达式。例如,在SELECT子句中,p.teams就是非法的,这是因为teams是一个集合但是下面查询中的SELECT子句是有效的,这是因为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关键字,但是在一个single-valued路么表达式前不需要使用它。如果一个标识变量是一个single-valued路径表达式的一部分,那么它不被认为是单独的。

EJB QL约束

EJB QL有以下约束:

1、不允许用注释。

2、日期和时间值精确到毫秒级并使用Java long类型。一个日期和时间常量必须是一个整型常量。要生成毫秒值,你可以使用java.util.Calendar类。

3、通常情况下。容器管理持续化不支持继承。因为这个原因,两个不同类型的entity bean不能进行比较。

 

 

版权所有:UML软件工程组织