UML软件工程组织

详解Enterprise JavaBeans查询语言之一
来源:www.linuxaid.com.cn 作者:Dale Green
Enterprise JavaBeans查询语言(EJB QL)定义了容器管理持续化的finder方法和select方法的查询。作为SQL92的一个子集,EJB QL进行了扩展,它可以使用entity bean的抽象模式中定义的关联。一个EJB QL查询可以跨越封装在同一个EJB JAR文件中的所有相关的entity bean的抽象模式。

你可以在entity bean中部署描述中定义EJB QL查询。典型的情况是,一个工具会将这些查询转换成低层数据存储所使用的查询语言。因为这种转换的存在,使用容器管理持续化的entity bean具有可移植性--它们的代码不受具体的数据存储的类型的影响。

下面列出了本文用到的一些术语的定义。

1、Abstract schema--抽象模式:一个entity bean的部署描述的一部分,它定义了bean的持续化字段和关联关系。

2、Abstract schema name--抽象模式名:在EJB QL查询中引用的一个逻辑命名。你需要为每个容器管理持续化的entity bean指定一个抽象模式名。

3、Abstract schema type--抽象模式类型:所有的EJB QL表达式都对应一个类型。如果表达式是一个抽象模式名,那么它的类型默认是定义了这个抽象模式名的entity bean的local接口。

4、Backus-Naur Form (BNF)--巴科斯-诺尔范式:一种描述高级语言语法的一种表示法。这一章的语法图表使用了BNF表示法。

5、navigation--跨越:在一个EJB QL表达式中对关联关系的使用。跨越操作符是一个句点。

6、path expression--路径表达式:一个跨越到相关entity bean的表达式。

7、persistent field--持续化字段:一个容器管理持续化的entity bean中的一个虚拟字段;它存储在一个数据库中。

8、relationship field--关联字段:一个容器管理持续化的entity bean中的一个虚拟字段;它确定了一个相关的entity bean。

简单的语法

这里简要地描述了EJB QL的语法,这样你可以快速进入下面查询示例的学习。如果你要对此进行更深入的学习,请阅读完整的语法。

一个EJB QL查询由三个子句组成:SELECT子句、FROM子句和WHERE子句,SELECT子句和FROM子句是必选的,而WHERE子句是可选的。下面是一个EJB QL查询的简单BNF定义:


EJB QL :: = select_clause 
from_clause [where_clause]



SELECT子句定义了对象的类型或查询的返回值。返回类型可是一个local接口、一个remote接口或是一个持续化字段。

FROM子句通过声明一个或多个标识变量定义了查询的范围,这些标识变量可能会在SELECT子句和WHERE子句中被引用。一个标识变量反映了下列元素之一:

1、一个entity bean的抽象模式名

2、一个集合的一个成员,这个集合是一个一对多关系中的多端

WHERE子句是一个限制查询找到的对象或数值的条件表达式。尽管它是可选的,但是绝大多数查询都会有一个WHERE子句。

简单的Finder查询

如果你对EJB QL不熟悉,这些简单的查询将有助于你尽快入门。

示例 1


SELECT OBJECT(p) 
FROM Player p



获得的数据:所有队员。

Finder方法: findall()

说明:FROM子句声明了一个名为p的标识变量,其中省略了可选的AS关键字。如果使用了AS关键字,这个子句将是这样的:


FROM Player AS p



Player元素是PlayerEJB entity bean的抽象模式名。因为bean在LocalPlayerHome接口中定义了findall方法,所以这个查询返回的对象具有LocalPlayer类型。

示例 2


SELECT DISTINCT OBJECT(p) 
FROM Player p 
WHERE p.position = ?1



获得的数据:由finder方法的参数指定位置的队员。

Finder方法: findByPosition(String position)

说明:在一个SELECT子句中,在例如p这样的独立的标识变量前面要加OBJECT关键字。DISTINCT关键字排除了重复的数据。

WHERE子句通过检查队员的position这个PlayerEJB entity bean的持续化字段对获得的队员进行了限制。?1元素表示了了findByPosition方法中的输入参数。

示例 3


SELECT DISTINCT OBJECT(p) 
FROM Player p 
WHERE p.position = ?1 
AND p.name = ?2



获得的数据:指定位置和姓名的队员。

Finder方法: findByPositionAndName(String position, String name)

说明:position元素和name元素是PlayerEJB entity bean的持续化字段。WHERE子句将这些字段与findByPositionAndName方法的输入参数进行比较。EJB QL使用一个后面带有整数的问号表示输入参数。第一个输入参数中?1,第二个是?2,依此类推。

跨越相关Bean的Finder查询

在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



获得的数据:属于指定城市的运动队的队员。

Finder方法: findByCity(String city)

说明:FROM子句声明了两个标识变量:p和t。p变量表示PlayerEJB entity bean,而t变量表示相关的TeamEJB bean。在t的声明中引用了之前声明的p变量。IN关键记号表示teams是一个相关bean的集合。p.teams表示式实现了从PlayerEJB bean到它的相关TeamEJB bean的跨越。p.teams表达式中的句点是跨越操作符。

