TIL [DB] ORM

김은혁·2021년 8월 2일
0

MVC 패턴

MVC(Model-View-Controller) 패턴은 사용자 인터페이스, 데이터 및 논리 제어를 구현하는데 널리 사용되는 소프트웨어 디자인 패턴이다. 이 패턴은 소프트웨어의 비즈니스 로직과 화면을 구분하는데 중점을 두고 있다. 이러한 관심사 분리는 더 나은 업무의 분리와 향상된 관리를 제공한다. 관심사 분리가 잘 이루어진다면, 사용자 인터페이스로부터 비즈니스 로직을 분리하여 어플리케이션의 시각적 요소나 그 이면에서 실행되는 비즈니스 로직을 서로 영향 없이 동작하게 할 수 있다.

Model

모델은 데이터와 비즈니스 로직을 관리한다. 모델은 어플리케이션이 포함해야할 데이터가 무엇인지 정의하고, 데이터의 상태가 변경되면 뷰에게 알리며 가끔 컨트롤러에게 알리기도 한다.(업데이트된 뷰를 제거하기 위해 다른 로직이 필요한 경우)

View

뷰는 레이아웃과 화면을 처리한다. 뷰는 어플리케이션의 데이터를 보여주는 방식을 정의한다.

Controller

컨트롤러는 명령을 모델과 뷰 부분으로 라우팅한다. 컨트롤러는 어플리케이션의 사용자로부터 입력에 대한 응답으로 모델 및 뷰를 업데이트하는 로직을 포함한다.

MVC 패턴의 한계

그렇다면 MVC 패턴은 무조건 좋은 패턴이라고 할 수 있을까? 물론 아니다. 그렇기에 MVVM, MVP, MVW 등 여러 패턴이 존재할 것이다.

한 모델은 다수의 뷰를 가질 수 있고 반대로 컨트롤러를 통해 한 뷰에 연결되는 모델도 여러 개가 될 수 있다. 결과적으로 뷰와 모델이 서로 의존성을 갖게 되는 것이다. MVC 규모 자체가 너무 복잡하고 비대해져서 새 기능을 추가할 때마다 의존성을 일일이 해결해야하는 형태를 MassiveViewController라고 부르는데, MVC의 한계를 표현한 용어이기도 하다.


ORM

Object-Relational Mapping, ORM은 객체와 관계형 데이터베이스의 데이터를 자동으로 매핑해주는 것을 의미한다. ORM을 이용하면 관계형 데이터베이스의 엔티티, 레코드에 접근할 때 마치 js의 객체나 클래스를 다루듯이 취급할 수 있다.

Js 코드로 표현

class Person (...) {
	...
}

const person = new Person(...);
                          
console.log(person.name); 
// "EunHyuk"
console.log(person.phone); 
// ["010-1234-5678", "031-123-4567"]

DB로 표현

person
id name company
0 EunHyuk no,,,
... ... ...

phone
id number
0 "010-1234-5678"
1 "031-123-4567"
... ...

person-phone
id person_id phone_id
0 0 0
1 0 1
... ... ...

JS에서 각 속성은 DB에서 필드라고 볼 수 있다
SQL 문이 전혀 없이도 DB에 접근

ORM의 장점

  • 더 직관적이고 비즈니스 로직에 집중하도록 도움
  • 재사용 및 유지보수의 편리성 증가
  • DBMS에 대한 종속성 감소

Sequelize

Sequelize는 Node.js 기반의 ORM이다. ORM은 다양한 관계형 데이터베이스를 지원한다.

Sequelize 설치
$ npm install --save sequelize

빈 프로젝트 만들기 => 다음과 같은 폴더 생성
$ npx sequelize-cli init

  • config : DB에 연결하는 방법을 CLI에 알려주는 구성 파일 포함
  • models : 프로젝트의 모든 모델 포함
  • migrations : 모든 마이그레이션 파일 포함
  • seeders : 모든 시드 파일 포함

CLI-DB 연결
config/config.json 설정

// config/config.json
{
  "development" : {
    "username" : "root",
    "password" : null,
    "database" : "데이터베이스 이름",
    "host" : "12.0.0.1",
   	"dialect" : "mysql"
  }
}

Sequelize CLI는 기본적으로 mysql을 가정한다. 다른 DB를 사용하고 싶은 경우 dialect옵션을 변경해주면 된다.

CLI 구성 파일을 올바르게 구성했다면 첫 번째 마이그레이션을 만들 준비가 되었다. model:generate명령을 사용하면 가능하다. 이 명령에는 name, attributes 옵션이 필요하다.

$ npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string

위의 명령어는 firstName, lastName, email을 속성으로 가지는 User 모델을 만드는 명령어이다. 이렇게 하면 models 폴더에 user파일을 만들고 migrations폴더에 xxxxxxxxx-create-user.js이란 이름의 마이그레이션 파일을 만든다. 공부를 하며 알게된 사실인데 속성들 사이 ,다음에 공백이 존재해선 안 된다.

마이그레이션 실행
위의 단계까지는 데이터베이스에 아무 것도 삽입하지 않았다. 이제 실제로 데이터베이스에 해당 테이블을 생성하려면 db:migrate명령을 실행해야 한다.

$ npx sequelize-cli db:migrate

위의 명령은 다음과 같은 동작을 수행시킨다.

  • SequelizeMeto 데이터베이스에서 호출된 테이블을 확인. 이 테이블은 현재 데이터베이스에서 실행된 마이그레이션을 기록하는데 사용
  • 아직 실행되지 않은 마이그레이션 파일을 찾음. (SequelizeMeta 테이블을 확인함으로써 가능)
  • Users마이그레이션 파일에 지정된 대로 모든 열을 사용하여 호출되는 테이블 생성

시드 생성
$ npx sequelize-cli seed:generate --name demo-user
위의 명령은 seeders 폴더에 시드 파일을 생성하고 이 파일을 편집하여 User테이블에 데이터를 넣을 수 있다.

module.exports = {
  up : (queryInterface, Sequelize) => {
    return queryInterface.bulkInsert('Users', [{
      firstName : 'John',
      lastName : 'Doe',
      email : 'example@example.com',
      createdAt : new Date(),
      updatedAt : new Date()
    }]);
  },
  down : (queryInterface, Sequelize) => {
    return queryInterface.bulkDelete('Users', null, {});
  }
};

시드 커밋
$ npx sequelize-cli db:seed:all
위와 같은 명령어를 입력하면 해당 시드 파일이 실행되고 데이터가 Users테이블에 삽입된다.

추가적인 사항은 공식문서에서 확인할 수 있다.
https://sequelize.org/master/manual/migrations.html

관계 설정
위의 과정에서 두 개 이상의 테이블이 있다면 Sequelize를 통해 1:1, 1:N, N:M 관계 설정이 가능하다.

1 : 1
1대 1 관계는 서로 다른 두 개의 모델이 오직 하나의 외래키로 연결되어 있는 관계이다. 위의 Person 모델과 관계지어지는 Team 모델이 있다고 가정해보자. 각 모델의 파일에 associate(models) 메서드 안에 다음과 같은 코드를 입력해주면 된다.

models/person.js
models.person.belongsTo(models.team)
// 이 경우 person 모델에 team모델을 참조하기 위한 teamId라는 속성이 생긴다.

models/team.js
models.team.hasOne(models.person)

1 : N
위와 비슷하지만 사용하는 메서드가 다르다.

models/person.js
models.person.belongsTo(models.team)

models/team.js
models.team.hasMany(models.person)

N : M

models/person.js
models.person.belongsToMany(models.team)

models/team.js
models.team.belongsToMany(models.person)

0개의 댓글