iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 17
0
Modern Web

讀官網文件邊走邊學nest.js系列 第 17

Day17-TypeORM(四)設定一對多/多對一

關於TypeORM設定一對多/多對一參考官網教學

假設新增部門entitiy,使得一個部門有多個使用者

新增部門entity,新增users屬性並設定@OneToMany()

@Entity("Departments")
export class Department {
    @PrimaryGeneratedColumn()
    id: number;

    @Column({
        length: 100,
    })
    depName: string;
    
    @OneToMany(type => User, user => user.dep) // type指定User, 第二個引數是function預設傳入第一個引數的type,這邊需要設定inverse屬性,user entity裡的dep屬性,這個屬性不會存到資料庫
    users: User[];

}

新增Deparment屬性以及foreign key於user.ts

@Entity('My_Users') // 指定table name
export class User {
    @PrimaryGeneratedColumn()
    id: number;
    // @Column為對應的資料庫欄位,或是傳入Column Options物件
    @Column()
    username: string;
   
    ...

    @ManyToOne(type => Department, dep => dep.users
    ,{
        onDelete: 'NO ACTION', // 如果刪除Department,不會一併把UserEntity刪除,另有CASCADE就會
     },
    ) // 設定type為Department,inverse property為Department Entity裡面的users屬性,這個屬性不會存到資料庫
    dep: Department;

    @RelationId((user: User) => user.dep) //指定foreignkey,要設定inverse property
    depId: number;
    
}

建立department.service.ts及depDTO.ts

@Injectable()
export class DepartmentService {
    constructor(
        @InjectRepository(Department) // 注入 typeorm repository
        private readonly depRepo: Repository<Department>,
    ) {}
    
    async addDep(depDto: DepartmentDTO){
        const dep = new Department();
        dep.depName = depDto.depName;
        return await this.depRepo.save(dep);
    }

    async getDepById(id){
        return await this.depRepo.findOne(id);
    }
}

export class DepartmentDTO {
    @IsString()
    @MaxLength(100)
    depName: string;
}

app.controller新增方法

export class AppController {
  constructor(
    private usersService: UsersService,
    private depService: DepartmentService){
  }
  
  ...
  
  @Post('dep')
  @UsePipes(new ValidationPipe({transform:true})) //自動把string轉成int
  addDep(@Body() depDTO: DepartmentDTO){
    return this.depService.addDep(depDTO);
  }
  
}

使用postman新增department

加入depId於userDTO,新增User時指定所屬部門

export class UserDTO {
    
    ...
    @IsNumber()
    depId: number;
}

把app.service與user相關的方法抽出來成為user.service.ts,並修改新增與修改邏輯,

@Injectable()
export class UsersService {
    constructor(
        @InjectRepository(User) // 注入 typeorm repository
        private readonly userRepo: Repository<User>,
        private depService: DepartmentService,
      ){}
      
    
      async addUser(data: UserDTO): Promise<User>{
        const user = new User();
        user.username = data.username;
        user.email = data.email;
        //user.depId  = data.depId; 不能只指定id,必須傳入department物件save的時候才會儲存關聯資料
        user.dep = await this.depService.getDepById(data.depId);
        return await this.userRepo.save(user); // 新增一筆user資料
      }
      
      async getUsers(): Promise<User[]>{
        return await this.userRepo.find({relations: ['dep']}); // relations指定載入關聯屬性,是陣列,可能有多個導覽屬性
      }
    
      async getUserById(id): Promise<User>{
        return await this.userRepo.findOne(id, {relations: ['dep']}); // relations指定載入關聯屬性,是陣列,可能有多個導覽屬性
        // 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);
        return await this.userRepo.update(id, user); // 用data裡的值更新到資料庫
      }
    
      ...
}

使用postman測試

Github source code
每天都好趕


上一篇
Day16-TypeORM(三) basic CRUD
下一篇
Day18-TypeORM(五) 設定多對多
系列文
讀官網文件邊走邊學nest.js31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
hank861299
iT邦新手 5 級 ‧ 2021-02-06 10:47:37

hello您好 我想要請教一個問題

關於這邊//user.depId = data.depId; 不能只指定id,必須傳入department物件save的時候才會儲存關聯資料

想請問一定要傳入department物件才能關聯嗎,這樣做的目的是會優化查詢速度嗎?
如果直接存取data.depId,未來也能用find找到資料嗎?

不知道其中有甚麼差別,希望能幫助解答,謝謝。

我要留言

立即登入留言