목차
1. 구체 테이블 상속 (Concrete Table Inheritance)
2. 단일 테이블 상속 (Single Table Inheritance)
태그
#TYPESCRIPT
#MYSQL
#DB
#NODE
#TYPEORM
2025년 1월 2일 13:57

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. 샘플 데이터 예시
id | title | description | type | size | answersCount | viewCount |
---|---|---|---|---|---|---|
1 | Photo1 | Desc1 | Photo | 15MB | NULL | NULL |
2 | Ques1 | Desc2 | Question | NULL | 5 | NULL |
3 | Post1 | Desc3 | Post | NULL | NULL | 100 |
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
테이블에 createdAt
과 updatedAt
컬럼이 포함되며, Audit
클래스의 필드들을 재사용할 수 있습니다.
3-2. 생성된 테이블
User Table |
---|
id (PK) |
name |
audit_createdAt |
audit_updatedAt |
3-3. 샘플 데이터 예시
id | name | audit_createdAt | audit_updatedAt |
---|---|---|---|
1 | Alice | 2024-06-01 | 2024-06-02 |
2 | Bob | 2024-06-03 | 2024-06-04 |
3-4. 설명
Audit
는User
테이블의 필드로 직접 추가됩니다.- 별도의 테이블이 생성되지 않고, 필드가 직접 부모 테이블에 포함됩니다.
- 접근은
audit.createdAt
,audit.updatedAt
과 같은 방식으로 가능합니다.
4. 비교 요약 테이블
전략 | 테이블 구조 | 필드 중복 | 유연성 | 쿼리 복잡도 | 데이터 정규화 |
---|---|---|---|---|---|
Concrete Table | 개별 테이블 | 있음 | 높음 | 낮음 | 높음 |
Single Table | 하나의 테이블 | 없음 | 중간 | 높음 | 낮음 |
Embedded Entity | 부모 테이블 내 | 없음 | 낮음 | 낮음 | 높음 |
5. 전략 선택 가이드
- Concrete Table Inheritance
- 각 하위 엔터티가 독립적인 테이블을 가져야 하는 경우.
- 유지보수가 용이하지만 필드 중복이 발생합니다.
- Single Table Inheritance
- 여러 엔터티가 동일한 테이블에 저장되어야 하는 경우.
- 쿼리가 복잡할 수 있고, NULL 값이 많아질 수 있습니다.
- Embedded Entity
- 필드 재사용이 필요하지만 독립적인 테이블이 필요하지 않은 경우.
- 간단한 구조에 적합합니다.
6. 마무리
TypeORM의 상속 전략은 프로젝트의 요구사항에 따라 선택해야 합니다.
- 복잡한 구조와 명확한 분리를 원한다면:
Concrete Table Inheritance
- 단순한 구조와 유연한 쿼리를 원한다면:
Single Table Inheritance
- 필드 재사용이 주목적이라면:
Embedded Entity
참고 사이트