[Clone Coding] What I Learn 2 : TypeORM and Entity

먹보·2023년 1월 26일
0

MUK_BO's Clone Coding

목록 보기
2/7

어제에 이어 클론 코딩을 본격적으로 들어가기 앞서 TypeORM on NestJS에 대해 조금 더 자세히 알게되었다. 아! 그리고 클론 코딩 시리즈의 경우 매 게시글 마다 사용중인 스택을 디폴트 값으로 매번 넣어줄 예정이다.

✍ <기술 스택>

  • Programming Language
    TypeScript
  • Framework
    NestJS
  • API 설계
    GraphQL and Apollo
  • Database & Relevant
    PostgresQL & TypeORM

✍ Entity

  • Entity : Entity란 쉽게 말해 데이터베이스 내부에 있는 테이블의 형태를 간단하게 보여주는 모델이라고 생각하면 편할 것 같다.
@ObjectType()
@Entity()
export class Restaurant {
  @PrimaryGeneratedColumn()
  @Field((type) => Number)
  id: number;

  @Field((type) => String)
  @Column()
  @IsString()
  @Length(5)
  name: string;

  @Field((type) => Boolean, { defaultValue: true })
  @Column({ default: true })
  @IsOptional()
  @IsBoolean()
  isVegan: boolean;
}

위와 같이 typeorm패키지에서 제공하는 @Entity Decorator를 사용해서 테이블을 정의하게 되며 각 테이블의 Coloumn 값은 보면 알겠지만 @Column으로 나타낸다.

(여기서 언급되지 않는 Decorator들은 typeorm에서 제공되는 것이 아닌 다른 패키지에서 제공되는 것으로 생각하면 된다)

📝 Synchronize & Table

지난 시간, TypeORM과 DB를 연결하면서 Synchronize에 대해서 간략하게 언급을 했던 적이 있다.

Synchronize를 True로 설정한 뒤 다음과 같이 Entity를 추가해주면 테이블 생성이 쉬워진다.

TypeOrmModule.forRoot({
      type: 'postgres',
      host: process.env.DB_HOST,
      port: +process.env.DB_PORT,
      username: process.env.DB_USERNAME,
      password: process.env.DB_PASSWORD,
      database: process.env.DB_NAME,
      synchronize: process.env.NODE_ENV !== 'prod',
      logging: true,
      entities: [Restaurant], // << Entity 추가 (Optional)
    }),

상황에 맞게 Decorator를 패키지에 가져와서 Entity에 적용해주면 테이블 스키마 관리도 효율적으로 이루어지니 공식문서를 참고해서 적용해보도록 하자.

TypeORM Decorator For Entities

✍ TypeORM Usage Pattern

📝 Active Record Pattern

간단한 사용법은 다음과 같다 (공식문서 참고).

import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity() // 
export class User extends BaseEntity {
    @PrimaryGeneratedColumn()
    id: number

    @Column()
    firstName: string

    @Column()
    lastName: string

    @Column()
    isActive: boolean
}

=> Active Record 사용시 모든 Entity 설정은 extends BaseEntity를 사용해야 한다.
=> Active Record 패턴은 모델 내에서 데이터베이스에 액세스하는 접근 방식

// example how to save AR entity
const user = new User()
user.firstName = "Timber"
user.lastName = "Saw"
user.isActive = true
await user.save()

// example how to remove AR entity
await user.remove()

// example how to load AR entities
const users = await User.find({ skip: 2, take: 5 })
const newUsers = await User.findBy({ isActive: true })
const timber = await User.findOneBy({ firstName: "Timber", lastName: "Saw" })

Active Record 사용 이유 : 소규모 프로젝트의 데이터 유지 관리 용이

📝 Data Mapper Pattern

간단한 사용법은 다음과 같다 (공식문서 참고)

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

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

    @Column()
    firstName: string

    @Column()
    lastName: string

    @Column()
    isActive: boolean
}

const userRepository = dataSource.getRepository(User)

// example how to save DM entity
const user = new User()
user.firstName = "Timber"
user.lastName = "Saw"
user.isActive = true
await userRepository.save(user)

// example how to remove DM entity
await userRepository.remove(user)

// example how to load DM entities
const users = await userRepository.find({ skip: 2, take: 5 })
const newUsers = await userRepository.findBy({ isActive: true })
const timber = await userRepository.findOneBy({
    firstName: "Timber",
    lastName: "Saw",
})

=> Data Mapper는 Active Record와는 다르게 BaseEntity에서 상속을 받지 않아도 되며, 데이타베이스에서 직접 Repository를 가져와서 어디에서나 TypeORM Method를 적용 할 수 있다.

=> Data Mapper는 모델 대신 리포지토리 내의 데이터베이스에 액세스하는 접근방식. 데이터 매퍼 접근 방식을 사용하여 "리포지토리"라는 별도의 클래스에서 모든 쿼리 메서드를 정의하고 리포지토리를 사용하여 객체를 저장, 제거 및 로드.

Data Mapper 사용 이유 : 대규모 프로젝트의 데이터 유지 관리 용이

📝 Active Record vs Data Mapper

사실, 규모가 어중간한 경우에는 둘 중 아무거나 써도 상관이 크게 없지만 이번 클론 코딩에서는 Data Mapper를 사용하게 되는데 그 이유는 다음과 같다.

  1. NestJS + TypeORM에서는 Repository에 대한 추가 모듈을 제공한다.
  2. Repository를 사용하면, Service, Test, 등 Model이 아닌 다른 곳에서도 적용이 용이해진다.

✍ Simple TypeORM Usage

  • TypeOrmModule.forFeature() : Entity Repo를 Import 해올 수 있다.
  • create : 새 엔티티 인스턴스를 만들고 이 개체의 모든 엔티티 속성을 새 엔티티에 복사합니다. 엔티티 스키마에 있는 속성만 복사합니다.
  • save(Promise) : 데이터베이스에 지정된 모든 엔티티를 저장합니다. 엔티티가 데이터베이스에 없으면 삽입하고, 그렇지 않으면 업데이트합니다.
  • update : 엔티티를 부분적으로 업데이트합니다. 엔티티는 주어진 조건으로 찾을 수 있습니다. save 메소드와 달리 캐스케이드, 관계 및 기타 작업이 포함되지 않은 기본 작업을 실행합니다. 빠르고 효율적인 UPDATE 쿼리를 실행합니다. 데이터베이스에 엔터티가 있는지 확인하지 않습니다.

TypeORM 사용방식은 이거 외에도 다양하므로 매일 매일 새로운 것을 사용 할 때마다 기록을 하려고 한다.

profile
🍖먹은 만큼 성장하는 개발자👩‍💻

0개의 댓글