在MyBatis中,实现一对多关系有两种方式:基于嵌套查询和基于嵌套结果。
1、基于嵌套查询
以学生成绩表和课程表的关系为例,在学生成绩表中,一个学生可以有多条成绩记录,每一条成绩记录都与某一门课程相关联。而在课程表中,每一门课程也会有多条成绩记录,因此它们之间就是一个典型的一对多关系。
我们可以采用嵌套的方式设计SQL语句,先查询学生成绩表,然后再根据课程ID字段查询课程表。具体步骤如下:
1)在Mapper文件中定义查询成绩的方法,同时在ResultMap中定义成绩信息(包括学生ID、学号、姓名、课程ID和成绩)以及嵌套的子查询语句。
代码语言:javascript复制<select id="selectScore" resultMap = "scoreResult">
SELECT s.student_id, s.student_no, s.name, s.course_id, s.score
FROM score s
</select>
<resultMap id="scoreResult" type="Score">
<id property="studentId" column="student_id"/>
<result property="studentNo" column="student_no"/>
<result property="name" column="name"/>
<collection property="courses" ofType="Course" resultMap="courseResult"/>
</resultMap>
<resultMap id="courseResult" type="Course">
<id property="id" column="id"/>
<result property="name" column="name"/>
</resultMap>
2)在Mapper文件中定义查询课程信息的方法,并在ResultMap中定义课程信息。
代码语言:javascript复制<select id="selectCourseById" parameterType="Integer" resultMap="courseResult">
SELECT course_id AS id, name
FROM course
WHERE course_id = #{id}
</select>
3)在Java代码中调用Mapper中的方法,获取所有学生的成绩列表。
代码语言:javascript复制public List<Score> selectAllScores() {
try(SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession()) {
return sqlSession.selectList("selectScore");
}
}
4)在返回结果中会得到多条学生成绩记录,每个记录中都包含有关该学生以及他们所属课程的信息。从结果中提取课程ID字段,然后调用查询课程信息的方法来获取相关联的课程详细信息。
代码语言:javascript复制public List<Score> selectAllScores() {
try(SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession()) {
List<Score> scores = sqlSession.selectList("selectScore");
for(Score score : scores) {
Integer courseId = score.getCourseId();
Course course = sqlSession.selectOne("selectCourseById", courseId);
score.setCourse(course);
}
return scores;
}
}
2、基于嵌套结果
另一种实现一对多关系的方式是基于嵌套结果,它允许我们将子结果映射到父结果中。使用此方法时,先定义含有多个属性的父实体类,然后定义该类与子实体类的关联关系。
以新闻分类和新闻列表为例,在新闻分类表中,每个分类可以包含多篇新闻,因此我们将它们之间的关系建立起来,并使用基于嵌套结果的方式查询。具体步骤如下:
1)在Mapper文件中定义查询新闻分类列表以及各分类下的新闻。在ResultMap中定义新闻分类信息(包括分类ID、分类名称)以及与之对应的所有新闻信息。
代码语言:javascript复制<select id="selectCategoryNews" resultMap="newsCategoryResult">
SELECT c.category_id, c.name, n.news_id, n.title, n.content
FROM category c LEFT JOIN news n ON c.category_id = n.category_id
ORDER BY c.category_id, n.news_id
</select>
<resultMap id="newsCategoryResult" type="NewsCategory">
<id property="categoryId" column="category_id"/>
<result property="name" column="name"/>
<collection property="newsList" ofType="News" resultMap="newsResult"/>
</resultMap>
<resultMap id="newsResult" type="News">
<id property="newsId" column="news_id"/>
<result property="title" column="title"/>
<result property="content" column="content"/>
</resultMap>
2)在Java代码中调用Mapper中的方法,获取所有新闻分类及其对应的新闻列表。
代码语言:javascript复制public List<NewsCategory> selectAllCategoriesWithNews() {
try(SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession()) {
return sqlSession.selectList("selectCategoryNews");
}
}
3)从查询结果中可得到多个新闻分类,它们及它们所属的新闻构成了一个嵌套的列表结构。可以将结果自动映射到含有父实体(NewsCategory)和子实体(News)的Java类中。
这样就完成了对一对多关系的查询。两种方式均可高效地实现一对多关系,并使数据的存取更加灵活。