多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] ### 多对多关联模型 满足条件:一个学生可以选择多个课程,一个课程也可以被多个学生选择 示例: ![](https://box.kancloud.cn/1e840ce844769077e3dda3a4f40c18ad_699x178.png) 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://box.kancloud.cn/1a0b8d7098ecd31596c538b090e9d265_579x360.png) ![](https://box.kancloud.cn/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; }); } ~~~