以角色為例,一個使用者擁有多個角色,一個角色包含多個使用者
流程跟設定多對一/一對多一樣
建立Role Entity
@Entity()
export class Role {
@PrimaryGeneratedColumn()
id: number;
@Column({
length: 50,
})
roleName: string;
@ManyToMany(type => User, user => user.roles) //設定bi-directional關聯
users: User[];
}
新增RoleDTO
import { IsString, MaxLength } from "class-validator";
export class RoleDTO {
@IsString()
@MaxLength(100)
roleName: string;
}
新增RoleService,記得註冊到Module
@Injectable()
export class RolesService {
constructor(
@InjectRepository(Role) // 注入 typeorm repository
private readonly roleRepo: Repository<Role>,
) {}
async addRole(roleDto: RoleDTO){
const role = new Role();
role.roleName = roleDto.roleName;
return await this.roleRepo.save(role);
}
async getRoleById(id){
return await this.roleRepo.findOne(id);
}
async getRolesByIds(ids){ //用在新增使用者時候要回傳Role[]
return await this.roleRepo.findByIds(ids);
}
async getRoles(){
return await this.roleRepo.find({relations:['users']}); //載入關聯屬性
}
}
修改appcontroller
...
@Get('role/list')
getRoles(){
return this.roleService.getRoles();
}
@Get('role/:roleId')
getRoleById(@Param('roleId') id){
return this.roleService.getRoleById(id);
}
@Post('role')
@UsePipes(new ValidationPipe({transform:true}))
addRole(@Body() roleDTO: RoleDTO){
return this.roleService.addRole(roleDTO);
}
...
修改user.entitie.ts,新增多對多關聯屬性
...
@ManyToOne(type => Department, dep => dep.users)
dep: Department;
@RelationId((user: User) => user.dep)
depId: number;
@ManyToMany(type => Role, role => role.users) //建立bi-directional多對多
@JoinTable() // 告訴typeorm要建立join table
roles: Role[];
...
修改userDTO,加入roleIds屬性
...
@IsNumber()
depId: number;
@IsNumber({
allowNaN: false,
allowInfinity:false,
},{each:true //檢查陣列每一個元素是否都是數字})
roleIds: number[];
...
修改user.service.ts
...
async addUser(data: UserDTO): Promise<User>{
const user = new User();
user.username = data.username;
user.email = data.email;
//user.depId = data.depId; 不能只指定id,必須傳入物件
user.dep = await this.depService.getDepById(data.depId);
// 先要取得role物件陣列,再指給user物件下的roles,save時才會儲存關聯
user.roles = await this.roleService.getRolesByIds(data.roleIds);
return await this.userRepo.save(user); // 新增一筆user資料
}
async getUsers(): Promise<User[]>{
return await this.userRepo.find({relations: ['dep', 'roles']}); // 載入dep及roles導覽屬性
}
async getUserById(id): Promise<User>{
return await this.userRepo.findOne(id, {relations: ['dep', 'roles']}); // 載入dep及roles導覽屬性
// return await this.userRepo.findOneOrFail(id); // 以id搜尋,沒找到會丟出例外
}
async updateUser(id, data: UserDTO){
const user = new User();
user.username = data.username;
user.email = data.email;
user.dep = await this.depService.getDepById(data.depId);
user.roles = await this.roleService.getRolesByIds(data.roleIds);
return await this.userRepo.update(id, user); // 用data裡的值更新到資料庫
}
...
使用postman測試
我已預先建立三個Role,先測試新增使用者
列出使用者清單,看是否有儲存關聯資料
列出Role清單,看是否載入關聯資料