在MyBatis中,實作一對多關系有兩種方式:基于嵌套查詢和基于嵌套結果。
1、基于嵌套查詢
以學生成績表和課程表的關系為例,在學生成績表中,一個學生可以有多條成績記錄,每一條成績記錄都與某一門課程相關聯。而在課程表中,每一門課程也會有多條成績記錄,是以它們之間就是一個典型的一對多關系。
我們可以采用嵌套的方式設計SQL語句,先查詢學生成績表,然後再根據課程ID字段查詢課程表。具體步驟如下:
1)在Mapper檔案中定義查詢成績的方法,同時在ResultMap中定義成績資訊(包括學生ID、學号、姓名、課程ID和成績)以及嵌套的子查詢語句。
<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中定義課程資訊。
<select id="selectCourseById" parameterType="Integer" resultMap="courseResult">
SELECT course_id AS id, name
FROM course
WHERE course_id = #{id}
</select>
3)在Java代碼中調用Mapper中的方法,擷取所有學生的成績清單。
public List<Score> selectAllScores() {
try(SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession()) {
return sqlSession.selectList("selectScore");
}
}
4)在傳回結果中會得到多條學生成績記錄,每個記錄中都包含有關該學生以及他們所屬課程的資訊。從結果中提取課程ID字段,然後調用查詢課程資訊的方法來擷取相關聯的課程詳細資訊。
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、分類名稱)以及與之對應的所有新聞資訊。
<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中的方法,擷取所有新聞分類及其對應的新聞清單。
public List<NewsCategory> selectAllCategoriesWithNews() {
try(SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession()) {
return sqlSession.selectList("selectCategoryNews");
}
}
3)從查詢結果中可得到多個新聞分類,它們及它們所屬的新聞構成了一個嵌套的清單結構。可以将結果自動映射到含有父實體(NewsCategory)和子實體(News)的Java類中。
這樣就完成了對一對多關系的查詢。兩種方式均可高效地實作一對多關系,并使資料的存取更加靈活。