分析实体Bean的应用时,会发现应用数据之间往往存在一些关系,这些数据本身对应的数据表之间存在着表项字段的关系,这些关系需要实体Bean来维护。EJB 2.0为实体Bean提供了对关系的全面支持,实现了CMR。
EJB 2.0对关系的支持给开发提供了很大方便,EJB 2.0的关系包括单项关系和双向关系,从对象数量上分为一对一、一对多和多对多3种,下面将通过实例来说明。
下面School的例子要复杂一些,由5个实体Bean组成,它们之间存在着一定的关系,具体关系如图3-13所示。
 
图3-13 School关系示图
表达这些实体Bean和它们之间的关系,需要在配置文件中体现,首先在jboss.xml中声明这5个实体Bean:
<?xml version="1.0"?>
<jboss>
<enterprise-beans>
<entity>
<ejb-name>TeacherBean</ejb-name>
<local-jndi-name>cmp/teacherLocal</local-jndi-name>
</entity>
<entity>
<ejb-name>ClassBean</ejb-name>
<local-jndi-name>cmp/classLocal</local-jndi-name>
</entity>
<entity>
<ejb-name>ClassroomBean</ejb-name>
<local-jndi-name>cmp/classroomLocal</local-jndi-name>
</entity>
<entity>
<ejb-name>StudentBean</ejb-name>
<local-jndi-name>cmp/studentLocal</local-jndi-name>
</entity>
<entity>
<ejb-name>GradeBean</ejb-name>
<local-jndi-name>cmp/gradeLocal</local-jndi-name>
</entity>
</enterprise-beans>
</jboss>
这里全部使用了本地对象。这个例子的重点不在jbosscmp-jdbc.xml,所有的新内容都在ejb-jar.xml中定义,ejb-jar.xml中声明了5个实体Bean之间存在4种关系,如下所示。
1.TeacherToClass关系
对于teacher与class的关系,一个老师通常会教多个班级,所以是一对多的关系。和从前一样,先定义这两个实体Bean:
<entity>
<description>Teacher</description>
<ejb-name>TeacherBean</ejb-name>
<local-home>com.liuyang.ejb.cmp.Teacher.TeacherLocalHome</local-home>
<local>com.liuyang.ejb.cmp.Teacher.TeacherLocal</local>
<ejb-class>com.liuyang.ejb.cmp.Teacher.TeacherBean</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.Integer</prim-key-class>
<transaction-type>Container</transaction-type>
<reentrant>False</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>TeacherBean</abstract-schema-name>
<cmp-field><field-name>teacherId</field-name></cmp-field>
<cmp-field><field-name>teacherName</field-name></cmp-field>
<cmp-field><field-name>sex</field-name></cmp-field>
<cmp-field><field-name>birthday</field-name></cmp-field>
<primkey-field>teacherId</primkey-field>
</entity>
Teacher包含: teacherId, teacherName, sex, birthday四个数据项,其中teacherId是主键。
<entity>
<description>Class</description>
<ejb-name>ClassBean</ejb-name>
<local-home>com.liuyang.ejb.cmp.Class.ClassLocalHome</local-home>
<local>com.liuyang.ejb.cmp.Class.ClassLocal</local>
<ejb-class>com.liuyang.ejb.cmp.Class.ClassBean</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.String</prim-key-class>
<transaction-type>Container</transaction-type>
<reentrant>False</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>ClassBean</abstract-schema-name>
<cmp-field><field-name>classId</field-name></cmp-field>
<primkey-field>classId</primkey-field>
</entity>
Class包含classId一个数据项,classId是主键。
在两个实体Bean之间建立关系需要定义两个实体对象,这里是teacher和Class,它们之间的关系定义用如下的方式描述:
<ejb-relation>
<ejb-relation-name>TeacherToClass</ejb-relation-name>
<ejb-relationship-role>
<ejb-relationship-role-name>Teacher-has-Classes</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<relationship-role-source>
<ejb-name>TeacherBean</ejb-name>
</relationship-role-source>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>Class-belongsto-Teacher</ejb- relationship-role-name>
<multiplicity>Many</multiplicity>
<relationship-role-source>
<ejb-name>ClassBean</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>teacher</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
</ejb-relation>
一个关系有两个关系角色组成,一个是由teacher指向class的Teacher-has-Classes,另一个是由class指向teacher的Class-belongsto-Teacher,所以一个关系的定义被分成两个关系角色的定义。
<multiplicity>One</multiplicity>
multiplicity用来规定一个关系角色的数量,这里的数量可以是one,即1个,或者Many,即多个。
<relationship-role-source>
<ejb-name>TeacherBean</ejb-name>
</relationship-role-source>
relationship-role-source用来规定关系角色的EJB对象。注意,这里使用的是EJB的名字,而不是JNDI的名字。
<cmr-field>
<cmr-field-name>teacher</cmr-field-name>
</cmr-field>
最重要的是cmr-field, CMR(Container Manager Relationship)是CMP 2.0的新特性,CMR为程序员实现数据之间的关系提供了极大的方便,可以定义一些CMR,并在实体Bean的类中给出对应的get()和set()方法,目的是存取关系项。这些关系项不是原有实体Bean的数据项,而是由容器管理的数据项,比如下面的定义:
<cmr-field-name>teacher</cmr-field-name>
对应地需要在ClassBean的实现代码中加入如下代码:
public abstract TeacherLocal getTeacher();
public abstract void setTeacher(TeacherLocal teacher);
这两个方法由容器实现,但是必须在这里声明它们。同时为了能够通过接口使用这两个方法,还需在对应的object接口(ClassLocal)中添加这两个方法:
public TeacherLocal getTeacher();
public void setTeacher(TeacherLocal teacher);
这样就可以通过object接口调用CMR方法了。由此可见CMR简化了我们开发数据表之间关系的实现过程。
2.ClassToClassroom关系
与前面的关系不同,ClassToClassroom是一对一的关系,它包含一个CMR:
<cmr-field>
<cmr-field-name>classroom</cmr-field-name>
</cmr-field>
所以在object接口(ClassLocal)中添加两个相应的方法:
public ClassroomLocal getClassroom();
public void setClassroom(ClassroomLocal room);
在ClassBean的实现代码中加入如下内容:
public abstract ClassroomLocal getClassroom();
public abstract void setClassroom(ClassroomLocal room);
这两个关系的例子,展示了如何定义一个一对多或一对一的方法,但是只在一个关系角色中使用了CMR,这让你懂得了关系的用法,下面的这个关系示例要复杂一点。
3.ClassToStudents关系
<ejb-relation>
<ejb-relation-name>ClassToStudents</ejb-relation-name>
<ejb-relationship-role>
<ejb-relationship-role-name>Class-has-Students</ejb-relationship- role-name>
<multiplicity>One</multiplicity>
<relationship-role-source>
<ejb-name>ClassBean</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>students</cmr-field-name>
<cmr-field-type>java.util.Collection</cmr-field-type>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>Students-belongsto-Class</ejb- relationship-role-name>
<multiplicity>Many</multiplicity>
<relationship-role-source>
<ejb-name>StudentBean</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>myclass</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
</ejb-relation>
ClassToStudents是一对多的关系,一个学生属于一个班,而一个班有很多学生,我们为一个班(class)对象设计了一个CMR,如下:
<cmr-field>
<cmr-field-name>students</cmr-field-name>
<cmr-field-type>java.util.Collection</cmr-field-type>
</cmr-field>
使用这个CMR可以管理一个class对应的多个student对象。这里需要为students指定一个集合类型,在前面的章节中,我们为CMP指定集合对象时提到过两种集合类Collection和Enumeration,这里我们仍然可以使用Collection,但是Enumeration不可以使用,除了Collection,你在这里还可以使用java.util.Set。
这里我使用了java.util.Collection,所以在object接口(ClassLocal)中添加两个相应的方法:
public Collection getStudents();
public void setStudents(Collection students);
在ClassBean的实现代码中加入对应方法:
public abstract Collection getStudents();
public abstract void setStudents(Collection students);
这个关系的另一端角色中包含另一个CMR:
<cmr-field>
<cmr-field-name>myclass</cmr-field-name>
</cmr-field>
这个CMR为一个student对象提供了访问其所在class的方法,在对应的Student- Local中加入下面两个方法:
public ClassLocal getMyclass();
public void setMyclass(ClassLocal myclass);
在StudentBean(student的实现类)中加入如下内容:
public abstract ClassLocal getMyclass();
public abstract void setMyclass(ClassLocal myclass);
4.StudentToGrade关系
这个关系是一个学生和年级之间的一对一关系,在这个例子中两个关系角色各包含一个CMR:
<ejb-relation>
<ejb-relation-name>StudentToGrade</ejb-relation-name>
<ejb-relationship-role>
<ejb-relationship-role-name>Student-has-Grade</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<relationship-role-source>
<ejb-name>StudentBean</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>grade</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>Grade-belongsto-Student</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<cascade-delete/>
<relationship-role-source>
<ejb-name>GradeBean</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>student</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
</ejb-relation>
对应两个CMR,分别在object接口和实现类中加入代码,如在StudentLocal中加入:
public GradeLocal getGrade();
public void setGrade(GradeLocal grade);
在StudentBean中加入:
public abstract GradeLocal getGrade();
public abstract void setGrade(GradeLocal grade);
在GradeLocal中加入:
public StudentLocal getStudent();
public void setStudent(StudentLocal student);
在GradeBean中加入:
public abstract StudentLocal getStudent();
public abstract void setStudent(StudentLocal student);
至此,已经介绍了一对一、一对多关系的用法,至于多对多关系的用法与一对多类似,只不过将One对Many改成Many对Many,然后写两个你需要的CMR。CMR与CMP数据类似,访问数据项时可以像使用CMP一样使用CMR的get()和set()方法。
|