ORM이란

cdwde·2022년 9월 14일
1
post-thumbnail

프로젝트를 진행하면서 TypeORM을 사용하고 있다. 이유는? 그냥 좋다고 하길래...😅 확실하게 ORM이 뭐고, 왜 쓰는지 이해하고 사용해보려고 글을 작성한다.

ORM (Object Relational Mapping 객체-관계 매핑)

객체와 관계형 데이터베이스의 데이터를 자동으로 매핑(연결)해주는 것이라는 의미로, 어플리케이션과 데이터베이스 연결 시 SQL 언어가 아닌 어플리케이션 개발언어로 데이터베이스를 접근할 수 있게 해주는 툴이다.

쉽게 설명하자면, 원래 관계형 DB를 사용하기 위해선 SQL을 사용해야했다. 하지만 어플리케이션 코드를 짜는 것도 머리가 아픈데 DB 쿼리까지 신경쓰려면 슬프다. 그래서 ORM을 사용한다고 한다.
예를 들어 파이썬(장고)에서 작성한 파이썬 코드를 관계형 DB의 SQL 쿼리로 자동 변환 시켜서 개발자가 따로 SQL 쿼리를 작성할 필요 없이 파이썬 코드 작성만으로 DB를 조작할 수 있게 해주는 것이다.

객체 지향 프로그래밍은 클래스를 사용하고, 관계형 데이터베이스는 테이블을 사용한다. 여기서 객체 모델과 관계형 모델 간의 불일치가 존재하는데 이를 객체 간의 관계를 바탕으로 SQL을 자동생성하여 불일치를 해결해준다.

ORM의 장점

완벽한 객체지향적인 코드

  • ORM을 사용하면 SQL Query가 아닌 직관적인 코드(메서드)로 데이터를 조작할 수 있어, 개발자가 객체 모델로 프로그래밍하는데 집중할 수 있도록 도와준다.
  • 선언문, 할당, 종료 같은 부수적인 코드가 없거나 급격히 줄어든다.
  • 각종 객체에 대한 코드를 별도로 작성하기 때문에 코드의 가독성을 올려준다.
  • SQL의 절차적이고 순차적인 접근이 아닌 객체 지향적인 접근으로 인해 생산성이 증가한다.

재사용, 유지보수, 리팩토링 용이성

  • ORM은 독립적으로 작성되어 있고, 해당 객체들을 재활용할 수 있다.
  • 매핑정보가 명확하여 ERD를 보는 것에 대한 의존도를 낮출 수 있다.

DBMS에 대한 종속성 하락

  • 객체 간의 관계를 바탕으로 SQL문을 자동으로 생성하고, 객체의 자료형 타입까지 사용할 수 있기 때문에 RDBMS의 데이터 구조와 객체지향 모델 사이의 간격을 좁힐 수 있다.
  • 객체에만 집중할 수 있기 때문에 DBMS를 교체하는 큰 작업에도 리스크가 적고 드는 시간도 줄어든다.

ORM의 단점

  • 완벽한 ORM으로만 서비스를 구현하기 어렵다.
    사용하기는 편하지만 설계는 매우 신중하게 해야하며, 프로젝트의 복잡성이 커질 경우 난이도 또한 올라갈 수 있다. 잘못 구현된 경우에 속도 저하 및 심각할 경우 일관성이 무너지는 문제점이 발생할 수 있다.

Node.js에서 지원하는 ORM

Sequlize

MySQL, PostgreSQL, MariaDB 등 많은 RDBMS를 지원하고 Promise 기반으로 구현되어 있기 때문에 비동기 로직을 편리하게 작성할 수 있다.

아직 제대로 써본 적이 없어서 잘 모르겠다.

TypeORM

공식문서에는 다음과 같이 정의되어 있다.

TypeORM은 Node.js, Browser, React Native 플랫폼 등에서 JS, TS와 함께 사용할 수 있는 ORM이다. 소규모 데이터베이스부터 대규모 엔터프라이즈 어플리케이션을 개발하는데 도움이 되는 추가 기능을 제공하는 것을 목표로 합니다. 다른 ORM과 달리 Active Record PatternData Mapper Pattern을 모두 지원하여 확장 가능하며 유지보수가 가능한 어플리케이션을 가장 생산적인 방법으로 작성할 수 있다.

Active Record Pattern

Active Record Patter은 모델 자체 내에서 모든 쿼리 메서드를 정의하고 모델 메서드를 사용하여 오브젝트를 생성, 삭제, 조회, 수정할 수 있게 하는 방식을 의미한다.

아래와 같이 User 모델의 프로퍼티와 메서드를 정의할 수 있다.

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 객체를 이미 구현된 메서드로 간단하게 생성, 삭제, 조회, 수정할 수 있다.

또한 위에서 User 모델에 직접 커스텀하여 구현한 메서드 또한 아래처럼 사용할 수 있다.

const user = new User()
user.firstName = "Timber"
user.lastName = "Saw"
user.isActive = true
await user.save()

await user.remove()
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" })
//구현한 메서드
const timber = await User.findByName("Timber", "Saw")

Data Mapper Pattern

Data Mapper Patter은 레포지토리라는 별도의 클래스에서 모든 쿼리 메서드를 정의하고 이 레포지토리를 사용하여 오브젝트를 생성, 삭제, 조회, 수정할 수 있게 하는 방식을 의미한다.

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

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

    @Column()
    firstName: string

    @Column()
    lastName: string

    @Column()
    isActive: boolean
}

아래처럼 User의 레포지토리를 가져와 User 레포지토리에 생성, 삭제, 조회, 수정할 수 있다.

const userRepository = dataSource.getRepository(User)

const user = new User()
user.firstName = "Timber"
user.lastName = "Saw"
user.isActive = true
await userRepository.save(user)

참고
[DB] ORM이란
ORM(Object Relational Mapping)이 뭘까? 🤔
[Node.js] TypeORM이란? (feat. ORM Library)

0개의 댓글