MybatisPlus二级映射和关联对象ResultMap

文章介绍了在在线教育平台中,如何使用MyBatis进行数据库操作,包括章节和资源的一对多和一对一映射,通过ChapterDto类展示如何在Mapper、Service和Controller层实现查询特定课程的详细结构。
摘要由CSDN通过智能技术生成

在我们的教程中,我们设计了一个课程内容的数据结构,包含章节和相关资源。这种结构非常适合在线教育平台或电子学习系统,其中课程内容需要被组织成不同的章节和子章节,每个子章节可能关联特定的学习资源。

这将是一个很好的示例来展示 MyBatis 中如何使用一对多(<collection>)和一对一(<association>)映射。

一、业务背景

1. 数据库表结构

  1. 章节表 (chapter)
    这张表包含所有章节的信息,其中包括大章节和小章节。大章节作为容器,可以包含多个小章节。
    • id (章节ID)
    • parent_id (父章节ID,用于区分大章节和小章节)
    • name (章节名称)
    • courseId (课程ID)
public class Chapter {
    private Long id;
    private Long parentId;
    private String name;
    private Long courseId;
}
  1. 资源表 (resource)
    这张表包含与小章节相关联的资源信息。
    • id (资源ID)
    • section_id (章节ID,关联到章节表)
    • name (资源名称)
public class Resource {
    private Long id;
    private Long sectionId;
    private String name;
}

2. 需求

要求根据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>

三、其他文件

1. Mapper

public interface ChapterMapper {
    List<ChapterDto> selectChaptersWithResources(Long courseId);
}

2. Service

@Service
public class ChapterService {
    @Autowired
    private ChapterMapper chapterMapper;

    public List<ChapterDto> getChaptersWithResources(Long courseId) {
        return chapterMapper.selectChaptersWithResources(courseId);
    }
}

3. Controller

@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)可能包含多个子章节。

聚合

这种聚合是根据您在 <collection> 标签中定义的规则进行的。MyBatis 会识别哪些行应该被映射为独立的实例,哪些行应该作为子元素聚合到其他实例中。

五、标签使用

1. <collection> 标签

用途:用于映射一对多关系。在这个例子中,ChapterDto类包含一个 Chapter 类型的列表,这代表了大章节和小章节之间的一对多关系。

常用属性

  • property:指定要映射到的目标属性名称。
  • ofType:指定集合中元素的类型。

2. <association> 标签

用途:用于映射一对一关系。在您的例子中,ChapterDto包含一个 Resource 类型的属性,这代表了小章节和资源之间的一对一关系。
常用属性

  • property:指定要映射到的目标属性名称。
  • javaType:指定关联对象的类型。

在这里插入图片描述

  • 32
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值