‘나야, ORM‘

김가을·2024년 11월 16일
post-thumbnail

Node.js에서 주로 사용되는 ORM은 Sequelize, TypeORM, Prisma가 있다.

Nest는 데이터베이스에 구애받지 않기 때문에 모든 SQL 또는 NoSQL 데이터베이스들과 쉽게 통합할 수 있다. 이 중 Typescrpt에 최적화된 TypeORM, Prisma에 대해 알아보겠다.

ORM

  • Object-Relational Mapping
    • Object는 객체지향언어에서 말하는 객체(object)를 의미함

    • Relational은 관계형 데이터베이스를 의미함

      ⇒ 객체과 관계형 데이터베이스를 자동으로 맵핑 시켜주는 기술이 ORM이다.

  • Nest.js는 코드를 객체지향적으로 설계하도록 되어 있음
  • 객체 지향 프로그래밍은 클래스를 사용하고 관계형 데이터베이스는 테이블을 사용함 이때 객체 모델과 관계형 모델 간 불일치가 존재하는데 ORM을 사용하면 객체간의 관계를 바탕으로 SQL을 자동으로 생성해 불일치를 해결해줄 수 있음
    • 매핑 역할 해주는 것이 ORM이고 객체를 통해 간접적으로 DB 데이터를 다룸.

      만약 SQL을 직접 작성해서 사용하는 프로젝트였으면 코드가 변경 될 때마다 SQL문을 수정해주거나 추가해줘야하는 번거로운 일이 생김

  • 패러다임 불일치
    • 다대다 관계에서 중간테이블이 하나 더 있어야 함

⇒ 즉, ORM을 사용하면 객체 지향적인 코드로 DB조작이 가능해지고, DB 종류에 상관없이 동일한 코드로 MySQL, PostgreSQL 등 다양한 DBMS를 사용할 수 있다.

TypeORM

  • Typescript + ORM
    • typescirpt에서 orm을 사용할 수 있도록 만든 프레임워크

특징

  • DB의 쿼리문을 사용하는 대신 코드를 사용해 직관적으로 데이터를 처리할 수 있어 사용이 편리하다
    **SQL 예시**
    SELECT * FROM users WHERE age > 20;
    
    **TypeORM 예시**
    const users = await userRepository.find({
      where: { age: MoreThan(20) },
    });
    
  • DBMS에 종속적인 쿼리를 사용하지 않아 DB 변경이 용이하다
  • 독립적인 코드를 사용해 재사용성이 증가하고 유지보수도 쉽다

TypeORM 작성 패턴은 두 가지가 존재한다.

  1. Active Record Pattern

    • 모델 자체 내에서 모든 쿼리 메서드를 정의하고 모델 메서드를 사용하여 오브젝트를 생성,삭제,조회,수정할 수 있게 하는 방식을 의미
    • BaseEntity라는 클래스를 사용하여 새로운 클래스에 상속하게 한 후 사용할 수 있다. 이를 통해 BaseEntity가 갖고 있는 메소드와 static으로 만들어 내는 커스텀 메소드를 이용할 수 있다.
    • 규모가 작은 애플리케이션에서 적합하고 간단히 사용할 수 있다.
    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
    
        static findByName(firstName: string, lastName: string) {
            return this.createQueryBuilder("user")
                .where("user.firstName = :firstName", { firstName })
                .andWhere("user.lastName = :lastName", { lastName })
                .getMany()
        }
    }

    → User 모델을 이용해 user 객체를 이미 구현된 메서드로 간단하게 crud 작성 가능

  2. Data Mapper Pattern

    • repository 라는 별도의 클래스에서 모든 쿼리 메서드를 정의하고 이 repository를 사용하여 객체를 저장 제거 불러온다.
    • 위의 Active Record Pattern와 차이는 User 모델에 접근하는 방식이 아닌 Repository에서 데이터에 접근한다.
    • 규모가 큰 애플리케이션에 적합하고 유지보수하는데 효과적이다.
    import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
    
    @Entity()
    export class User {
        @PrimaryGeneratedColumn()
        id: number
    
        @Column()
        firstName: string
    
        @Column()
        lastName: string
    
        @Column()
        isActive: boolean
    }
  • 테이블간의 관계가 복잡해지고 쿼리가 복잡해질 수록 구현이 어렵다.

그래서 TypeORM의 대표적인 별명중 하나는 anyORM이다.

타입체크를 제대로 해주지 않아, 컴파일 환경에서 에러를 검출하지 못하고, 런타임 환경에서 에러가 발생하게 되는 경우가 생기기 때문이다.

