很多应用(程序)需要使用特定的条件在数据库中查找实体BEANS。借助EJB-QL查询语言,实体BEANS可以在HOME接口中定义Find方法,通过实体BEAN的属性来查询。
加一个FIND方法需要做2步:
在HOME接口加一个FIND方法
在BEAN的部署描途中加入EJB-QL查询。
Resin-CMP使用EJB2.0规范的EJB-QL查询语言。EJB-QL类似SQL,为了适合于操作实体BEAN,EJB-QL与SQL相比,EJB-QL增加了一些限制和扩展。例如,EJB-QL扩展了SQL,直接支持关联和方法参数。
下而的例子,学校的校长需要知道当前有哪门课程正在上课和任课老师是谁。
Database Schema
Courses.sql
CREATE TABLE find_courses (
course_id VARCHAR(250) NOT NULL,
instructor VARCHAR(250),
PRIMARY KEY(course_id)
);
lEJB-QL
在findall 和 findByInstructor 方法中,使用EJB-QL从数据库中选取一个教师。EJB-QL类似于一个有一定限制的SQL,加入对关联和方法参数的直接支持。
findall方法查数据库所有的课程,schema 名字course 来自abctract-schena-ame。字段courseId是cmp-field 名字,这些名字不必与SQL的表名和列名一致。如果在部署配置中改变了SQL的表名和列名,EJB-QL仍然引用相同的abstract名字。
SELECT o FROM course o
findByInstructor 使用带参数instructor的方法查找课程,因为instructor是一个参数,它必须在查询中指定。EJB-QL使用参数的方法是?n。n是参数的序号,从1开始。
SELECT o FROM courses o WHERE o.instructor = ?1
Client Serverlet
在下面的例子中,我们列举三种find方法
1.通常使用的findByPriaryKey
2.返回集合 findAll
3.带一个instructor参数的findByInstructor
成对出现的本地对象和它的Home接口符合Home接口在Factory模式(设计模式中的工厂模式)中的角色(远程Home的Find方法永远返回远程接口或者远程接口的集合)
如果应用程序需要返回其它的值,包括本地Beans,需要调用ejbSelect方法。
findAll方法返回包含所有课程的集合。Client端在课程的集合上进行迭代遍历。
Findall Courses
...
Collection c = home.findAll();
Iterator iter = c.iterator();
while (iter.hasNext()) {
Course course = (Course) iter.next();
out.println(course.getCourseId() + " is taught by " +
course.getInstructor() + "<br>");
}
...
结果类似于下面:
Potions is taught by Severus Snape
Transfiguration is taught by Minerva McGonagall
Defense Against the Dark Arts is taught by Remus Lupin
上例中带参数instructor的findByInstructor方法返回一个教师所教授的课程,单值查找方法期望返回一个且只有一个结果。如果没有查找到结果,findByInstructor抛出一个ObjectNotFoundException异常。如果返回值多于一个,它将抛出一个FinderException(异常)。
Finding a Course by its Instructor
...
Course course = home.findByInstructor(teacher);
out.println(course.getCourseId() + " is taught by " +
course.getInstructor() + "<br>");
...
返加结果类似:
Potions is taught by Severus Snape
实体BEAN类
CourseHome接口定义了findAll和findByInstructor方法,同时有一个findByPrimaryKey方法,实现该接口的类中并不实现该方法,Resin-CMP会自动生成它的代码。
CourseHome.java
package example.cmp.find;
import java.util.*;
import javax.ejb.*;
public interface CourseHome extends EJBLocalHome {
Course findByPrimaryKey(String name)
throws FinderException;
Collection findAll()
throws FinderException;
Course findByInstructor(String instructor)
throws FinderException;
}
Course.java
package example.cmp.find;
import javax.ejb.*;
public interface Course extends EJBLocalObject {
String getCourseId();
String getInstructor();
}
CourseBean.java
package example.cmp.find;
abstract public class CourseBean
extends com.caucho.ejb.AbstractEntityBean {
abstract public String getCourseId();
abstract public String getInstructor();
}
Deployment Descriptor
Deployment Descriptor新特点是<query>节,虽然我们已经在sql-table和sql-column元素中定义了对象与数据库之间的映射,但查询用的是abstract 名字。
WEB-INF/cmp-find.ejb
<ejb-jar>
<enterprise-beans>
<entity>
<ejb-name>find_CourseBean</ejb-name>
<local-home>example.cmp.find.CourseHome</local-home>
<local>example.cmp.find.Course</local>
<ejb-class>example.cmp.find.CourseBean</ejb-class>
<persistence-type>Container</persistence-type>
<reentrant>True</reentrant>
<abstract-schema-name>courses</abstract-schema-name>
<sql-table>find_courses</sql-table>
<primkey-field>name</primkey-field>
<prim-key-class>String</prim-key-class>
<cmp-field><field-name>courseId</field-name></cmp-field>
<cmp-field>
<field-name>instructor</field-name>
<sql-column>teacher</sql-column>
</cmp-field>
<query>
<query-method>
<method-name>findAll</method-name>
</query-method>
<ejb-ql>SELECT o FROM courses o</ejb-ql>
</query>
<query>
<query-method>
<method-name>findByInstructor</method-name>
</query-method>
<ejb-ql>SELECT o FROM courses o WHERE o.instructor=?1</ejb-ql>
</query>
</entity>
</enterprise-beans>
</ejb-jar>
Tag Meaning
Query Contains the query information for a find method
Query-method The method descriptor
Method-name The method name
Ejb-ql The query for the find method