关联关系
关联关系概念
可以通过模型字段关联其它数据模型,对应模型字段会记录关联数据模型的数据ID。如学生表中可设置课程ID 字段为关联关系,查询时可以通过课程ID获取到关联课程的信息。
关联关系类型
数据库类型为云数据库(文档型):
当前支持关联关系类型:一对一、一对多、多对一;
数据库类型为云数据库(MySQL),或自有MySQL数据库:
当前支持关联关系类型:一对一、一对多、多对一、多对多;
关联关系删除行为
当前支持的删除行为:
- 删除关联模型数据
- 不删除关联模型数据
- 禁止删除存在关联关系的数据
数据模型关联关系举例说明
接下来,我们实机操作,以《学生信息管理系统》为需求背景,从数据库E-R设计延伸出数据模型设计,直到生产中如何使用模型操作数据。
说明:以下截图均来自云后台数据管理界面,登录请 点击这里
业务模型 E-R 图
《学生信息管理系统》主要做学生相关数据管理,其中包含多对一、多对多和一对一关系,如下图所示:
创建模型
基于业务需求,我们整理成表格信息,首先我们先依次创建出每个模型单体,不考虑关联关系。 说明:
- 红色表示多对一关系
- 绿色表示多对多关系
- 黄色表示一对一关系
- 关联关系方便展示,本小节先不关心,在下一小节使用
学生 | 班级 | 课程 | 学籍信息 |
---|---|---|---|
姓名 | 名称 | 编号 | 编号 |
年龄 | 年级 | 名称 | 学籍所在地 |
性别 | |||
所在班级 | 班内学生 | ||
所学课程 | 选课学生 | ||
学籍档案 | 绑定学生 |
创建模型时,我们统一使用云后台-数据管理-从空白创建-云开发MySQL数据库或者云数据库(文档型) 如果mysql数据库未拥有,可点击下方的初始化按钮,初始化完毕后继续操作
- 创建学生模型
如果没有性别枚举,可以在创建时新建选项集
- 创建班级模型
创建课程模型
创建学籍信息模型
创建关联关系
接下来我们来为模型建立关联关系,在云开发数据管理中关联关系是成对出现的,例如在学生和班级关系中(多对一关系),班级是学生的父模型(一方),那么学生就是班级的子模型(多方)。当我们成功为学生模型创建多对一关系关联班级模型后,班级模型中就会出现一对多关系关联学生模型。此时关联关系字段会自动关联目标模型的数据标识,即主键。
说明:
- 在编辑模式下,可以通过”添加一列“来继续创建关系字段
- 为了方便后续直观识别关系字段,我们将关系字段命名按照两个模型标识表示,如学生关联班级的字段是student_class,那么班级中成对的字段就是class_student,其他关系如是
- 在建立关系时,一定要分清当前主模型和关联模型的父子关系,从而选择对应字段类型
创建学生-班级多对一关系
创建学生-课程多对多关系
创建学生-学籍一对一关系
学生关联关系概览
班级、课程、学籍中对应的关系
这样我们将所有的模型都创建完毕,物理层的数据库存储也伴随模型而创建,接下来我们对数据进行操作,操作之前我们先对模型和物理存储的关系简明额要的阐述一下。
数据模型的物理意义
数据模型是业务需求的抽象,属于逻辑层含义,但实际进行数据存储和处理的还是物理层的数据库,为了更形象的解释其对应关系,我们采用关系型数据库 SQL 作为参照说明。
以下给出的 SQL 仅为了解释映射关系,而非实际存储
- 数据模型到物理存储
有同学肯定会问:既然模型字段和数据库列是一一对应的,为什么还需要数据模型,直接操作DB岂不更加直接明了?
- 首先,模型更容易理解更贴近自然语言,就好比面向对象语言之于汇编语言、 AIGC 之于人工智能、矿泉水之于冰山融雪...一一对应只是在当前业务场景下,更复杂的企业级模型可不一定哦
- 其次,模型更贴近业务的使用者而非底层逻辑的实现者,两者点亮的技能树不同
- 最后,模型身处逻辑层,屏蔽了来自物理层数据库的复杂设计和使用,最重要的是模型可以对接纷繁复杂眼花缭乱的各路数据库产品,云开发为广大开发者不仅提供了关系型数据库MySQL,还包括 NoSQL 数据库选项,都可以通过同一种模型接入
- 关联关系物理意义
- 前文不断强调要识别 多对一和一对多 关系中的父子模型概念,在数据模型中,这两者关系都是通过子模型的关联字段来维护的。比如“学生-班级”是多对一关系,学生是子模型班级是父模型,那么关联关系值的物理存储位置一定是子模型学生的关联列student_class
- 从上图 SQL 可以看出,在 多对多关系 中,关联关系并不维护在某一方模型,而是会有中间模型来维护,该中间模型不具有业务属性,而仅仅作为多对多关系维系的纽带,所以它并不开放给开发者
- 一对一 关系是特殊的多对一(或一对多)关系,物理存储位置同后者
以上,我们只是对模型和物理存储做浅尝即止的解释,为求在模型设计和数据操作时有更直观的理解,接下来我们利用创建好的模型做实机数据演示。
数据操作
创建数据
- 我们通过控制台,依次创建班级、课程、学生数据,最后创建学籍数据并绑定学生信息
- 如果使用sdk创建可参考下列方式,使用文档请 点击这里
// 创建班级
const { data } = await models.class.createMany({
data: [
{
name: "1班",
grade: "一年级"
},
{
name: "2班",
grade: "一年级"
}
],
});
// 创建课程
const { data } = await models.course.createMany({
data: [
{
name: "语文",
code: "001"
},
{
name: "数学",
code: "002"
}
],
});
// 创建学籍信息
const { data } = await models.profile.createMany({
data: [
{
code: "01",
address: "北京朝阳区"
},
{
code: " 02",
address: "上海虹桥区"
}
],
});
// 创建学生
const { data } = await models.student.createMany({
data: [
{
"name": "小明",
"birth": 6,
"gender": "1",
// 建立学籍一对一关系,_id为学籍数据标识
"student_profile": {
"_id": "9ZRF3VHQR6"
},
// 建立班级多对一关系,_id为班级数据标识
"student_class": {
"_id": "9ZREB4QKDS"
},
// 建立课程多对多关系,_id为课程数据标识
"student_course": [
{
"_id": "9ZREE51ERE"
},
{
"_id": "9ZREDFX4G8"
}
]
},
],
});
- 为了方便在控制台查看,重新编辑模型,将学生姓名、班级名称、课程名称、学籍编号设置为“主展示列”。
我们创建好的两条学生数据如下:
姓名name | 年龄birth | 性别gender | 学籍档案student_profile | 所在班级student_class | 所学课程 student_course | 数据标识 |
---|---|---|---|---|---|---|
小明 | 6 | 男 | 02 | 2 班 | 语文、数学 | 9ZREQJ0MPW |
小红 | 6 | 女 | 01 | 1 班 | 语文、数学 | 9ZREUB0FJ0 |
数据查询
我们用如下几个场景介绍关联关系的查询。
- 查询一年级 2 班所有的男生信息,包括班级、学籍和学习课程信息。
const { data } = await models.student.list({
// 展示参数,如果只展示当前模型非关联数据,可以使用 select:{$master:true}
select: {
_id: true,
name: true,
birth: true,
gender: true,
// 展示结果包含关联课程信息(多对多)
student_course: {
name: true,
code: true
},
// 展示结果包含班级信息(多对一)
student_class: {
name: true,
grade: true
},
// 展示结果包含学籍信息(一对一)
student_profile: {
code: true,
name: true
}
},
// 筛选条件,where指当前主模型条件;relateWhere指当前关联模型条件,其中relateWhere内的第一级参数为当前模型的关联字段,where内字段为关联模型字段
filter: {
// 条件:男生
where: {
$and: [
{
gender: {$eq: "1"}
}
]
},
// 条件:一年级 2 班
relateWhere: {
student_class:{ // 学生模型关联字段
where: {
$and:[
{
grade: {$eq: "一年级"} // 班级模型字段
},
{
name: {$eq: "2班"} // 班级模型字段
}
]
}
}
}
},
pageSize: 10, // 分页
pageNumber: 1, // 当前页数
getCount: true // 查询数据总数
}
});
// 返回查询到的数据列表 records 和 总数 total
console.log(JSON.stringify((data)));
// return
//{
// "records": [
// {
// "student_class": {"grade": "一年级","name": "2班","_id": "9ZREB4QKDS"},
// "gender": "1",
// "student_profile": {"code": " 02","_id": "9ZRF3VHQR6"},
// "name": "小明",
// "birth": 6,
// "_id": "9ZREQJ0MPW",
// "student_course": [
// {
// "code": "001",
// "name": "语文",
// "_id": "9ZREDFX4G8"
// },
// {
// "code": " 002",
// "name": "数学",
// "_id": "9ZREE51ERE"
// }
// ]
// }
// ],
// "total": 1
//}
查询所有学生信息,按姓名字典序排序
const { data } = await models.student.list({
select: {
$master:true // 展示学生模型所有非关联字段
},
filter: {
where: {}
},
orderBy:[
{
name: "DESC"
}
],
pageSize: 10,
pageNumber: 1,
getCount: true
});