好久没写MyBatis了,今天继续。
处理has-one关系需要用到association元素,而处理has many关系则需要用到collection元素。例如本例中,假设一名教师可同时指导多名学生,下面就来介绍如何使用collection元素来实现这种映射,具体的任务是查询出教师及其指导的多个学生的信息(本示例源代码下载页面:http://down.51cto.com/data/490947)。
一、为Teacher实体增加相关属性
为教师实体增加指导学生集合的属性如下:
1
|
private List<Student> supStudents; //指导学生
|
并为其增加setter和getter方法,这里略过。
二、TeacherMapper接口
为实现教师实体映射,应先创建映射器接口如下:
1
2
3
4
5
|
package com.abc.mapper;
import com.abc.domain.Teacher;
public interface TeacherMapper {
public Teacher getById( int id);
} |
三、映射文件
为教师实体创建的映射文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<? xml version = "1.0" encoding = "utf8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--与以前一样,namespace的值是对应的映射器接口的完整名称--> < mapper namespace = "com.abc.mapper.TeacherMapper" >
<!--TeacherMapper接口中getById方法对应的SQL语句。 查询教师及其指导的学生的信息。由于教师、学生都有 id、name、gender等属性,因此给教师的字段都起了别名--> < select id = "getById" parameterType = "int" resultMap = "supervisorResultMap" >
select t.id t_id, t.name t_name, t.gender t_gender, t.research_area t_research_area, t.title t_title, s.id,s.name, s.gender,s.major,s.grade from teacher t,student s where t.id=#{id} and s.supervisor_id = t.id </ select >
<!--教师实体映射--> < resultMap id = "supervisorResultMap" type = "Teacher" >
< id property = "id" column = "t_id" />
< result property = "name" column = "t_name" />
< result property = "gender" column = "t_gender" />
< result property = "researchArea" column = "t_research_area" />
< result property = "title" column = "t_title" />
<!--collection元素映射教师的指导学生集合的属性。resultMap 以命名空间名.resultMap的id的形式,引用studentResultMap。 需要注意的是,上面的select语句中学生的字段名/别名应与 studentResultMap中的column属性一致--> < collection property = "supStudents"
resultMap = "com.abc.mapper.StudentMapper.studentResultMap" />
</ resultMap >
</ mapper >
|
相应地,学生实体的映射文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<? xml version = "1.0" encoding = "utf8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> < mapper namespace = "com.abc.mapper.StudentMapper" >
< resultMap id = "studentResultMap" type = "Student" >
< id property = "id" column = "id" />
< result property = "name" column = "name" />
< result property = "gender" column = "gender" />
< result property = "major" column = "major" />
< result property = "grade" column = "grade" />
<!--相应地,在此引用supervisorResultMap,亦采用 命名空间名.resultMap的id的形式。--> < association property = "supervisor"
resultMap = "com.abc.mapper.TeacherMapper.supervisorResultMap" />
</ resultMap >
</ mapper >
|
在工程的src\resources目录下新建子目录mappers,用来统一存放映射文件。为了能让MyBatis找到这些映射文件,修改其核心配置文件configuration.xml中的mappers元素如下:
1
2
3
4
5
|
<!--在classpath中以相对路径的形式引用映射文件--> < mappers >
< mapper resource = "resources/mappers/StudentMapper.xml" />
< mapper resource = "resources/mappers/TeacherMapper.xml" />
</ mappers >
|
注意:resources目录在工程编译前会被复制到classes目录下(详见工程生成文件build.xml中的copy-resources和compile这两个target),而classes目录会被ant添加到classpath中。
四、执行类
执行类为CollectionDemo,其内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
package com.demo;
import org.springframework.context.ApplicationContext;
import com.abc.mapper.StudentMapper;
import com.abc.mapper.TeacherMapper;
import com.abc.domain.Teacher;
import com.abc.domain.Student;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class CollectionDemo
{ private static ApplicationContext ctx;
static { //在类路径下寻找resources/beans.xml文件 ctx = new ClassPathXmlApplicationContext( "resources/beans.xml" );
} public static void main(String[] args)
{ //从Spring容器中请求映射器 TeacherMapper mapper = (TeacherMapper)ctx.getBean( "teacherMapper" );
//查询id为1的教师 Teacher teacher = mapper.getById( 1 );
if (teacher == null )
{ System.out.println( "未找到相关教师信息。" );
} else { //教师信息 System.out.println( "**********************************************" );
System.out.println( "教师姓名:" + " " + teacher.getName());
System.out.println( "教师职称:" + " " + teacher.getTitle());
System.out.println( "**********************************************" );
System.out.println( "指导学生信息:" );
//遍历指导的学生 for (Student s : teacher.getSupStudents())
{ System.out.println( "**********************************************" );
System.out.println( s.getName() + " " + s.getGender() + " " + s.getGrade()
+ " " + s.getMajor());
//从学生端访问教师 System.out.println( "指导教师研究方向:" + s.getSupervisor().getResearchArea());
} System.out.println( "**********************************************" );
} } } |
从中可看出,可以从任意一端访问另一端的对象。
五、修改build.xml
为了能用ant运行此程序,需修改build.xml中的run target,指定类CollectionDemo为执行类。如下:
1
2
3
4
5
6
7
8
9
|
< target name = "run" depends = "compile" >
<!--指定CollectionDemo为要运行的类--> < java fork = "true" classname = "com.demo.CollectionDemo"
classpathref = "library" >
<!--把classes目录添加到工程的classpath中。 ${targetdir}是指引用上面定义的property元素targetdir--> < classpath path = "${targetdir}" />
</ java >
</ target >
|
运行结果如下: