Node 교재로 공부하던 중 ORM사용시에 모델을 정의하게 되는데 실무에서는 모델들이 100개가 넘어가는 경우가 흔하다고 한다

위의 사진에서는 각각의 모델들을 수동적으로 초기화 시키고, 연관 관계를 짖는 코드이다
만약 실무에서 모델들이 100개가 넘어가면 모두 수동으로 초기화 시키기는 너무 비효율적이다
그래서 책에서 제공된 동적으로 모델들을 초기화 시키는 코드를 나의 상황에 맞게 변형시켜 보았다
나의 개발 환경은 typescript를 사용하므로 CommonJS가 아닌 ESM 환경이다
폴더명, 파일명 추출
const __dirname = fileURLToPath(new URL('.', import.meta.url));
const __filename = fileURLToPath(import.meta.url);
const basename = path.basename(__filename);
먼저 현재 폴더명과 파일명을 추출 한다
models 폴더 내부 파일 추출
const files = fs.readdirSync(__dirname).filter(file => {
// 숨김 파일, index.ts, ts 확장자가 아닌 파일 필터링
return file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.ts';
});
파일명의 첫 글자가 점(.)인 파일, 현재 파일인 index.ts, 확장자가 .ts가 아닌 파일을 필터링 한다
비동기로 모듈 가져오기
const models: Promise<MyModel | undefined>[] = files.map(async file => {
const model: MyModel | undefined = await import(`../models/${file}`).then(data => data.default);
//미완성 모델이라서 export하지 않은 파일 검증
if (typeof model !== 'undefined') {
model.initiate(sequelize);
return model;
}
});
Node 교재에선 동적으로 모델들을 불러오는 해당 방식의 단점이 미완성 모델이 있을시 미완성 모델도 초기화 시키는 점과 models 폴더 내부에 model 객체가 아닌 다른 파일을 넣지 않도록 주의해야 한다고 한다
그래서 개인적인 생각으로는 미완성 모델은 export를 하지 않는다고 생각해서 미완성 모델을 검증하는 if 문을 추가하였다
비동기 작업 대기
//비동기 작업이 전부 완료된 후 연관 관계 설정
Promise.all(models).then(models => {
models.forEach(model => {
if (model) model.associate();
});
});
위의 단계에서 모든 비동기 작업(모델 초기화)이 완료된 이후에 모델간 연관 관계를 설정해야 하므로
Promise.all() 메서드를 사용해서 모든 비동기 작업들이 완료된 후 연관 관계를 설정한다
주의 사항
app.listen(port, async () => {
await sequelize
.sync({ force: false })
.then(() => console.log('디비 연결 성공'))
.catch(e => console.log(e));
console.log(`open Server port ${port}`);
});
비동기 코드를 작성한 후 서버를 실행 시킬때 db와의 연결을 시도하면 db에는 아무런 테이블이 생성되지 않는다

데이터베이스에는 연결이 성공적이지만 테이블은 아무것도 생성되지 않은걸 볼 수 있다

나는 이러한 문제 때문에 몇시간 고생했다...
원인은 모델을 비동기적으로 불러오기 때문이다
시퀄라이즈는 모델들을 초기화 시킨 이후 db와의 연결을 통해 테이블을 생성해야 하는데
모델 초기화보다 db연결이 먼저 진행되기 때문에 발생하는 문제이다
그러므로 모델 초기화 이후 db연결을 진행시켜 줘야한다
//비동기 작업이 전부 완료된 후 연관 관계 설정
const conn = Promise.all(models).then(async models => {
models.forEach(model => {
if (model) model.associate();
});
//연관 관계 설정 이후 db 연결
await sequelize
.sync({ force: false })
.then(() => console.log('디비 연결 성공'))
.catch(e => console.log(e));
});
export default conn;
//app.js
import conn from './sequelize/models/index.js';
app.listen(port, async () => {
await conn; //서버 실행시 시퀄라이즈 셋팅 대기
console.log(`open Server port ${port}`);
});
전체 코드
// models/index.ts
import { Sequelize } from 'sequelize';
import configs from '../config/config.js';
import dotenv from 'dotenv';
import { MyModel } from '../../types/types.js';
import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';
dotenv.config();
const __dirname = fileURLToPath(new URL('.', import.meta.url));
const __filename = fileURLToPath(import.meta.url);
const PRODUCTION = process.env.PRODUCTION;
const config = PRODUCTION ? configs.production : configs.development;
const sequelize = new Sequelize(config.database, config.username, config.password, {
...config,
dialect: 'mysql',
});
const basename = path.basename(__filename);
const files = fs.readdirSync(__dirname).filter(file => {
// 숨김 파일, index.ts, ts 확장자가 아닌 파일 필터링
return file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.ts';
});
const models: Promise<MyModel | undefined>[] = files.map(async file => {
const model: MyModel | undefined = await import(`../models/${file}`).then(data => data.default);
//미완성 모델이라서 export하지 않은 파일 검증
if (typeof model !== 'undefined') {
model.initiate(sequelize);
return model;
}
});
//비동기 작업이 전부 완료된 후 연관 관계 설정
const conn = Promise.all(models).then(async models => {
models.forEach(model => {
if (model) model.associate();
});
//비동기로 모델을 불러오기 때문에 모델 초기화 후 db 연결
await sequelize
.sync({ force: false })
.then(() => console.log('디비 연결 성공'))
.catch(e => console.log(e));
});
export default conn;
'database' 카테고리의 다른 글
| SQL 쿼리 성능 개선 (0) | 2024.08.19 |
|---|---|
| 테이블 2개 JOIN시 COUNT값이 곱셈이 된다? (0) | 2024.08.17 |
| ORM 사용 후기 (0) | 2024.04.11 |
| mariadb Node 환경에서 트랜젝션과 관리 (0) | 2024.04.02 |
| MySQL 자료형 (1) | 2024.03.14 |