Prisma

  • SQL 코드를 쓰지 않고 javascript, typescript 코드로 데이터베이스를 수정할 수 있도록 연결해주는 ORM이다.(JS, TS 사이의 다리. 즉, 번역기 역할)
  • 객체를 schema로 정의한다음 그 객체와 내가 선택한 데이터 베이스를 연결시켜주는 매개체이다.
  • 코드 내의 변수와 함수의 데이터 타입이 데이터베이스 스키마와 정확히 일치하도록 보장하기 때문에 Node.js + Typescript에서 특히나 유용하다
  • 데이터베이스 스키마의 변경 사항이 자동으로 코드에 반영되어 타입 에러를 줄이고, 개발 과정에서의 디버깅 시간을 단축시켜주어, 데이터 쿼리 및 변형 작업을 더욱 안정적이고 신속하게 수행할 수 있다.

즉, 기존의 ORM과 달리 쿼리 없이 prisma-client의 내장 함수로 완전히 작동이 가능하다. 예를 들어 Java의 JPA의 경우 JPA Query Factory나 EntityManager를 통해 쿼리를 보내지만 복잡한 쿼리나 커스텀이 필요한 경우 JPQL, QueryDSL 등 직접 쿼리를 작성하여 쿼리를 생성하는데, Prisma는 이 과정을 없앰으로써 기존의 ORM보다 개발자의 생산성을 높이면서 동시에 쿼리에 대한 제어는 더 높다.

사용하는 이유

기존 ORM과 다른 작동방식 때문!!

  • 기존 ORM은 DB의 테이블과 코드 내의 클래스를 매핑하여 사용하는 반면 Prisma는 schema.prisma 파일에서 생성한 model이 유일한 단일 출처 역할을 함
    • 데이터베이스 구조, 데이터 모델 정의, 데이터 타입, 관계 등등 모든 정보가 이 파일 하나에 정의되어 있음
    • 하나의 파일에 정의되어 있기 때문에 데이터 타입이 일치하지 않거나 분리되는 문제 방지함. 저 파일을 수정하면 자동으로 CRUD 함수를 업데이트 해주고 모델 변경도 동일함.

특징

  1. 타입 안정성 보장
    • Prisma는 schema.prisma파일을 기반으로 타입 안전한 코드와 CRUD API를 자동 생성함.
    • 이를 통해 개발자는 코드 작성 시 데이터 타입 관련 오류를 줄일 수 있고, 컴파일 시점에서 타입 오류를 감지할 수 있음
  2. 자동 마이그레이션
    • Prisma는 데이터베이스 스키마의 변경을 손쉽게 적용할 수 있는 마이그레이션 도구를 제공함
    • schema.prisma 파일의 변경 사항을 기반으로 데이터베이스 스키마를 자동으로 업데이트할 수 있어 개발 및 배포가 수월해짐
  3. 개발 효율성 및 확장성
    • Prisma Client를 통해 간단한 코드로 복잡한 SQL 쿼리를 실행할 수 있음
    • 개발자가 데이터베이스 작업에 필요한 코드 양을 줄이고, 생산성을 높일 수 있음
model User {
  id    Int    @id @default(autoincrement())
  name  String
  email String @unique
}

//schema.prisma

Prisma 스키마 파일을 사용해 모델을 정의함

  • 데이터베이스 구조를 명확하게 정의함

    Prisma가 추구하는 것은 "개발자의 생산성" 이다.

⇒ 그래서 스타트업 환경에서는 빠른 개발과 시장 출시가 핵심이기에 많은 곳에서 Prisma를 활용해 데이터 모델을 빠르게 구축하고 복잡한 데이터베이스 관계를 쉽게 관리하고 있음. 특히 전자 상거래, 소셜 미디어에서 많이 쓰임

추가로 Prisma 자체가 창업자가 GraphQL 개발자와 협업하여 개발한 기술이기 때문에 GraphQL과의 궁합이 좋다

TypeORMPrisma는 같은 ORM이지만 작동 방식은 매우 다르다.

TypeORM은 SQL과 유사한 쿼리 작성 및 설정을 요구하여 데이터베이스 접근에 더 가깝게 설계된 반면, Prisma는 데이터베이스와 상호 작용할 때 직관적이고 간결하게 코드를 작성할 수 있도록 개발자의 편의성을 고려해 더 높은 추상화 수준을 제공한다.

profile
말못하는감자에서말하는감자가되기까지

0개의 댓글