關於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每天都好趕
hello您好 我想要請教一個問題
關於這邊//user.depId = data.depId; 不能只指定id,必須傳入department物件save的時候才會儲存關聯資料
想請問一定要傳入department物件才能關聯嗎,這樣做的目的是會優化查詢速度嗎?
如果直接存取data.depId,未來也能用find找到資料嗎?
不知道其中有甚麼差別,希望能幫助解答,謝謝。