以角色为例,一个使用者拥有多个角色,一个角色包含多个使用者
流程跟设定多对一/一对多一样
- 建立Entity Class并设定@ManyToMany
- 新增DTO、Service 和上一节中创建User一样
- 新增@ManyToMany() inverse属性于另一端Entity class,并以@JoinTable()建立Join Table
- 修改UserDTO
- 在UsersService里修改新增代码
- 在UsersSerive里修改读取代码,载入关联属性
- 使用Postman测试
建立Role Entity
import {Entity, PrimaryGeneratedColumn, Column, ManyToMany} from 'typeorm';
import { User } from './User';
@Entity()
export class Role {
@PrimaryGeneratedColumn()
id: number;
@Column({
length: 50,
})
roleName: string;
@ManyToMany( type => User, user => user.roles)
users: User[];
}
新增RoleDTO
import { IsString, MaxLength } from 'class-validator';
export class RoleDTO {
@IsString()
@MaxLength(100)
roleName: string;
}
新增RoleService,记得注册到Module
import { Injectable } from '@nestjs/common';
import { Role } from 'shared/entity/Role';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { RoleDTO } from './roleDTO';
@Injectable()
export class RoleService {
constructor(
@InjectRepository(Role)
private readonly roleRepo: Repository,
) {}
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']}); // 载入关联属性
}
}
新增RoleController
import { Controller, Get, Param, Post, UsePipes, ValidationPipe, Body } from '@nestjs/common';
import { RoleService } from './role.service';
import { RoleDTO } from './roleDTO';
@Controller()
export class RoleController {
constructor(
private readonly roleService: RoleService,
) {}
@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,新增多对多关联属性
import {Entity, PrimaryGeneratedColumn, Column, ManyToOne, RelationId, ManyToMany, JoinTable} from 'typeorm';
import { Platform } from './Platform';
import { Role } from './Role';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
age: number;
@ManyToOne( type => Platform, platform => platform.users, {
onDelete: 'NO ACTION', // 如果刪除Platform,不会一并把UserEntity刪除,另有CASCADE就会
}) // 设定type为Platform,inverse property为Platform Entity里面的users属性,这个属性不会存到数据库
plat: Platform;
@RelationId((user: User) => user.plat)
platId: number;
@ManyToMany( type => Role, role => role.users ) // 建立bi-directional多对多
@JoinTable() // 告訴typeorm要建立join table
roles: Role[];
}
修改userDTO,加入roleIds
import { IsString, MaxLength, IsNumber } from 'class-validator';
import { Platform } from 'shared/entity/Platform';
import { Role } from 'shared/entity/Role';
export class UserDTO {
@IsString()
@MaxLength(100)
name: string;
@IsNumber()
age: number;
@IsNumber()
platId: number;
plat: Platform;
@IsNumber({
allowNaN: false,
allowInfinity: false,
}, { each: true, // 检查阵列每一个元素是否都是数字
})
roleIds: number[];
roles: Role[];
}
修改user.service.ts
import { Injectable } from '@nestjs/common';
import { User } from 'shared/entity/User';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { UserDTO } from './userDTO';
import { Platform } from 'shared/entity/Platform';
import { PlatformService } from 'feature/platform/platform.service';
import { RoleService } from 'feature/role/role.service';
@Injectable()
export class UserService {
constructor(
@InjectRepository(User)
private readonly userRepo: Repository,
private platformService: PlatformService,
private roleService: RoleService,
) {}
async addUser(userDTO: UserDTO) {
const user = new UserDTO();
user.name = userDTO.name;
user.age = userDTO.age;
// user.platId = data.platId; 不能只指定id,必须传入platform对象save的时候才会储存关联资料
user.plat = await this.platformService.getPlatformById(userDTO.platId);
// 先要取得role,再指给user物件下的roles,save时才会存储关联
user.roles = await this.roleService.getRolesByIds(userDTO.roleIds);
return await this.userRepo.save(user);
}
async getUsers(): Promise{
return await this.userRepo.find({relations: ['plat', 'roles']}); // relations指定载入关联属性,是阵列,可能有多个导出属性
}
async getUserById(id) {
return await this.userRepo.findOne(id, {relations: ['plat', 'roles']});
// relations指定载入关联属性,是阵列,可能有多个导览属性
// return await this.userRepo.findOneOrFail(id); // 以id搜寻,没找到会丢出例外
}
async updateUser(id, data: UserDTO){
const user = new User();
user.name = data.name;
user.age = data.age;
user.plat = await this.platformService.getPlatformById(data.platId);
return await this.userRepo.update(id, user); // 用data里的值更新到数据库
}
}
使用postman测试
我已预先建立三个Role,先测试新增使用者
列出使用者清单,看是否有储存关联资料
列出Role清单,看是否载入关联资料
推荐一下我的公众号: 【 geekjc 】,微信号: 【 c8706288 】一起学习交流编程知识,分享经验,各种有趣的事。