[TypeORM] @Many-to-One & @One-to-Many를 활용하여 @Many-to-Many Relations 구현

TypeORM을 통해 Table간 Relation을 구성하다보면 N : N의 관계로 구성을 해야될 때가 있다.

TypeORM의 공식 문서를 확인해보면 N : N을 구성하는 법은 다음과 같다.

// category.entity.ts
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";

@Entity()
export class Category {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

}

// question.enetity.ts
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(() => Category)
    @JoinTable()
    categories: Category[];

}

 

 

Category 테이블과 Question 테이블이 N : N의 관계로 구성된다.

TypeORM에서 @JoinTable( )을 통해 자동으로 CategoryId와 QuestionId가 칼럼으로 되어있는 테이블을 자동으로 생성해주는데 이 테이블은 services.ts 혹은 controllers.ts가 없고, 테이블만 존재하는 상태이기 때문에 해당 테이블 관련 API를 구축하기 힘들고, TypeORM이 자동으로 생성하다보니 개발자가 직접 테이블을 제어하기 힘들다는 단점이 있다.

 

이러한 단점을 해결하는 방법으로는 @One-to-many, @Many-to-One을 활용하여 직접 @Many-to-Many와 같은 Relations를 구현하는 방법이 있다.

// category.entity.ts
import {Entity, PrimaryGeneratedColumn, Column, OneToMany} from "typeorm";

@Entity()
export class Category {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;
    
    @OneToMany(() => CategoryQuestion, (categoryQuestion) => categoryQuestion.category)
    categoryQuestions: CategoryQuestion[];

}

// question.entity.ts
import {Entity, PrimaryGeneratedColumn, Column, OneToMany, JoinTable} from "typeorm";
import {Category} from "./Category";

@Entity()
export class Question {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    title: string;

    @Column()
    text: string;
    
    @OneToMany(() => CategoryQuestion, (categoryQuestion) => categoryQuestion.question)
    categoryQuestions: CategoryQuestion[];

}

// categoryquestion.entity.ts
import {Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinTable} from "typeorm";
import {Category} from "./Category";
import {Question} from "./Question";

@Entity()
export class CategoryQuestion {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    categoryId: number;

    @Column()
    questionId: number;
    
    @ManyToOne(() => Category, (category) => category)
    category: Category;
    
    @ManyToOne(() => Question, (question) => question)
    question: Question;
}

위와 같이 entity.ts로 Join Table을 따로 관리할 경우, @JoinTable( )로 생성한 테이블과 달리 categoryQuestion.service.ts로 직접 테이블에 접근이 가능하고, 코드적으로 명확하게 파악할 수 있다.

 

참고) https://typeorm.io/#/many-to-one-one-to-many-relations