[Nest.js] typeORM0.3 적용하기

bshunter·2023년 8월 4일
1

오늘은 typeorm의 최신 버전인 0.3에서 새로 도입된 injection 기능에 대해 알아보고, 기존의 repository 패턴과 어떻게 다른지, 어떻게 설정하고 사용하는지에 대해 간단한 예제를 통해 설명해드리겠습니다.

typeorm 0.2버전에서 오류를 겪는 분들에게 도움이 되기를 바랍니다.

TypeORM

typeorm은 nest.js에서 데이터베이스와의 연동을 쉽게 해주는 ORM(Object-Relational Mapping) 라이브러리입니다.

ORM이란 객체와 관계형 데이터베이스의 테이블을 매핑해주는 기술로, SQL 쿼리를 직접 작성하지 않고도 데이터베이스의 CRUD(Create, Read, Update, Delete) 작업을 수행할 수 있습니다.
typeorm은 TypeScript와 JavaScript를 지원하며, MySQL, PostgreSQL, SQLite, Oracle 등 다양한 데이터베이스를 지원합니다.

typeorm 0.2버전까지는 repository 패턴을 사용하여 데이터베이스와의 작업을 수행했습니다.
repository 패턴이란 데이터베이스와의 접근을 추상화하여 별도의 클래스로 분리하는 디자인 패턴입니다.
repository 클래스는 엔티티(Entity) 클래스와 일대일로 매핑되며, 엔티티 클래스는 데이터베이스의 테이블과 일대일로 매핑됩니다.
repository 클래스는 getRepository 함수를 통해 생성하거나 상속받아 사용할 수 있습니다.

예를 들어, User라는 엔티티 클래스가 있다면, UserRepository라는 repository 클래스를 만들어서 User 엔티티와 관련된 데이터베이스 작업을 수행할 수 있습니다.

다음은 User 엔티티 클래스와 UserRepository repository 클래스의 예시입니다.

// user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

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

@Column()
name: string;

@Column()
email: string;
}
// user.repository.ts
import { EntityRepository, Repository } from 'typeorm';
import { User } from './user.entity';

@EntityRepository(User)
export class UserRepository extends Repository<User> {
// User 엔티티와 관련된 비즈니스 로직을 여기에 작성할 수 있습니다.
}

위와 같이 repository 패턴을 사용하면 데이터베이스와의 작업을 캡슐화하여 재사용성과 유지보수성을 높일 수 있습니다.

하지만 repository 패턴에도 단점이 있습니다. 예를 들어, 서비스(Service) 클래스에서 repository 클래스를 사용하려면 다음과 같은 방법으로 의존성 주입(Dependency Injection)을 해야합니다.

// user.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UserRepository } from './user.repository';

@Injectable()
export class UserService {
constructor(
@InjectRepository(UserRepository)
private userRepository: UserRepository,
) {}

// UserService에서 UserRepository를 사용하는 메소드들
}

위 코드에서 보면, UserService 클래스의 생성자에서 @InjectRepository 데코레이터(Decorator)를 사용하여 UserRepository 타입의 userRepository 인스턴스를 주입받고 있습니다.
이렇게 하면 UserService 클래스는 UserRepository 클래스에 강하게 의존하게 됩니다.
만약 UserRepository 클래스가 변경되거나 다른 클래스로 교체되어야 한다면, UserService 클래스도 함께 수정해야합니다.
이는 결합도(Coupling)가 높아지고, 테스트와 유지보수에 어려움을 초래할 수 있습니다.

TypeORM 0.3

이러한 문제를 해결하기 위해 typeorm 0.3버전에서는 injection 기능을 도입했습니다.
injection 기능은 repository 패턴을 사용하는 것이 아니라, repository를 서비스처럼 주입할 수 있게 해줍니다.

즉, repository 클래스를 따로 만들지 않고, 엔티티 클래스만 있으면 됩니다.
그리고 엔티티 클래스를 @Inject 데코레이터를 사용하여 서비스 클래스에 주입할 수 있습니다.
이렇게 하면 서비스 클래스는 엔티티 클래스에만 의존하게 되고, repository 클래스의 변경이나 교체에 영향을 받지 않게 됩니다.

다음은 injection 기능을 사용하는 방법입니다.

먼저, app.module.ts 파일에서 TypeOrmModule.forRoot 메소드에 autoLoadEntities 옵션을 true로 설정해줍니다.
이 옵션은 엔티티 클래스를 자동으로 로드하고 데이터베이스와 동기화해줍니다.

// app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'root',
database: 'test',
autoLoadEntities: true, // 이 옵션을 true로 설정합니다.
synchronize: true,
}),
],
})
export class AppModule {}

그 다음, user.module.ts 파일에서 TypeOrmModule.forFeature 메소드에 User 엔티티 클래스를 인자로 넘겨줍니다.
이 메소드는 User 엔티티 클래스를 현재 모듈의 공급자(Provider)로 등록해줍니다.

// user.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UserService } from './user.service';

@Module({
imports: [TypeOrmModule.forFeature([User])], // User 엔티티 클래스를 인자로 넘겨줍니다.
providers: [UserService],
})
export class UserModule {}

마지막으로, user.service.ts 파일에서 @Inject 데코레이터를 사용하여 User 엔티티 클래스의 인스턴스를 주입받습니다. 이 인스턴스는 Repository<User> 타입이므로, Repository<User>의 모든 메소드를 사용할 수 있습니다.

// user.service.ts
import { Injectable, Inject } from '@nestjs/common';
import { User } from './user.entity';

@Injectable()
export class UserService {
constructor(
@Inject('User') // @Inject 데코레이터를 사용하여 User 엔티티 클래스의 인스턴스를 주입받습니다.
private userRepository: Repository<User>, // 이 인스턴스는 Repository<User> 타입입니다.
) {}

// UserService에서 userRepository를 사용하는 메소드들
}

이렇게 injection 기능을 사용하면 repository 패턴을 사용하는 것보다 코드가 간결해지고, 의존성 주입이 쉬워집니다. 또한, 서비스 클래스와 repository 클래스의 결합도가 낮아져서 테스트와 유지보수에 유리합니다.

injection 기능은 typeorm 0.3버전부터 지원되므로, nest.js 프로젝트에서 typeorm을 사용하시는 분들은 package.json 파일에서 typeorm의 버전을 확인하시고, 필요하다면 업데이트하시기 바랍니다.

이상으로 nest.js와 typeorm에서 injection 기능에 대해 알아보았습니다. injection 기능을 사용하여 데이터베이스 작업을 더 쉽고 효율적으로 수행할 수 있기를 바랍니다.

1개의 댓글

comment-user-thumbnail
2024년 5월 17일

자세한 설명글 잘 읽었습니다.

답글 달기