목차

1. 구체 테이블 상속 (Concrete Table Inheritance)

1-1. 코드

1-2. 생성된 테이블

1-3. 설명

2. 단일 테이블 상속 (Single Table Inheritance)

2-1. 코드

2-2. 생성된 테이블

2-3. 샘플 데이터 예시

2-4. 설명

3. 임베디드 엔티티 (Embedded Entities)

3-1. 코드

3-2. 생성된 테이블

3-3. 샘플 데이터 예시

3-4. 설명

4. 비교 요약 테이블

5. 전략 선택 가이드

6. 마무리

태그

#TYPESCRIPT

#MYSQL

#DB

#NODE

#TYPEORM

[TypeORM] Entity Inheritance

2025년 1월 2일 13:57

65-thumbnail-image

TypeORM은 엔터티 상속을 통해 코드 중복을 줄이고 데이터 모델을 효율적으로 관리할 수 있는 기능을 제공합니다. 주요 상속 전략으로는 구체 테이블 상속(Concrete Table Inheritance)단일 테이블 상속(Single Table Inheritance) 이 있습니다.

1. 구체 테이블 상속 (Concrete Table Inheritance)

구체 테이블 상속은 공통 필드를 가진 여러 엔터티가 각각 독립된 테이블로 생성되는 방식입니다. 이를 통해 코드 중복을 줄이고 유지 보수를 용이하게 할 수 있습니다.

1-1. 코드

먼저, 공통 필드를 가진 추상 클래스를 정의합니다:

import { PrimaryGeneratedColumn, Column } from 'typeorm';

export abstract class Content {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    title: string;

    @Column()
    description: string;
}

그런 다음, 이 추상 클래스를 상속받는 엔터티들을 정의합니다:

import { Entity, Column } from 'typeorm';
import { Content } from './Content';

@Entity()
export class Photo extends Content {
    @Column()
    size: string;
}

@Entity()
export class Question extends Content {
    @Column()
    answersCount: number;
}

@Entity()
export class Post extends Content {
    @Column()
    viewCount: number;
}

이렇게 하면 photo, question, post 세 개의 테이블이 생성되며, 각 테이블은 Content 클래스의 공통 필드와 자신만의 고유한 필드를 포함하게 됩니다

1-2. 생성된 테이블

Photo Table
id (PK)
title
description
size
Question Table
id (PK)
title
description
answersCount
Post Table
id (PK)
title
description
viewCount

1-3. 설명

  • 각 자식 엔터티(Photo, Question, Post)는 별도의 테이블로 생성됩니다.
  • 공통 필드(id, title, description)는 모든 테이블에 반복됩니다.

2. 단일 테이블 상속 (Single Table Inheritance)

단일 테이블 상속은 여러 엔터티가 하나의 테이블에 저장되는 방식입니다. 이때 각 행은 특정 엔터티 유형을 식별할 수 있는 추가 컬럼을 가집니다.

2-1. 코드

먼저, 임베디드 엔터티를 정의합니다:

@Entity()
@TableInheritance({ column: { type: 'varchar', name: 'type' } })
export class Content {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    title: string;

    @Column()
    description: string;
}

그런 다음, 다른 엔터티에서 이를 포함시킵니다:

@ChildEntity()
export class Photo extends Content {
    @Column()
    size: string;
}

@ChildEntity()
export class Question extends Content {
    @Column()
    answersCount: number;
}

@ChildEntity()
export class Post extends Content {
    @Column()
    viewCount: number;
}

이렇게 하면 content라는 하나의 테이블이 생성되고, 모든 Photo, Question, Post 엔터티의 데이터가 이 테이블에 저장됩니다. 각 행은 type 컬럼을 통해 해당 데이터의 엔터티 유형을 식별할 수 있습니다.

2-2. 생성된 테이블

Content Table
id (PK)
title
description
type
size
answersCount
viewCount

2-3. 샘플 데이터 예시

idtitledescriptiontypesizeanswersCountviewCount
1Photo1Desc1Photo15MBNULLNULL
2Ques1Desc2QuestionNULL5NULL
3Post1Desc3PostNULLNULL100

2-4. 설명

  • 모든 자식 엔터티(Photo, Question, Post)는 하나의 테이블(Content)에 저장됩니다.
  • type 컬럼을 통해 각 행이 어떤 자식 엔터티인지 구분됩니다.
  • 불필요한 NULL 값이 생길 수 있습니다.

3. 임베디드 엔티티 (Embedded Entities)

임베디드 엔티티는 상속과 유사하게 공통 필드를 재사용할 수 있는 방법입니다. 그러나 상속과 달리 데이터베이스에 별도의 테이블을 생성하지 않고, 필드를 포함하는 방식으로 구성됩니다.

3-1. 코드

먼저, 임베디드 엔터티를 정의합니다:

import { Column } from 'typeorm';

export class Audit {
    @Column()
    createdAt: Date;

    @Column()
    updatedAt: Date;
}

그런 다음, 다른 엔터티에서 이를 포함시킵니다:

import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
import { Audit } from './Audit';

@Entity()
export class User {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

    @Column(() => Audit)
    audit: Audit;
}

이렇게 하면 User 테이블에 createdAtupdatedAt 컬럼이 포함되며, Audit 클래스의 필드들을 재사용할 수 있습니다.

3-2. 생성된 테이블

User Table
id (PK)
name
audit_createdAt
audit_updatedAt

3-3. 샘플 데이터 예시

idnameaudit_createdAtaudit_updatedAt
1Alice2024-06-012024-06-02
2Bob2024-06-032024-06-04

3-4. 설명

  • AuditUser 테이블의 필드로 직접 추가됩니다.
  • 별도의 테이블이 생성되지 않고, 필드가 직접 부모 테이블에 포함됩니다.
  • 접근은 audit.createdAt, audit.updatedAt과 같은 방식으로 가능합니다.

4. 비교 요약 테이블

전략테이블 구조필드 중복유연성쿼리 복잡도데이터 정규화
Concrete Table개별 테이블있음높음낮음높음
Single Table하나의 테이블없음중간높음낮음
Embedded Entity부모 테이블 내없음낮음낮음높음

5. 전략 선택 가이드

  1. Concrete Table Inheritance
  • 각 하위 엔터티가 독립적인 테이블을 가져야 하는 경우.
  • 유지보수가 용이하지만 필드 중복이 발생합니다.
  1. Single Table Inheritance
  • 여러 엔터티가 동일한 테이블에 저장되어야 하는 경우.
  • 쿼리가 복잡할 수 있고, NULL 값이 많아질 수 있습니다.
  1. Embedded Entity
  • 필드 재사용이 필요하지만 독립적인 테이블이 필요하지 않은 경우.
  • 간단한 구조에 적합합니다.

6. 마무리

TypeORM의 상속 전략은 프로젝트의 요구사항에 따라 선택해야 합니다.

  • 복잡한 구조와 명확한 분리를 원한다면: Concrete Table Inheritance
  • 단순한 구조와 유연한 쿼리를 원한다면: Single Table Inheritance
  • 필드 재사용이 주목적이라면: Embedded Entity

참고 사이트

https://orkhan.gitbook.io/typeorm/docs/entity-inheritance