해결된 질문
22.05.15 14:38 작성
·
937
0
강사님 안녕하세요
항상 좋은 강의 들려주셔서 감사합니다
강의를 수강하며 코드를 따라해보니 실행도 잘되고 테이블도 잘 생성되었습니다
그런데 제가, 코드를 변형하고 싶었습니다
user.js에 기본키 역할을 하는 email 컬럼(필드)을 넣고 싶었습니다
기본키로 id가 자동 생성된다고 말씀해주셨는데,
저는 email 컬럼(필드)를 만들어서 기본키 역할을 하게 만들고 싶었습니다
그래서 추가했더니 에러가 생겨서 혹시 어디가 문제인지 봐주시면 정말 감사하겠습니다
(스택오버플로우를 찾아봐도 아직 실력이 부족해서 원하는 해답을 찾기 어려웠습니다)
1단계. 워크 벤치에서 테이블을 다시 삭제했습니다
2단계는 user.js를 아래처럼 고쳤습니다
3단계는 comment.js를 고쳤습니다
4단계 app.js를 실행했습니다
그러자 에러가 생겼습니다
콘솔창 메시지를 그대로 복붙했습니다
C:\Program Files\nodejs\node.exe .\app.js
3001 번 포트에서 대기 중
Executing (default): CREATE TABLE IF NOT EXISTS `users` (`email` VARCHAR(30) , `name` VARCHAR(20) NOT NULL UNIQUE, `age` INTEGER UNSIGNED NOT NULL, `married` TINYINT(1) NOT NULL, `comment` TEXT, `created_at` DATETIME NOT NULL, PRIMARY KEY (`email`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci;
Executing (default): SHOW INDEX FROM `users` FROM `nodejs`
Executing (default): CREATE TABLE IF NOT EXISTS `comments` (`id` INTEGER NOT NULL auto_increment , `comment` VARCHAR(100) NOT NULL, `created_at` DATETIME, `commenter` VARCHAR(30), PRIMARY KEY (`id`), FOREIGN KEY (`commenter`) REFERENCES `users` (`email`) ON DELETE SET NULL ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
Error
at Query.run (c:\실험\learn_sequelize\node_modules\sequelize\lib\dialects\mysql\query.js:52:25)
at c:\실험\learn_sequelize\node_modules\sequelize\lib\sequelize.js:313:28
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async MySQLQueryInterface.createTable (c:\실험\learn_sequelize\node_modules\sequelize\lib\dialects\abstract\query-interface.js:94:12)
at async Function.sync (c:\실험\learn_sequelize\node_modules\sequelize\lib\model.js:937:5)
at async Sequelize.sync (c:\실험\learn_sequelize\node_modules\sequelize\lib\sequelize.js:377:9) {name: 'SequelizeDatabaseError', parent: Error: Referencing column 'commenter' and refe…lumn 'email' in foreign key constraint 'comm…, original: Error: Referencing column 'commenter' and ref…umn 'email' in foreign key constraint 'comm…, sql: 'CREATE TABLE IF NOT EXISTS `comments` (`id` IN…LT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;', parameters: {…}, …}
아래는 전체 소스코드 입니다
app.js 소스코드입니다
const express = require('express');
const path = require('path')
const morgan = require('morgan')
const nunjucks = require('nunjucks');
const { sequelize } = require('./models')
const app = express();
app.set('port', process.env.PORT || 3001);
app.set('view engine', 'html');
nunjucks.configure('views', {
express: app,
watch: true,
});
sequelize.sync({force: false})
.then(()=>{
console.log('데이터베이스 연결 성공');
})
.catch((err)=>{
console.error(err);
});
app.use(morgan('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
// app.use('/', indexRouter);
// app.use('/users', usersRouter);
// app.use('/comments', commentsRouter);
app.use((req, res, next) => {
const error = new Error(`${req.method} ${req.url} 라우터가 없습니다.`);
error.status = 404;
next(error);
}); //
app.use((err, req, res, next) => {
res.locals.message = err.message;
res.locals.error = process.env.NODE_ENV !== 'production' ? err : {};
res.status(err.status || 500);
res.render('error');
});//
app.listen(app.get('port'), () => {
console.log(app.get('port'), '번 포트에서 대기 중');
}); //3001번 포트 대기 중
user.js 소스코드입니다
/**
* ./models/user.js
*/
const Sequelize = require('sequelize');
module.exports = class User extends Sequelize.Model {
static init(sequelize) {
return super.init({
email: {
type: Sequelize.STRING(30),
primaryKey: true,
},
name: {
type: Sequelize.STRING(20),
allowNull: false,
unique: true,
},
age: {
type: Sequelize.INTEGER.UNSIGNED,
allowNull: false,
},
married: {
type: Sequelize.BOOLEAN,
allowNull: false,
},
comment: {
type: Sequelize.TEXT,
allowNull: true,
},
created_at: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.NOW,
},
}, {
sequelize,
timestamps: false,
underscored: false,
modelName: 'User',
tableName: 'users',
paranoid: false,
charset: 'utf8',
collate: 'utf8_general_ci',
});
}
static associate(db) {
db.User.hasMany(db.Comment, { foreignKey: 'commenter', sourceKey: 'email' });
}
};
comment.js 소스코드입니다
/**
* ./models/comment.js
*/
const Sequelize = require('sequelize');
module.exports = class Comment extends Sequelize.Model {
static init(sequelize) {
return super.init({
comment: {
type: Sequelize.STRING(100),
allowNull: false,
},
created_at: {
type: Sequelize.DATE,
allowNull: true,
defaultValue: Sequelize.NOW,
},
}, {
sequelize,
timestamps: false,
modelName: 'Comment',
tableName: 'comments',
paranoid: false,
charset: 'utf8mb4',
collate: 'utf8mb4_general_ci',
});
}
static associate(db) {
db.Comment.belongsTo(db.User, { foreignKey: 'commenter', targetKey: 'email' });
}
};
index.js 소스코드입니다
const Sequelize = require('sequelize');
const User = require('./user');
const Comment = require('./comment');
const env = process.env.NODE_ENV || 'development'; //환경변수 NODE_ENV 또는 'development' 로 하겠다
const config = require(__dirname + '/../config/config.json')[env];
const db = {};
const sequelize = new Sequelize(config.database, config.username, config.password, config);
db.sequelize = sequelize;
db.Sequelize = Sequelize;
db.User = User;
db.Comment = Comment;
User.init(sequelize);
Comment.init(sequelize);
User.associate(db);
Comment.associate(db);
module.exports = db;
구글링을 해봐도 원인을 잘 모르겠어서 가르쳐주시면 정말 감사하겠습니다
읽어주셔서 감사합니다
답변 1
1
2022. 05. 15. 15:35
에러메시지가 짤려서 안 보이는데요. 저기 나오는 SQL을 순서대로 워크벤치에 입력한 후에 에러메시지 전체를 확인해봐야할 것 같습니다.
혹시 이렇게 이해해도 되는지 질문드리고 싶습니다
위의 사진처럼 commenter 컬럼 따로 이렇게 만들어주지 않고
}
이렇게 belongsTo 문 안에만 commenter 외래키를 만들어주면
commenter 컬럼의 데이터타입의 디폴트값이,
시퀄라이즈가 자동으로 만들어주는 id 컬럼과 같은 int 타입이 되기 때문에
호환성 문제가 생긴 것이라는 결론을 내렸습니다
네 알겠습니다..
먼저 익스프레스 공식문서부터 찾아봤었는데 시퀄라이즈가 안나와서요
시퀄라이즈 공식문서도 찾아봤는데, 여기는 검색창이 안보여서.. 어떤 목록을 찾아야 하는지 모르겠어서
Sequelize v6 | Sequelize
결국 스택오버플로우에서 다른 분들 예시보고 추론을 하게 된 것 같습니다
그래도 공식문서 위주로 찾는 연습을 해볼게요
2022. 05. 15. 16:33
user.js 입니다
/**
* ./models/user.js
*/
const Sequelize = require('sequelize');
module.exports = class User extends Sequelize.Model {
static init(sequelize) {
return super.init({
email: {
type: Sequelize.STRING(30),
primaryKey: true,
},
name: {
type: Sequelize.STRING(20),
allowNull: false,
unique: true,
},
age: {
type: Sequelize.INTEGER.UNSIGNED,
allowNull: false,
},
married: {
type: Sequelize.BOOLEAN,
allowNull: false,
},
comment: {
type: Sequelize.TEXT,
allowNull: true,
},
created_at: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.NOW,
},
}, {
sequelize,
timestamps: false,
underscored: false,
modelName: 'User',
tableName: 'users',
paranoid: false,
charset: 'utf8',
collate: 'utf8_general_ci',
});
}
static associate(db) {
db.User.hasMany(db.Comment, { foreignKey: 'commenter', sourceKey: 'email' });
}
};
comment.js 입니다 ㅠㅠ
/**
* ./models/comment.js
*/
const Sequelize = require('sequelize');
module.exports = class Comment extends Sequelize.Model {
static init(sequelize) {
return super.init({
commenter: {
type: Sequelize.STRING(30),
},
comment: {
type: Sequelize.STRING(100),
allowNull: false,
},
created_at: {
type: Sequelize.DATE,
allowNull: true,
defaultValue: Sequelize.NOW,
},
}, {
sequelize,
timestamps: false,
modelName: 'Comment',
tableName: 'comments',
paranoid: false,
charset: 'utf8mb4',
collate: 'utf8mb4_general_ci',
});
}
static associate(db) {
db.Comment.belongsTo(db.User, { foreignKey: 'commenter', targetKey: 'email' });
}
};
마지막으로 index.js 소스코드입니다
const Sequelize = require('sequelize');
const User = require('./user');
const Comment = require('./comment');
const env = process.env.NODE_ENV || 'development'; //환경변수 NODE_ENV 또는 'development' 로 하겠다
console.log(process.env.NODE_ENV)
console.log(env)
const config = require(__dirname + '/../config/config.json')[env];
const db = {};
const sequelize = new Sequelize(config.database, config.username, config.password, config);
db.sequelize = sequelize;
db.Sequelize = Sequelize;
db.User = User;
db.Comment = Comment;
User.init(sequelize);
Comment.init(sequelize);
User.associate(db);
Comment.associate(db);
module.exports = db;
2022. 05. 15. 18:40
const { DataTypes } = require("Sequelize");
Foo.hasOne(Bar, {
foreignKey: {
// name: 'myFooId'
type: DataTypes.UUID
}
});
Bar.belongsTo(Foo);
2022. 05. 15. 18:53
아뇨.. type이 핵심입니다... 제가 코드에 type을 적어드렸는데 왜 자꾸 name만 적으시나요. foreignKey: { name: 'commenter', type: Sequelize.STRING(30) }
2022. 05. 15. 18:58
아, 그리고 지금 charset, collation이 테이블 둘이 다릅니다. 문자열에서는 이 둘이 중요해서 두 테이블이 같아야할 것 같습니다. 테이블 지우고 다시 만들어보세요.
2022. 05. 15. 19:09
참고로 Sequelize랑 DataTypes랑 호환됩니다. DataTypes.UUID, Sequelize.UUID
DataTypes.STRING(30), Sequelize.STRING(30)
2022. 05. 15. 16:00
답변해주셔서 감사합니다
워크벤치를 확인해보니, users 테이블은 생성이 되었습니다
comments 테이블은 생성되지 않았습니다
제 생각에는
부모 테이블을 만든 다음 외래키를 갖는 자식 테이블을 생성하는 순서니까
부모테이블인 users 테이블부터 먼저 만들어졌으니 순서는 맞는 것 같았습니다
에러메시지를 봤습니다
여기서 파란색 표시된 에러 메시지를 스택오버플로우에 검색해봤습니다
컬럼이 호환되지 않는다고 합니다
mysql - 오류 번호 : 3780 외래 키 제약 조건 '%s'에서 열 '%s'와 참조 열 '%s'를 참조하는 것은 호환되지 않습니다 - 스택 오버플로 (stackoverflow.com)
그런데, 저는 이 원인이 좀 의아한 게 아래 사진을 봐주시면
comments.js의 commenter 컬럼을
user.js의 email 컬럼을 참고하는 외래키로 만들어주긴 했지만,
commenter의 type을 따로 세팅해주지도 않았는데, 왜 호환성 문제가 생긴건지 모르겠습니다
혹시 제가 놓친 부분을 가르쳐주시면 정말 감사하겠습니다