在我们的教程中,我们设计了一个课程内容的数据结构,包含章节和相关资源。这种结构非常适合在线教育平台或电子学习系统,其中课程内容需要被组织成不同的章节和子章节,每个子章节可能关联特定的学习资源。
这将是一个很好的示例来展示 MyBatis 中如何使用一对多(
)和一对一(
)映射。
chapter
)id
(章节ID)parent_id
(父章节ID,用于区分大章节和小章节)name
(章节名称)courseId
(课程ID)public class Chapter {
private Long id;
private Long parentId;
private String name;
private Long courseId;
}
resource
)id
(资源ID)section_id
(章节ID,关联到章节表)name
(资源名称)public class Resource {
private Long id;
private Long sectionId;
private String name;
}
要求根据courseId
查询出指定课程的信息,包括大章节、小章节、资源,并以一定结构返回,比如
[
{
"id": 1,
"parentId": null,
"name": "Chapter 1",
"courseId": 100,
"subChapters": [
{
"id": 11,
"parentId": 1,
"name": "Section 1.1",
"courseId": 100,
"resource": {
"id": 101,
"sectionId": 11,
"name": "Introduction Video"
}
},
{
"id": 12,
"parentId": 1,
"name": "Section 1.2",
"courseId": 100,
"resource": null
}
],
"resource": null
}
// other...
]
所以我们定义一个Dto
如下
public class ChapterDto extends Chapter {
private List<ChapterDto> subChapters;
private Resource resource;
// 构造器、getter和setter
}
在 ChapterMapper.xml
文件中,我们定义 SQL 查询以及结果映射。
<mapper namespace="com.example.mapper.ChapterMapper">
<resultMap id="ChapterDtoMap" type="com.example.dto.ChapterDto">
<id column="chapter_id" property="id" />
<result column="parent_id" property="parentId" />
<result column="name" property="name" />
<result column="courseId" property="courseId" />
<collection property="subChapters" ofType="com.example.dto.ChapterDto">
<id column="sub_chapter_id" property="id" />
<result column="sub_parent_id" property="parentId" />
<result column="sub_name" property="name" />
<result column="sub_courseId" property="courseId" />
<association property="resource" javaType="com.example.model.Resource">
<id column="resource_id" property="id" />
<result column="section_id" property="sectionId" />
<result column="resource_name" property="name" />
association>
collection>
resultMap>
<select id="selectChaptersWithResources" resultMap="ChapterDtoMap">
SELECT
c.id AS chapter_id, c.parent_id, c.name, c.courseId,
sc.id AS sub_chapter_id, sc.parent_id AS sub_parent_id, sc.name AS sub_name, sc.courseId AS sub_courseId,
r.id AS resource_id, r.section_id, r.name AS resource_name
FROM
chapter c
LEFT JOIN
chapter sc ON c.id = sc.parent_id
LEFT JOIN
resource r ON sc.id = r.section_id
WHERE
c.courseId = #{courseId} AND c.parent_id IS NULL
select>
mapper>
public interface ChapterMapper {
List<ChapterDto> selectChaptersWithResources(Long courseId);
}
@Service
public class ChapterService {
@Autowired
private ChapterMapper chapterMapper;
public List<ChapterDto> getChaptersWithResources(Long courseId) {
return chapterMapper.selectChaptersWithResources(courseId);
}
}
@RestController
@RequestMapping("/chapters")
public class ChapterController {
@Autowired
private ChapterService chapterService;
@GetMapping("/{courseId}")
public ResponseEntity<List<ChapterDto>> getChapters(@PathVariable Long courseId) {
List<ChapterDto> chapters = chapterService.getChaptersWithResources(courseId);
return ResponseEntity.ok(chapters);
}
}
在提供的 resultMap
中,一级映射是针对 ChapterDto
类的直接属性的映射。这意味着数据库中的列(如 chapter_id, parent_id等)直接映射到 ChapterDto
类的相应属性(如 id, parent_id等),这部分映射是非常直接的。
二级映射用于处理复杂的对象关系,比如当一个对象包含其他对象或对象的集合
时。这通常在处理一对多关系时出现,例如,一个章节结构(ChapterDto
)可能包含多个子章节。
这种聚合是根据您在
标签中定义的规则进行的。MyBatis 会识别哪些行应该被映射为独立的实例,哪些行应该作为子元素聚合到其他实例中。
用途:用于映射一对多关系。在这个例子中,ChapterDto
类包含一个 Chapter
类型的列表,这代表了大章节和小章节之间的一对多关系。
常用属性:
property
:指定要映射到的目标属性名称。ofType
:指定集合中元素的类型。用途:用于映射一对一关系。在您的例子中,ChapterDto
包含一个 Resource
类型的属性,这代表了小章节和资源之间的一对一关系。
常用属性:
property
:指定要映射到的目标属性名称。javaType
:指定关联对象的类型。