https://orkhan.gitbook.io/typeorm/docs/relations
What are relations
1. @OneToOne
2. @ManyToOne
3. @OneToMany
4. @ManyToMany
Relation options
관계 설정을 위해 처리하는 옵션
eager: booleam - true로 처리되면 메인 엔티티를 로드할 때 연관된 엔티티가 같이 로드 된다.
QueryBuilder나 find* 메소드 사용시.
casecade: boolean | ("insert | "update")[] - true로 처리되면 연관된 엔티티가 DB에 추가되고 업데이트 된다.
배열을 통해 옵션을 넘기는 것도 가능하다.
onDelete: "RESTRICT" | "CASCADE" | "SET NULL" - 외래키 행동에 대한 조건을 설정한다. 연관된 오브젝트 삭제시
nullable: boolean - 관계의 column이 nullable인지 아닌지 결정한다. 기본은 nullable
oprhanedRowAction: "nullify" | "delete" | "soft-delete" | disable
- 부모가 DB 상에 존재하는 자식 객체 없이 저장되었을 때(cascade = true) 어떤 식으로 처리할지 정한다.
delete는 고아객체를 DB상에서 없앤다. soft-delete는 삭제 되었다는 마크 처리만 진행한다.
nullify는 relation key를 삭제한다. disable은 그대로 둔다.
Cascades
예시)
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany } from "typeorm"
import { Question } from "./Question"
@Entity()
export class Category {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@ManyToMany((type) => Question, (question) => question.categories)
questions: Question[]
}
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToMany,
JoinTable,
} from "typeorm"
import { Category } from "./Category"
@Entity()
export class Question {
@PrimaryGeneratedColumn()
id: number
@Column()
title: string
@Column()
text: string
@ManyToMany((type) => Category, (category) => category.questions, {
cascade: true,
})
@JoinTable()
categories: 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를 호출하지 않았다. 자동으로 추가가 된다.
Casecade는 좋고 쉬운 방법으로 보이지만, 원하지 않는 오브젝트가 DB에 저장될 때 버그와 보안 이슈를 가져올 수 있다.
또한 새로운 객체를 DB에 저장할 때 모호한 방식을 제공한다.
Cascade Options
cascade 옵션은 boolean으로 처리되거나 Array로 처리할 수 있다. 기본은 false이고 true로 설정시 모든 캐스캐이드 옵션을 반영한다.
예시)
@Entity(Post)
export class Post {
@PrimaryGeneratedColumn()
id: number
@Column()
title: string
@Column()
text: string
// Full cascades on categories.
@ManyToMany((type) => PostCategory, {
cascade: true,
})
@JoinTable()
categories: PostCategory[]
// Cascade insert here means if there is a new PostDetails instance set
// on this relation, it will be inserted automatically to the db when you save this Post entity
@ManyToMany((type) => PostDetails, (details) => details.posts, {
cascade: ["insert"],
})
@JoinTable()
details: PostDetails[]
// Cascade update here means if there are changes to an existing PostImage, it
// will be updated automatically to the db when you save this Post entity
@ManyToMany((type) => PostImage, (image) => image.posts, {
cascade: ["update"],
})
@JoinTable()
images: PostImage[]
// Cascade insert & update here means if there are new PostInformation instances
// or an update to an existing one, they will be automatically inserted or updated
// when you save this Post entity
@ManyToMany((type) => PostInformation, (information) => information.posts, {
cascade: ["insert", "update"],
})
@JoinTable()
informations: PostInformation[]
}
@JoinColumn
외래키를 가진 테이블을 정의할 뿐만 아니라, join column 이름과 referenced column 이름을 설정할 수 있도록 한다.
@JoinColumn을 설정할 때, 자동으로 propertyName과 referencedColumnName으로 처리된 컬럼을 생성한다.
@ManyToOne(type => Category)
@JoinColumn() // this decorator is optional for @ManyToOne, but required for @OneToOne
category: Category;
이는 categoryId Column을 데이터베이스 상에 추가한다. 바꾸고 싶은 경우에는 다음과 같이 처리할 수 있다.
@ManyToOne(type => Category)
@JoinColumn({ name: "cat_id" })
category: Category;
JoinColumns는 항상 다른 칼럼을 참조한다.
기본적으로 주요키를 참조하는데 다른 칼럼을 참조하길 원하는 경우 다음과 같이 처리할 수 있다.
@ManyToOne(type => Category)
@JoinColumn({ referencedColumnName: "name" })
category: Category;
이 때, Category 엔티티의 Id를 참조하는 것이 아닌 name 값을 참조하게 된다.
컬럼 이름은 categoryName으로 처리된다.
// 근데 어지간하면 그냥 id로 참조할 것 같다. (다른 테이블이랑 다르게 name으로 참조..? 굳이)
또한 여러 컬럼을 지정할 수 있다. 다시 한번 기본적으로 엔티티의 주요 키를 참조하지 않는다.
레퍼런스 네임 값을 지정해야 한다.
@ManyToOne(type => Category)
@JoinColumn([
{ name: "category_id", referencedColumnName: "id" },
{ name: "locale_id", referencedColumnName: "locale_id" }
])
category: Category;
// 실무에서 이렇게 복잡하게 쓸까... 싶은 생각이 든다.
@JoinTable options
ManyToMany 관계에서 사용된다. ManyToMany. 관계에서는 TypeORM에 의해 자동으로 중간 테이블이 생성된다. 참조하는 엔티티와 연관된 칼럼을 포함한다. 중간 테이블에 생성되는 컬럼 이름과 연관 컬럼을 수정할 수 있다.
중간 테이블의 이름을 바꾸는 동작도 가능하다.
@ManyToMany(type => Category)
@JoinTable({
name: "question_categories", // table name for the junction table of this relation
joinColumn: {
name: "question",
referencedColumnName: "id"
},
inverseJoinColumn: {
name: "category",
referencedColumnName: "id"
}
})
categories: Category[];
destination 테이블에서 복합된 주요 키를 가진 경우, array로 지정해야 한다.
'프로그래밍 > TypeORM' 카테고리의 다른 글
[TypeORM] Using Validation (0) | 2023.09.04 |
---|---|
[TypeORM] Many-to-one / one-to-many relations (0) | 2023.09.04 |
[TypeORM] One-to-one relations (0) | 2023.09.03 |
[TypeORM] Find Options - Advanced options (0) | 2023.09.02 |
[TypeORM] Find Options - Basic Options (0) | 2023.09.02 |
댓글