ORM/TypeORM
Type ORM 알아보기 [NestJS]
muyeon
2023. 12. 15. 09:39
TypeORM은 TS와 JS에서 사용할 수 있는 객체 관계 매핑(ORM) 라이브러리 중 하나이다.
ORM은 데이터베이스와의 상호작용을 추상화하여 개발자가 객체 지향 프로그래밍 스타일을 사용하여 데이터베이스와 상호 작용할 수 있게 해준다.
Column Annotation
PrimaryGeneratedColumn
- 해당 필드를 기본 키로 사용하며, 자동으로 생성되는 숫자 형태의 값이다.
- 주로 순차적인 정수 값을 기본키로 사용할 때 활용된다.
// @PrimaryGeneratedColumn() 은 자동으로 id 를 생성한다.
// 1, 2, 3, 4, 5 -> 순서대로 id 값이 올라간다.
// @PrimaryGeneratedColumn('uuid')
// asd1rf123f-213dsaf3-123asdbe-oinpoml 같은 uuid 가 들어간다.
// @PrimaryColumn() 은 id 를 우리가 직접 넣겠다.
@PrimaryGeneratedColumn()
id: number;
Column
- 데이터베이스의 열(Column)에 해당하는 필드를 정의한다.
@Column()
title: string;
CreateDateColumn
- 엔티티가 생성될 때마다 해당 필드에 자동으로 현재 날짜 및 시간이 기록된다.
- 데이터가 생성된 일시를 추적하기 위해 사용된다.
// row 가 생성이 될 때마다 날짜와 시간이 자동으로 찍힌다.
@CreateDateColumn()
createdAt: Date;
UpdateDateColumn
- 엔티티가 업데이트될 때마다 해당 필드에 자동으로 현재 날짜 및 시간이 갱신된다.
- 데이터가 언제 마지막으로 수정되었는지를 추적하기 위해 사용된다.
// 업데이트 되는 날짜와 시간이 자동으로 찍힌다.
@UpdateDateColumn()
updatedAt: Date;
VersionColumn
- Optimistic Locking 을 위해 사용된다. 버전 필드의 값이 엔티티가 업데이트 될 때마다 자동으로 증가하며, 업데이트 시에 이 값이 변경되면 업데이트가 충돌하지 않도록 한다.
// 데이터가 업데이트 될 때마다 1 씩 올라간다. 처음 생성되면 값은 1이다.
// save 함수가 몇 번 불렸는지 기억한다.
@VersionColumn()
version: number;
Generated('uuid')
- 해당 필드에 UUID(Universally Unique Identifier)를 자동으로 생성하여 할당한다.
- 주로 기본키나 다른 식별자로 활용된다.
// Generated 와 Column 어노테이션은 같이 사용해야한다.
// increment 는 PrimaryGeneratedColumn 을 하고서 UUid 를 넣지 않은것과 같다.
// uuid 는 데이터가 생성될 때마다 additionalId 컬럼에다 생성할 수 있다.
@Column()
@Generated('uuid')
additionalId: number;
Column Property
type
- 데이터베이스에서 인식할 컬럼의 타입을 지정한다.
- varchar는 가변길이 문자열을 나타낸다
name
- 데이터베이스에 저장될 때 컬럼의 이름을 지정한다.
- 프로퍼티의 이름으로 자동으로 유추되지만, 필요에 따라 별도의 이름으로 지정할 수 있다.
length
- 문자열 형태의 컬럼에서 저장 가능한 최대길이를 나타낸다.
nullable
- 해당 컬럼이 null 값을 가질 수 있는지 여부를 나타낸다.
- true 로 설정하면 null 이 허용된다.
update
- false 로 설정되면 처음 저장할 때만 값을 저장 가능하고 이후에는 값이 변경되지 않는다.
- true 로 설정되면 업데이트가 가능하다.
select
- find 메서드를 실행할때 이 컬럼이 기본적으로 선택(include)되는지 여부를 결정한다.
- false 로 설정되면 find 시에 선택되지 않는다.
default
- 컬럼에 값이 입력되지 않았을때 기본적으로 입력되는 값을 지정한다.
unique
- 해당 컬럼이 유일한 값을 가져야하는지 여부를 결정한다.
- true로 설정되 있으면 해당 컬럼은 유일한 값을 가져야 한다. 주로 ID나 이메일과 같은 식별자에 사용된다.
@Column({
// 데이터베이스에서 인지하는 column 타입, 자동으로 유추된다. text 는 길이를 지정할 수 없고 varchar 만 지정할 수 있다.
type: 'varchar',
// 데이터베이스 컬럼 이름, 프로퍼티 이름으로 자동 유추됨
name: 'title',
// 값의 길이, 입력할 수 있는 글자의 길이 300
length: 300,
// null 이 가능한지
nullable: true,
// false 면 처음 저장할때만 값 지정 가능, 이후 값 변경 불가능
update: true,
// find() 를 실행할 때 기본으로 값을 불러 올지 정한다.
// 기본값이 true
select: false,
// 기본 값, 아무것도 입력 안했을때 기본으로 입력 되게 하는 값
default: 'default value',
// 기본이 false, 컬럼중에서 유일무이한 값이 되어야하는지 정해준다. id, 이메일에 많이 사용
unique: true,
})
title: string;
Enum column
- 데이터의 인테그리티를 유지해주는 기능
- 특정 값들로 컬럼의 값들을 제한하고 싶을때 사용한다.
export enum Role {
USER = 'user',
ADMIN = 'admin',
}
@Entity()
export class UserModel {
// ... 중략
@Column({
type: 'enum',
enum: Role,
default: Role.USER,
})
role: Role;
// ... 중략
}
Entity Embedding
임베딩은 '심다'라는 느낌이다.
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Student {
@PrimaryGeneratedColumn()
id: number;
@Column()
firstName: string;
@Column()
lastName: string;
@Column()
class: string;
}
export class Teacher {
@PrimaryGeneratedColumn()
id: number;
@Column()
firstName: string;
@Column()
lastName: string;
@Column()
salary: number;
}
위 그림처럼 student 와 teacher 를 비교했을 때 중복되는 부분들이 있다. 이를 entity embedding 으로 해결할 수 있다.
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
export class Name {
@Column()
first: string;
@Column()
last: string;
}
@Entity()
export class StudentModel {
@PrimaryGeneratedColumn()
id: number;
@Column(() => Name)
name: Name;
@Column()
class: string;
}
@Entity()
export class TeacherModel {
@PrimaryGeneratedColumn()
id: number;
@Column(() => Name)
name: Name;
@Column()
salary: number;
}
이 방법도 있지만 보통 이방법보다는 상속을 통해 비슷한 기능을 사용한다.
Table Inheritance
Table Inheritance 에는 두 가지가 있다.
첫번째로 평범한 형태인 상속을 받으면 상속받은 클래스들이 각각 개별테이블을 생성하는 형식
두번째는 Single Table Inheritance 이고 테이블을 하나만 생성하는 방식이다.
두가지 방법은 똑같지만 테이블을 생성하는 방식만 다르다.
평범한 Inheritance
export class BaseModel {
@PrimaryGeneratedColumn()
id: number;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}
@Entity()
export class BookModel extends BaseModel {
@Column()
name: string;
}
@Entity()
export class CarModel extends BaseModel {
@Column()
brand: string;
}
Single Table Inheritance
@Entity()
@TableInheritance({
column: {
name: 'type',
type: 'varchar',
},
})
export class SingleBaseModel {
@PrimaryGeneratedColumn()
id: number;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}
@ChildEntity()
export class ComputerModel extends SingleBaseModel {
@Column()
brand: string;
}
@ChildEntity()
export class AirplaneModel extends SingleBaseModel {
@Column()
country: string;
}