在WHERE子句中,标识变量city之前的句点是一个分隔符,而不是一个跨越操作符。严格说来,表达式可以跨越到关联字段(相关的bean),而不是持续化字段。要访问一个持续化字段,一个表达式必须使用句点作为分隔符。

表达式不可以对作为集合的关联字段作更进一步的跨越。在一个表达式的语法中,collection-value字段是一个终结符。因为teams字段是一个集合,所以WHERE子句不可以指定 p.teams.city--这是一个非法的表达式。

示例 5


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



获得的数据:属于指定运动联盟的队员。

Finder方法: 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



获得的数据:参与指定运动的队员。

Finder方法: findBySport(String sport)

说明:sport持续化字段属于LeagueEJB bean。要访问sport字段,查询必须首先实现从PlayerEJB bean到TeamEJB bean的跨越(p.teams),然后实现从TeamEJB bean到LeagueEJB bean的跨越(t.league)。因为league关联字段不是一个集合,在它后面可以跟随sport持续化字段。

使用其它条件表达式的Finder查询

每一个WHERE子句都必须指定一个条件表达式,这样的条件表达式可以有几种。在之前的示例中,条件表达式是检测是否相等的比较表达式。在下面的例子中,使用了一些其它种类的条件表达式。

示例 7


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



获得的数据:所有不属于任何运动队的队员。

Finder方法: findNotOnTeam()

说明:PlayerEJB bean的teams关联字段是一个集合。如果一个队员不属于任何运动队,那么teams集合为空,条件表达式的结果将为TRUE。

示例 8


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



获得的数据:薪水位于指定范围的队员。

Finder方法: findBySalaryRange(double low, double high)

说明:BETWEEN表达式是一个三元表达式:一个持续化字段(p.salary)和两个输入参数(?1和?2)。下面的表达式与之前的BETWEEN表达式等价:


p.salary >= ?1 AND p.salary <= ?2



示例 9


SELECT DISTINCT OBJECT(p1) 
FROM Player p1, Player p2 
WHERE p1.salary > p2.salary
AND p2.name = ?1



获得的数据:所有薪水高于指定姓名的队员薪水的队员。

Finder方法: findByHigherSalary(String name)

说明:FROM子句声明了两个标识变量(p1和p2),这两个标识变量具有同一类型(Player)。之所以在这里需要两个标识变量是因为以WHERE子句中将一个队员(p2)的薪水与另一个队员(p1)进行了比较。
Select查询

这一部分的查询是select方法所使用的。与finder方法不同,一个select方法可以返回持续化字段或其它entity bean。

示例 10


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



获得的数据:指定队员所属的联盟。 

Select方法:ejbSelectLeagues(LocalPlayer player) 

说明:这个查询的返回类型是LeagueEJB entity bean的抽象模式类型。这个抽象模式类型映射到LocalLeagueHome接口。因为表达式t.league不是一个独立的标识变量,OBJECT关键字被省略了。 

示例 11 


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



获得的数据:指定队员所参与的运动。 

Select方法: ejbSelectSports(LocalPlayer player) 

说明:这个查询返回了一个名为sport的String named sport,这是LeagueEJB entity bean的一个持续化字段。 

完整的语法 

在这一部分我们讨论Enterprise JavaBean规范中定义的EJB QL语法。下面的素材中的大多数直接取自Enterprise JavaBean规范或是对规范的解释。 

EJB QL的BNF语法 

这里是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)


BNF符号 

表8-1介绍了在这一章中使用的BNF符号。 

表8-1 BNF 符号概览 


符号 描述 
::= 该符号左边的元素被该符号 右边的结构所定义 
* 该符号前面的结构可以 重复零次或多次 
{...} 在这个花括号中的结构 一起组合成一组 
[...] 方括号中的结构是可选的 
| 一个具有排它性的OR 
黑体字 一个关键字 (尽管在这个BNF定义中使用了大写, 但是事实上关键字 并不是大小写敏感的) 
空白区域 一个空白区域可以是一个空格、 横表符或是换页符 



FROM子句 

FROM子句通过声明标识变量定义了查询的范围。这里是FROM子句的语法: 



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



标识符 

一个标识符是由一个或多个字符组成的序列。在Java编程语言(以下简称"Java")中的标识符的首字符必须是一个有效的首字符(字母、$和_)。在一外Java标识符中的每一个子序列字符都必须是一个有效的非首字符(字母、数字、$和_)。(详细情况请参阅Character类的isJavaIdentifierStart方法和isJavaIdentifierPart方法的J2SE API文档。在EJB QL中问号(?)是一个保留字符,它不可以在一个标识符中使用。与一个Java变量不同,一个EJB QL标识符是对大小写不敏感的。 

一个标识符不能与EJB QL关键字发生冲突: 


AND
AS 
BETWEEN
DISTINCT
EMPTY
FALSE
FROM
IN
IS 
LIKE
MEMBER
NOT
NULL
OBJECT
OF
OR
SELECT
TRUE
UNKNOWN
WHERE



EJB QL的关键字同时也是SQL的保留字。在将来,EJB QL关键字将扩充到包含其它SQL保留字。Enterprise JavaBeans规范推荐你不要在EJB QL标识符中使用其它SQL保留字

 

 

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