多对多
多对多关联模型
满足条件:一个学生可以选择多个课程,一个课程也可以被多个学生选择 示例: student 学生表 class 课程表 student_has_class 中间表 >[danger] 多对多,需要借助第三个中间表,中间表包含了2个外键,分别是两个表的主键
我们假设有这样的一个场景,文章(Post)可以有多个标签(Tag),同样,一个Tag也可以对应多个Post,我们需要一张关联表PostTag来记录Post和Tag之间的关系。
一、model 建立3张模型表
- [ ] tag 表
- [ ] post 表
- [ ] post_tag 表
二、建立表关系
文章表 Post.belongsToMany(Tag, { through: { model: PostTag, unique: false, }, foreignKey: 'postId', //通过外键postId constraints: false });
标签表 Tag.belongsToMany(Post, { through: { model: PostTag, unique: false, }, foreignKey: 'tagId', //通过外键tagId constraints: false });
>[danger] 建议关联关系之后,Post会自动添加addTags、getTags、setTags方法。
Tag会自动添加addPosts、getPosts、setPosts方法。
## 三、添加
static async create(data) { //例如我们tag表有2条数据,[{id:1,name:'标签1'},{id:2,name:'标签2'}] //传递进来的data = {name:'文章1',tagIds:[1,2]} let newPost = await Post.create({name: data.name}); //返回创建的post对象 let tags = await Tag.findAll({where: {id: data['tagIds']}})//找到对应的tagId对象 await newPost.setTags(tags) //通过setTags方法在postTag表添加记录 return true
//以上操作会给post表创建一条新的记录,{id:1,name:'文章1'}
//给postTag表添加2条记录,[{id:1,postId:1,tagId:1},{id:2,post:1,tagId:2}]
}
![](https://www.xnip.cn/wp-content/uploads/2020/docimg10/1a0b8d7098ecd31596c538b090e9d265_579x360.png)
![](https://www.xnip.cn/wp-content/uploads/2020/docimg10/56daf427b4950f9183c79563df4d443a_477x194.png)
## 四、关联查询
static async allPost() { return await Post.findAll({ include: [ {model: Tag, attributes: ['id', 'name']} ] }); }
//查询结果 { "code": 200, "msg": "查询成功!", "data": [ { "createdAt": "2018-12-10 13:18:11", "updatedAt": "2018-12-10 13:18:11", "id": 1, "name": "文章1", "tags": [ { "createdAt": "2018-12-10 13:21:37", "updatedAt": "2018-12-10 13:21:37", "id": 1, "name": "标签1", "postTag": { "createdAt": "2018-12-10 13:18:11", "updatedAt": "2018-12-10 13:18:11", "id": 1, "postId": 1, "tagId": 1 } }, { "createdAt": "2018-12-10 13:21:37", "updatedAt": "2018-12-10 13:21:37", "id": 2, "name": "标签2", "postTag": { "createdAt": "2018-12-10 13:18:11", "updatedAt": "2018-12-10 13:18:11", "id": 2, "postId": 1, "tagId": 2 } } ] } ]
## 更新
static async updatePost(id, data) { //id为需要修改的ID,data = {name:'修改文章',tagIds:[1]} let tags = await Tag.findAll({where: {id: data['tagIds']}}) Post.findByPk(id).then(function (post) { post.update({name: data.name}) post.setTags(tags) }) return true }
## 事务
多表更新中,我们总担心那一步出错,导致后期难以维护,这里可以使用transaction事务来处理。一旦那一步出错,自动回滚。我拿创建那一步写个范例。
static async create(data) {
let tags = await Tag.findAll({where: {id: data['tagIds']}})
return Sequelize.transaction(function (t) {
return Post.create({name: data.name}, {transaction: t})
.then(function (post) {
return post.setTags(tags, {transaction: t})
});
}).then(function (result) {
// 事务已被提交 result 是 promise 链返回到事务回调的结果
}).catch(function (err) {
// 事务已被回滚 throw 抛出错误
throw err;
});
}