@OneToOne(() => Profile)
@JoinColumn()
profile: Profile;
한 엔티티가 여러 엔티티와 연관되거나, 여러 엔티티가 하나의 엔티티와 연관됩니다. 예를 들어, 한 사용자가 여러 게시물을 작성할 수 있다.
@OneToMany(() => Post, post => post.user)
posts: Post[];
@ManyToOne(() => User, user => user.posts)
user: User;
@ManyToMany(() => Subject)
@JoinTable()
subjects: Subject[];
true로 설정하면, 관계된 엔티티를 자동으로 로드한다.cascade: true 또는 cascade: ['insert', 'update']'RESTRICT', 'CASCADE', 'SET NULL'NULL을 허용할지 여부를 설정한다.'nullify', 'delete', 'soft-delete', 'disable'cascade는 연관된 엔티티도 함께 저장(insert), 수정(update), 삭제(remove)할 수 있도록 하는 옵션
Question 엔티티를 저장할 때, 연결된 Category 엔티티도 자동으로 저장되게 만들 수 있다.@ManyToMany, @OneToMany, @OneToOne 등의 관계 설정에 cascade 옵션을 지정한다.@Entity()
export class Category {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@ManyToMany(() => Question, question => question.categories)
questions: Question[]
}
@Entity()
export class Question {
@PrimaryGeneratedColumn()
id: number
@Column()
title: string
@Column()
text: string
@ManyToMany(() => Category, category => category.questions, {
cascade: true, // 중요 포인트
})
@JoinTable()
categories: Category[]
}
cascade: true를 설정하면Question을 저장할 때Category도 같이 저장됨
const category1 = new Category()
category1.name = "ORMs"
const category2 = new Category()
category2.name = "Programming"
const question = new Question()
question.title = "How to ask questions?"
question.text = "Where can I ask TypeORM-related questions?"
question.categories = [category1, category2]
await dataSource.manager.save(question)
category1,category2를 따로save()하지 않아도,cascade때문에 자동으로 DB에 저장됩니다.
| 옵션명 | 설명 |
|---|---|
"insert" | 새로운 객체가 있으면 자동 저장됨 |
"update" | 기존 객체가 변경되면 자동 업데이트 |
"remove" | 관계에서 빠진 객체를 DB에서도 삭제 |
"soft-remove" | soft remove 수행 |
"recover" | soft remove된 객체 복구 |
@ManyToMany(() => PostCategory, {
cascade: true // insert, update, remove 모두 포함
})
categories: PostCategory[]
@ManyToMany(() => PostDetails, {
cascade: ["insert"] // 새로 생성된 것만 저장
})
details: PostDetails[]
@ManyToMany(() => PostImage, {
cascade: ["update"] // 기존 객체 수정만 반영
})
images: PostImage[]
@ManyToMany(() => PostInformation, {
cascade: ["insert", "update"]
})
informations: PostInformation[]
| 관계 방향 | @JoinColumn 필요 여부 |
|---|---|
@ManyToOne | 선택 (자동으로 생성됨) |
@OneToOne | 필수 (한쪽은 반드시 명시해야 함) |
@ManyToOne(() => Category)
@JoinColumn()
category: Category;
위 코드는 categoryId라는 컬럼(FK)을 생성하여 Category 엔티티의 id(기본 키)를 참조하는 외래 키로 사용한다.
@ManyToOne(() => Category)
@JoinColumn({ name: "cat_id" })
category: Category;
categoryId(자동으로 생성되는 컬럼) 대신 cat_id라는 외래 키 컬럼을 사용하도록 지정한 것.
@ManyToOne(() => Category)
@JoinColumn({ referencedColumnName: "name" })
category: Category;
@ManyToOne(() => Category)
@JoinColumn([
{ name: "category_id", referencedColumnName: "id" },
{ name: "locale_id", referencedColumnName: "locale_id" }
])
category: Category;
정확한 이해를 돕기 위해 @JoinTable의 동작 원리와 옵션들을 예제 기반으로 알기 쉽게 설명해드릴게요.
@ManyToMany 관계에서는 두 엔티티 간의 관계를 나타내기 위한 중간 테이블(junction table) 이 자동 생성된다.@JoinTable 이다.@ManyToMany(() => Category)
@JoinTable()
categories: Category[];
question_categories_category 같은 중간 테이블을 자동 생성하며, 컬럼은 questionId, categoryId처럼 자동으로 설정된다.@ManyToMany(() => Category)
@JoinTable({
name: "question_categories", // 중간 테이블 이름
joinColumn: {
name: "question", // 현재 엔티티(Question)의 FK 컬럼명
referencedColumnName: "id" // Question의 어떤 컬럼을 참조할지 (기본은 id)
},
inverseJoinColumn: {
name: "category", // 반대편 엔티티(Category)의 FK 컬럼명
referencedColumnName: "id" // Category의 어떤 컬럼을 참조할지
}
})
categories: Category[];
| 항목 | 설명 |
|---|---|
name | 생성할 중간 테이블 이름 지정 |
joinColumn | 현재 엔티티(왼쪽)의 외래 키 설정 |
inverseJoinColumn | 상대 엔티티(오른쪽)의 외래 키 설정 |
➡ 결과적으로 생성되는 중간 테이블은 다음과 같이 생깁니다:
| question | category |
|---|---|
| 1 | 2 |
| 1 | 3 |
예를 들어 Category의 기본키가 id + localeId 두 개라면:
@ManyToMany(() => Category)
@JoinTable({
name: "question_categories",
joinColumn: [
{ name: "question_id", referencedColumnName: "id" }
],
inverseJoinColumn: [
{ name: "category_id", referencedColumnName: "id" },
{ name: "category_locale", referencedColumnName: "localeId" }
]
})
categories: Category[];
joinColumn 또는 inverseJoinColumn에 배열을 넣어 복합키를 설정할 수 있다.