소프트웨어 설계에서 디자인 패턴
1. MVC
MVC는 Model View Controller의 약자로 애플리케이션을 세 가지 역할로 구분하는 개발 방법론. 사용자가 Controller를 조작하면, Controller는 Model을 통해 데이터를 가져온다. 가져온 정보를 바탕으로 시각적 표현을 담당하는 View를 제어하여 사용자에게 전달한다.
Web에서 MVC를 적용하면 다음 과정을 거치게 된다.
- 사용자가 웹 사이트에 접속
- Controller는 사용자가 요청한 웹페이지를 서비스하고자 모델을 호출
- Model은 데이터베이스이나 파일 등 리소스를 제어하고, 그 결과를 반환
- Controller는 Model이 반환한 결과를 View에 반영
- 새로운 정보가 반영된 View가 사용자에게 전달
2. ORM
ORM(Object-Relational Mapping)은 모델을 기술하는 도구이다. ORM을 이용하면 직접 SQL 쿼리를 작성하지 않고, 엔티티를 자바스크립트로 표현할 수 있다. 자바스크립트에는 객체를 클래스로 구현하였는데, 클래스와 데이터 테이블을 자동으로 매핑(연결)한 것이다.
Object)) --- B(ORM) B --- C[(Relational
Database)]
3. Sequelize
Sequelize는 프로미스 기반 Node.js 환경에서 사용할 수 있는 ORM이다. 설치 및 사용법은 공식문서 - CLI을 사용하는 방법를 읽도록 하자.
npm install --save sequelize
npm install --save mysql2 // 지원하는 데이터베이스 중 원하는 것을 선택.
npm install --save sequelize-cli // CLI(Command-line Interface)를 사용할 수 있도록 하는 보조 툴
모델(Models)은 클래스(Class)의 메서드, 속성과 스키마(Schema)의 엔티티를 합쳐놓은 것이다. 실제 데이터베이스로 옮기기 전, 와이어 프레임을 짤 수 있는 곳. 모델의 기능을 추가하거나 삭제할 수 있다.
마이그레이션(Migration)은 스키마(Schema)를 정의한다. 한편, 각각의 마이그레이션은 깃의 커밋처럼 작업 히스토리를 남기는 역할을 수행한다. 따라서, 모델을 수정해야한다면 먼저 작업을 되돌리고, 새로운 마이그레이션을 생성한다.
npx sequelize-cli db:mirgrate:undo // 가장 최근에 데이터베이스로 옮긴 작업을 되돌린다.
npx sequelize-cli migration:generate --name ...// 모델을 수정하기 위해 새로운 마이그레이션을 생성한다. 새로 생성한 마이그레이션에 수정 작업을 해야한다.
새로 생성한 마이그레이션에 반영할 수정사항을 적어준다. 이 때, 마이그레이션이 작업 히스토리의 역할을 수행할 수 있도록 up, down에 모두 적어주어야 한다.
// 새로 생성한 mirgartion js
'use strict';
const { users, url } = require("../models")
// npx sequelize-cli migration:generate --name "name..."
//새로운 Migration Skeleton을 생성한다. 여기에서 FK 등 수정작업을 할 것.
module.exports = {
up: async (queryInterface, Sequelize) => {
// UP은 새로 추가할 요소들을 적는다. 데이터 베이스에 적용하기.
// QueryInterface API를 살펴볼 것.
queryInterface.addColumn("urls", "userId", Sequelize.INTEGER);
},
down: async (queryInterface, Sequelize) => {
// DOWN은 Undo 할 때 할 것을 적는다. 데이터 베이스에서 되돌리기.
queryInterface.removeColumn("urls", "userId");
}
};
Association은 관계형 데이터베이스에서 JOIN 관계를 갖는 데이터 사이의 처리를 위해 사용한다. Sequelize에서 $1: N$을 구현해보자. 새로운 마이그레이션을 생성하여 외래키를 만들고, 각 모델파일에서 association을 추가해야 한다. 모델과 마이그레이션에서 수정작업이 끝나면, npx sequelize-cli db:migrate
를 실행하면 된다.
// 1. models/url.js
"use strict";
const { Model } = require("sequelize");
module.exports = (sequelize, DataType) => {
class url extends Model {
static associate(models) {
// Associate를 정의한다.
url.belongsTo(models.users, {
foreignKey: "userId"
})
}
};
url.init({
// Model fields
url: DatyTypes.STRING,
title: DataTypes.STRING,
visits: {
type: DataTypes.INTEGER,
defaultValue:0
}
}, {
// Sequelizer Options
sequelize,
modelName: "url"
})
return url;
};
// 2. models/users.js
"use strict"
const { Model } = require("sequelizer");
module.exports = (sequelize, DataTypes) => {
class users extends Model {
static associate(models) {
// Associate를 정의한다.
users.hasMany(models.url, {
foreignKey: "userId",
as: "urls"
})
}
};
users.init({
name: DataTypes.STRING,
email: DataTypes.STRING
}, {
sequelize,
modelName: "users"
});
return users;
}
// 3. migrations/새로 생성한 마이그레이션.js
// urls 테이블에 새로운 Column(=userId)를 생성해야 한다.
"use strict"
module.exports = {
up: async (queryInterface, Sequelize) => {
// Model 이름이 아닌 Table 이름으로 적어야 한다. (urls이다)
return queryInterface.addColumn("urls", "userId", {
type: "integer",
references: {
model: "users",
key: "id"
},
// 참조하는 테이블을 수정하거나 삭제하면, 다른 테이블도 같이 영향을 받는다.
// 따라서 삭제 또는 수정할 때 FOREIGN KEY의 제약조건을 미리 설정해야한다.
onUpdate: "CASCADE",
onDelete: "SET NULL"
})
},
down: async (queryInterface, Sequelize) => {
return queryInterface.removeColumn("urls, "userId");
}
};
위 예제에서 볼 수 있듯이 외래키를 사용할 때 제약조건을 설정해야한다. 삭제 또는 수정할 때 어떤 행동을 할 것인지 정할 수 있다. 자세한 내용은 다음 테이블을 참조하도록 하자.
제약조건 | 내용 |
---|---|
CASCADE | 참조되는 테이블에서 데이터를 삭제하거나 수정하면, 참조하는 테이블의 데이터도 삭제하거나 수정한다. |
SET NULL | 참조되는 테이블에서 데이터를 삭제하거나 수정하면, 참조하는 테이블의 데이터를 NULL로 변경한다. |
NO ACTION | 참조되는 테이블에서 데이터를 삭제하거나 수정하여도, 참조하는 테이블의 데이터를 변경하지 않는다. |
SET DEFAULT | 참조되는 테이블에서 데이터를 삭제하거나 수정하면, 참조하는 테이블의 데이터를 필드의 기본값으로 변경한다. |
RESTRICT | 참조되는 테이블에 데이터가 남아있으면, 참조되는 테이블의 데이터를 삭제하거나 수정할 수 없다. |
Leave a comment