저장을 습관화
NestJS - TypeORM OneToMany, ManyToOne 본문
예를 들어,
사용자의 정보가 저장되는 Users 테이블과,
사용자가 작성한 게시글이 저장되는 Posts 테이블이 존재한다고 한다.
- users.entity.ts
import {
Column,
CreateDateColumn,
DeleteDateColumn,
Entity,
OneToMany,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
import { Posts } from '../posts/posts.entity';
@Entity({ name: 'Users' }) // DB에서 쓰일 테이블의 이름
export class Users {
@PrimaryGeneratedColumn({ type: 'int', name: 'id' })
id: number;
@Column('varchar', { name: 'email', unique: true, length: 30 })
email: string;
@Column('varchar', { name: 'nickname', length: 30 })
nickname: string;
@Column('varchar', { name: 'password', length: 100, select: false })
password: string;
@Column({ type: 'boolean', default: false })
isAdmin: boolean;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
@DeleteDateColumn()
deletedAt: Date | null;
// Relation
@OneToMany(() => Posts, (post: Posts) => post.user, {
cascade: true,
})
post: Posts[];
}
- posts.entity.ts
import { Users } from '../users/users.entity';
import {
Column,
CreateDateColumn,
DeleteDateColumn,
Entity,
JoinColumn,
ManyToOne,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
@Entity({ name: 'Posts' })
export class Posts {
@PrimaryGeneratedColumn({ type: 'int', name: 'id' })
id: number;
@Column({ type: 'int' })
userId: number;
@Column({ type: 'varchar' })
title: string;
@Column({ type: 'varchar' })
content: string;
@Column({ type: 'varchar', nullable: true })
imgUrl: string;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
@DeleteDateColumn()
deletedAt: Date | null;
// Relation
@ManyToOne(() => Users, (user: Users) => user.post, {
onDelete: 'CASCADE',
})
// 외래키 정보
@JoinColumn([
{
referencedColumnName: 'id',
name: 'userId',
},
])
user: Users[];
}
이때 하위 테이블이 되는 Posts에선
@ManyToOne 데코레이터로 하위 테이블임을 선언하고,
@JoinColumn 데코레이터를 이용하여 상대방(Users)의 컬럼 'id'가
본 테이블인 Posts의 컬럼 'UserId'가 된다고 선언하였다.
여기서 궁금한 점이 생겼다.
이렇게 선언이 다 끝난 상태인데, 왜 userId라는 실제 컬럼이 필요한 걸까?
심지어 TypeORM의 공식 문서에서도 이러한 내용은 없는데
테스트 1. 실제 컬럼 'userId'와 JoinColumn 데코레이터를 삭제하고 DB와 테이블을 재생성한다.
- posts.entity.ts
// ...
@Entity({ name: 'Posts' })
export class Posts {
@PrimaryGeneratedColumn({ type: 'int', name: 'id' })
id: number;
// @Column({ type: 'int' })
// userId: number;
// ...
@ManyToOne(() => Users, (user: Users) => user.post, {
onDelete: 'CASCADE',
})
// 외래키 정보
// @JoinColumn([
// {
// referencedColumnName: 'id', // 상대방 컬럼
// name: 'userId', // 여기서 쓸 컬럼
// },
// ])
user: Users[];
}
ManyToOne 데코레이터의 설정에 따라서 속성명 'user'와 'Id'가 붙어 외래키가 자동으로 생성되었다.
이 현상은 JoinColumn 데코레이터를 붙여줘도 동일한 결과였다.
하지만 이 경우 서비스 단에서 typeorm을 이용해서 데이터를 직접 입력할 수가 없었다.
- posts.service.ts
postman을 이용하여 POST한 결과
어째서 존재하는 컬럼에 데이터를 입력할 수 없는지가 궁금해서 질문을 해보니
다음과 같은 답변이 달렸다.
...
질문하신 내용은 TypeORM에서 엔티티 간의 관계를 맺을 때 외래키 컬럼을 별도로 작성하는 이유와 관련된 내용으로 보입니다. 이와 관련하여 유사한 질문에 대한 답변이 있는 게시글이 있어서 링크를 공유드립니다.
제로초님께서는 하위 테이블에서 외래키 컬럼을 별도로 작성하는 이유에 대해 답변하셨는데, 별도의 외래키 컬럼인 OwnerId가 실제로 존재하며, Owner는 join 후에 생성되는 속성(실제 컬럼이 아닌)으로, 둘을 모두 적는 이유는 외래키 컬럼 자체도 사용할 수 있게 하기 위함이라고 하셨습니다. 이를 통해 OwnerId와 같은 실제 컬럼값을 직접 컨트롤할 수 있게 하는 것입니다.
...
OwnerId는 실제로 존재하는 컬럼이고, Owner는 join 후에 생성되는 속성입니다(실제 컬럼이 아닙니다). 그래서 둘 다 적어준 것이고 공존이 가능한 것이고요.
Owner만 존재해도 되긴 하는데 OwnerId에 값을 직접 넣을 수는 없으므로 OwnerId를 따로 만들어서 직접 컨트롤할 수 있게 한 겁니다.
하위 테이블이 되는 엔티티에서 외래키 컬럼을 별도로 작성하는 이유가 궁금합니다 - 인프런
강의에서 OneToMany, ManyToOne 관계인 엔티티들을 보면/entity/Users.ts// ...@Entity({ schema: 'sleact', name: 'users' })export class Users {@PrimaryGeneratedColumn({ ty...
www.inflearn.com
다른 사람은 '이미 실제 컬럼 OwnerId가 존재하는데,
JoinColumn 에서 같은 이름으로 컬럼을 생성해도 되는가?'라고 질문했었다.
하지만 JoinColumn으로 생성되는 컬럼은 실제가 아니었기에 공존이 가능했고,
오히려 실제가 아니었기에 직접 컨트롤할 수 없으므로
이를 사용하기 위해선 실제 컬럼을 만들어주어야 한다라는 결론이 나왔다.
끝.
'공부 > node.js' 카테고리의 다른 글
NestJS - Swagger 데코레이더 정리 (0) | 2024.01.09 |
---|---|
NestJS - TypeORM CRUD (0) | 2023.12.29 |
NestJS - TypeORM 트랜잭션 (0) | 2023.12.28 |
에러 기록 - passport를 이용하여 로그인 시도 중 발생하는 401 Unauthorized 에러 (0) | 2023.12.22 |
NestJS의 라이프 사이클 (0) | 2023.12.20 |