本文已参与「新人创作礼」活动,一起开启掘金创作之路。
书接上回,上次我们介绍了Nestjs中利用sequelize完成多表间(多对多、一对多)的查询操作。今天一起来看一下多表间的插入操作。
Nestjs使用sequelize完成多表操作(一对多、多对多)
注意:当我们用一条命令插入多张表的时候,sequelize其实也在帮我们生成多条sql语句。若此时部分sql没有被成功执行,并不会干涉成功的sql执行。此时肯定会造成脏数据的产生。所以涉及到多sql执行的时候大家最好用sequelize提供的事务方法。这样才能保证数据不被污染。本文着重讲解多表操作默认不会产生不成功sql。
先说一下我们的实现的需求(E-R模型基于专栏中的上篇博客)。要在用户注册的时候给用户分配一个角色。
先看一下在sequelize5.x的时候声明实例时候的一个坑
// users/user.model.ts
import {
Column,
Table,
Model,
HasMany,
BelongsToMany,
} from 'sequelize-typescript';
import { License } from '../licenses/license.model';
import { RoleUser } from '../role_users/role_user.model';
import { Role } from '../roles/role.model';
@Table({
tableName: 'admin_user',
timestamps: false,
})
export class User extends Model<User> { // 给Model范型我们的User
@Column
username: string;
@Column
password: string;
@Column
email: string;
@Column
mobile: string;
@Column
create_time: Date;
@HasMany(() => License)
licenses: License[];
@HasMany(() => RoleUser)
role_user: RoleUser[];
@BelongsToMany(() => Role, () => RoleUser)
roles: Role[];
}
而后在执行插入操作的时候就会有意想不到的bug
// users/user.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/sequelize';
import { User } from './user.model';
import { License } from '../licenses/license.model';
import { Role } from '../roles/role.model';
import { getLocalDate } from '../utils/index';
import { RoleUser } from '../role_users/role_user.model';
@Injectable()
export class UsersService {
constructor(
@InjectModel(User)
private userModel: typeof User
) {}
async create(user: User): Promise<User> {
await this.userModel.create(
{
username,
password,
email,
role_user: [{ role_id: 7 }], // 此时我们在RoleUser插入一条role_id为7(即给该新用户分配一个id为7的角色)的数据,user_id默认会取到本条User数据的id
},
{
include: RoleUser, // 注意:此时应该是在我们的RoleUser中加表插入一条数据,不是在Role表插入数据
},
);
return await User.findOne({ // 插入后查询数据验证
where: { username },
include: [Role],
});
}
}
TS会报错
大家可以看到这是ts报的缺少类型的错。此时有些类型是sequelize给实例挂上的如$add,我们无论如何是绕不过去的。此时有几个解决方案:
1.在该语句上加上一行注释// @ts-ignore。而后就可以完成插入操作了。这样显然有点治标不治本,显然不是很满意的方案
2.有人给ts提了issues。大家可以到github看下针对该问题的解决方案
3.因为在声明User实例的时候参考的是sequelize-typescript5.x的写法。在6.x的时候官方文档就建议在声明User类是继承Model的时候不要给范型了
export class User extends Model {
......
}
到这里可以看到插入语句就不再报错了。
我们再看一下sequelize给我们生成的sql。可以看到也是执行了两条sql操作。所以最好是用事务把两条操作包起来。避免数据污染
我们再用Postman测试一下,可以看到用户【小明】已经被插入数据库中并被分配了一个【普通用户的角色】