EJB-QL 用来在CMP类型的EJB中描述 finders和select 方法。设计这种语言的目的是严格的描绘内存对象的查询,而不是数据库的查询。 但是EJB-QL的语法与 SQL非常相似。 他有三个基本语句: SELECT, FROM, WHERE.。通过这几个语句可以实现各种各样的组合。本文的目的不是解释 EJB-QL的各种用法。我们会给出几种语法,并用几个例子来描述它。
<ejb-ql> 标记
EJB-QL不能单独使用,必须定义在ejb-jar.xml文件中的 <ejb-ql> 标记中。这个标记属于 <query> 标记,<query>定义EJB中的查询(finder或者 select方法)。EJB容器可以将查询转化为 finder或者 select方法的具体实现。. 下面是一个<ejb-ql> 标记的例子。.
<ejb-jar>
<enterprise-beans>
<entity>
<ejb-name>hotelEJB</ejb-name>
...
<abstract-schema-name>hotelSchemaName</abstract-schema-name>
<cmp-field>...
...
<query>
<query-method>
<method-name>findByCity</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</query-method>
<ejb-ql>
<![CDATA[SELECT OBJECT(h) FROM hotelSchemaName AS h WHERE h.city = ?1]]>
</ejb-ql>
</query>
</entity>
...
</enterprise-beans>
...
</ejb-jar>
蓝色的为EJB-QL 查询,红色的为 <![CDATA[...]]> 为特定的 XML符号,注意必须一直用这种表示方法。
常用语法
SELECT OBJECT(variable)
FROM abstractSchemaName [AS] variable
[WHERE value comparison value]
上面是最常用的语法,后面我们会看到更多的语法要素。在这个语法中,可以在FROM 中声明一个或者多个 变量(variables), 在SELECT 和 WHERE 中引用。 注意 abstractSchemaName,,它与 ejb-jar.xml中 entity 标记中声明的一致。
value 可以是一个参数( parameter), 数字(numeric或者字符( string),变量( variable), 变量中的成员( member inside this variable),或者常量(例如 'Pleasant Inn', 23, TRUE).。每个查询有一个返回类型( return type)。 Values and return types can be of 6 different data types.
SELECT OBJECT(h)
FROM hotelSchemaName AS h 返回所有的 hotels.
SELECT OBJECT(h)
FROM hotelSchemaName AS h
WHERE h.city = 'San Diego' 返回在 San Diego的 hotels .
在 SELECT语句中,关键字DISTINCT 可以避免查询出现重复的值。事实上,对于finder方法,由于其返回实体Bean,而实体Bean本身不会重复(因为其主关键字不同)。 但是对于 select 方法,可能就会有重复。
Select 方法的语法
当处理一个select方法时,返回类型 ( SELECT语句) 可以不用是 OBJECT(x)。 可以为任意类型的任意值。示例如下:
SELECT [DISTINCT] value
FROM abstractSchemaName [AS] variable
[WHERE ...]
保留关键字
EJB-QL保留关键字如下:
SELECT
FROM
WHERE OBJECT
AS
IN NOT
AND
OR
LIKE
ESCAPE
BETWEEN
IS
NULL
EMPTY
MEMBER
OF TRUE
FALSE LENGTH
LOCATE
CONCAT
SUBSTRING
ABS
SQRT
返回类型
所有的查询必须返回下面中的一种:
与 SELECT 语句中定义的对象一致的类型(type)
一个包含这种类型的Collection (当不使用SELECT DISTINCT时允许重复)
一个包含这种类型的 Set (不允许重复,必须用 SELECT DISTINCT)
选择什么取决于你,下面是相应的一些示例:
SELECT OBJECT(h)
FROM hotelSchemaName AS h
WHERE h.id = ?1 finder 方法如下:
abstract public Hotel findByHotelID(String hotelID);
(其实这个例子没有必要,因为findByPrimaryKey 完成的是同样的功能)
SELECT OBJECT(h)
FROM hotelSchemaName AS h
WHERE h.city = ?1 (允许重复)
or
SELECT DISTINCT OBJECT(h)
FROM hotelSchemaName AS h
WHERE h.city = ?1 (不重复) finder 方法如下:
abstract public Collection findByCity(String city);
SELECT OBJECT(h)
FROM hotelSchemaName AS h
WHERE h.capacity >= ?1 finder 方法如下:
abstract public Set findByCapacity(integer numberOfPeople);
变量
变量在 FROM中声明,表示一个 EJB对象。可以在 SELECT 和 WHERE 语句中声明。变量的类型在 ejb-jar.xml中的 abstract schema name 中声明。
后边我们会讨论 range variables
成员操作
通过点(".")你可以说明一个成员属于一个对象,通过点(".")你可以说明任意的cmp-field 名字,或者是一个单值的 cmr-field 的名字。你可以通过(".")操作单值对象(包括数据成员和关系链)。下面是一些示例:
SELECT OBJECT(h)
FROM hotelSchemaName h
WHERE ... ... h.capacity > 100
... h.owner = ?1
... h.owner.name = 'Harry'
... h.owner.hotel = h
... h.rooms = ?1 (这里的 cmp-field 名为 'city')
(这里的 cmr-field 'owner' 包含一个唯一的Owner对象)
(这里的owner包含一个 cmp-field 'name')
(这里owner 包含 cmr-field 'hotel'; 这个条件总为真)
(语法错误 – 不能使用一个 Collection cmr-field – 应该使用 range变量语法替代 )
Range Variable Syntax
当一个变量的成员是一个 Collection时,你不能通过点(".")操作它。你必须指定一个新的变量 ,这个变量回迭代(iterate)Collection中的每一个记录。下面是语法
SELECT [DISTINCT] OBJECT(variable)
FROM abstractSchemaName [AS] variable, IN (variable.collectionMember) [AS] variable2
[WHERE ...]
(注意这里的IN操作与WHERE中的不同),你可以在WHERE中 使用新定义的变量 ,就像一般的变量一样。
SELECT DISTINCT OBJECT(h)
FROM hotelSchemaName AS h, IN (h.rooms) AS r
WHERE r.smoking = TRUE
(返回所有不吸烟的房间)
WebLogic Server 6.1 : range变量语法 在WLS是不同的。下面是一个例子 :
SELECT DISTINCT OBJECT(h)
FROM hotelSchemaName AS h, r IN h.rooms
WHERE r.smoking = TRUE
参数
当finder或者select方法有一个或者多个参数时,可以用"?n"来表示第n个参数,下面是一个 finder方法的例子:
abstract public Hotel findByCityAndState(String city, String state);
你可以用?1表示参数city, ?2表示state,EJB-QL如下所示:
SELECT OBJECT(h)
FROM hotelSchemaName AS h
WHERE h.city = ?1 AND h.state = ?2
条件操作符
条件操作符是很多的,可以通过括号( )来区分优先级,,通过 AND或者OR合并,例如下面的例子:
... WHERE (h.owner.name = 'Harry' AND h.capacity > 100) OR (h.owner.name = 'Joe' AND h.capacity > 200)
下面是这些操作符的详细列表
NOT
颠倒当前的条件
... WHERE NOT (h.capacity > 100)
等价于:
... WHERE (h.capacity <= 100)
[NOT] LIKE
对字符串进行模式匹配,模式可以包含统配符: % 表示任意字符串, _ 表示单个字符串。统配符可以通过使用 ESCAPE后面跟一个换码符置换掉。
... WHERE h.state LIKE 'K%'
(将返回在 Kentucky 或者 Kansas的hotel)
... WHERE h.owner.name LIKE 'J__'
(两个下划线 '_')
(将返回 Joe拥有的hotel)
... WHERE h.id LIKE 'A_1%' ESCAPE ''
(将返回以 "A_1"开头的hotel。这里下划线 "_" 被反斜杠 ""置换掉)
[NOT] BETWEEN x AND y
检查是否在两个数值的范围中
... WHERE h.capacity BETWEEN 100 AND 200
IS [NOT] NULL
检查对象是否为 'null'.
... WHERE h.owner IS NULL
(返回owner为空的hotel)
[NOT] IN listOfStrings
在 WHERE中,检查一个字符串是否在一系列的字符串之中。 这与 FROM中的IN操作不同。
... WHERE h.state IN ('Ohio', 'Texas', ?1)
[NOT] MEMBER [OF]
检查一个值是否在一个集合中
... WHERE ?1 MEMBER OF h.rooms
(返回包含某一个的房间的 hotel )
=, <>
检查是否相等
... WHERE h.owner.name = 'Harry'
... WHERE h.owner.name <> 'Joe'
<, >, <=, >=
数字间的比较,对数字和日期有效
... WHERE h.capacity >= 100
IS [NOT] EMPTY
检查一个集合Collection中是否有元素
... WHERE h.rooms IS EMPTY
(返回没有房间的 hotels)
数据类型
EJB-QL中共有6中数据类型,它们可以用于返回值,参数,常量,变量。
Objects
它是一个一般的 Java object.。这样的一个object可以直接被映射为一个abstract schema name,,或者其它 object的成员
SELECT OBJECT(h)
FROM hotelSchemaName h
WHERE h.owner = ?1
(这里的object 为 h, h.owner 和 ?1)
Collections
可以表示为 range变量, 一个object的成员, 或者使用select方法时,返回值为 Collection
SELECT OBJECT(h)
FROM hotelSchemaName h
WHERE ?1 MEMBER OF h.rooms
(Collection 为 h.rooms)
SELECT OBJECT(h)
FROM hotelSchemaName h, IN h.rooms AS r
WHERE r = ?1
( Collections 为 r 和 h.rooms)
SELECT h
FROM hotelSchemaName
(返回所有hotel的Collection )
Strings
可以用作字符 参数,成员变量 ,或者单引号 '中定义的常量。
... WHERE h.owner.name = 'Harry'
(String为 h.owner.name (变量) 和 'Harry' (常量))
... WHERE h.owner.name = 'O''Sullivan'
(常量)
Numbers
可以用作数字参数,成员变量 ,常量。 number 可以为负数 (加 -) 或者小数 (加.),甚至是科学计数法。 integer 转换为 float是自动完成的 。
13
-16
17.2
1.98E4
45 + 12.1 (自动转换为 float)
Dates
日期其实是另一种形式的数字。如果用常量来表示, 就是从 01/01/1970 00:00:00 GMT后以秒为单位的一个数字。如果是 参数或者成员变量, 必须是一个 Date对象。
... WHERE reservation.arrivalDate = ?1
(这里的 date是成员变量 arrivalDate 和参数)
... WHERE reservation.arrivalDate < ??????? (这里的值需要计算)
Booleans
布尔型参数 或者成员变量,或者常量TRUE 或者 FALSE
... WHERE room.smoking = TRUE
字符串函数
LENGTH(s)
返回字符串的长度
... WHERE LENGTH(h.owner.name) > 3
LOCATE(s, substr [, startPosition])
返回以各子串在字符串中的位置。 当指定起始点后,子串的搜索从起始点开始。
... WHERE LOCATE(h.owner.name, 'rr') = 2
(Harry's hotel 会被返回)
... WHERE LOCATE(h.owner.name, 'rr', 3) >= 0
(从位置 3开始, Harry's hotel 将不会被返回)
CONCAT(s1, s2)
连接两个字符串为新的字符串
SELECT CONCAT (CONCAT( h.owner.name, ', the owner of '), h.name)
FROM hotelSchemaName AS h
(select方法返回所有的hotel的所有owner,返回值为一个字符类型的集合)
SUBSTRING(s, startPosition, length)
根据指定位置,指定的字符串数从字符串中得到一个字串。
... WHERE SUBSTRING(h.owner.name, 0, 2) = 'Jo'
(将会返回Joseph, Joe, 等, 等价于h.owner.name LIKE 'Jo%')
数字函数和操作
ABS(n)
返回一个数字的绝对值
SELECT ABS(a.balance)
FROM accountSchemaName AS a
WHERE a.balance < 0
(select方法将会返回所有的资产为负的记录,但返回值为正的)
SQRT(n)
返回数字的平方根
SELECT OBJECT(a)
FROM accountSchemaName AS a
WHERE SQRT(a.balance) = 2
(返回资产为4的账号)
+, -, *, /
加,减,乘,除操作
SELECT ABS(a.balance) FROM accountSchemaName AS a
WHERE a.balance + 1 = 5
(返回资产为4的账号)
SELECT OBJECT(h)
FROM hotelSchemaName AS h
WHERE h.capacity / 2 >= ?1
SELECT OBJECT(h)
FROM hotelSchemaName AS h
WHERE h.capacity >= ?1 * 2
(上面的两个查询都是返回指定容量双倍的hotel)
SELECT h.capacity - 10
FROM hotelSchemaName AS h
(返回 hotel的容量 ,返回值会减去10)