Nest.js学习之路(18)-TypeORM(5)设定多对多

以角色为例,一个使用者拥有多个角色,一个角色包含多个使用者

流程跟设定多对一/一对多一样

  1. 建立Entity Class并设定@ManyToMany
  2. 新增DTO、Service 和上一节中创建User一样
  3. 新增@ManyToMany() inverse属性于另一端Entity class,并以@JoinTable()建立Join Table
  4. 修改UserDTO
  5. 在UsersService里修改新增代码
  6. 在UsersSerive里修改读取代码,载入关联属性
  7. 使用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,先测试新增使用者


Nest.js学习之路(18)-TypeORM(5)设定多对多_第1张图片
2018111402.png

列出使用者清单,看是否有储存关联资料


Nest.js学习之路(18)-TypeORM(5)设定多对多_第2张图片
2018111403.png

列出Role清单,看是否载入关联资料


Nest.js学习之路(18)-TypeORM(5)设定多对多_第3张图片
2018111404.png

推荐一下我的公众号: 【 geekjc 】,微信号: 【 c8706288 】一起学习交流编程知识,分享经验,各种有趣的事。

tuiguang.png

你可能感兴趣的:(Nest.js学习之路(18)-TypeORM(5)设定多对多)