Sequelize创建关联时报db.define is not a function错误如何解决
错误根源
- 执行顺序倒置:index.js中优先导入模型文件,此时sequelize实例尚未初始化,挂载到db对象的操作也未执行,模型文件中导入的db是空对象,自然不存在
define方法 - 方法调用对象错误:
define是Sequelize实例的原生方法,你自行声明的db是普通JS对象,本身不具备define方法 - 关联逻辑时机错误:未等模型定义完成就调用
hasOne、hasMany等关联方法,自然会报方法不存在
修正方案
1. 调整模型文件写法(以practUsers.js为例)
模型文件不要直接导入index.js的db,改为导出工厂函数,接收sequelize实例和DataTypes作为参数完成模型定义,关联逻辑写在模型的associate静态方法中:
const Sequelize = require('sequelize') const Op = Sequelize.Op module.exports = (sequelize, DataTypes) => { const practUser = sequelize.define("practUsers", { firstName: { type: DataTypes.STRING, allowNull: false }, lastName: { type: DataTypes.STRING, allowNull: false }, address: { type: DataTypes.STRING, allowNull: false }, unit: { type: DataTypes.STRING, allowNull: false }, city: { type: DataTypes.STRING, allowNull: false }, province: { type: DataTypes.STRING, allowNull: false }, postal_code: { type: DataTypes.STRING, allowNull: false }, phoneNumber: { type: DataTypes.STRING, allowNull: false }, email: { type: DataTypes.STRING, allowNull: false, unique: true }, birthdate: { type: DataTypes.STRING, allowNull: false }, healthCardNumber: { type: DataTypes.STRING, allowNull: false, unique: true }, profession: { type: DataTypes.STRING, allowNull: false }, designation: { type: DataTypes.STRING, allowNull: false }, userType: { type: DataTypes.STRING, allowNull: false }, }) practUser.associate = (models) => { practUser.hasMany(models.practAppt, {foreignKey: "client"}) } return practUser }
practAppt.js也采用同样的工厂函数写法,关联逻辑写在自身的associate方法中:
module.exports = (sequelize, DataTypes) => { const practAppt = sequelize.define("practAppt", { // 保留你原有practAppt的字段定义 }) practAppt.associate = (models) => { practAppt.hasOne(models.practUser, {foreignKey: "email"}) } return practAppt }
2. 调整index.js逻辑
先初始化sequelize实例,再加载模型,删除顶部提前导入模型的代码,加载模型时传入sequelize和DataTypes参数:
'use strict'; const fs = require('fs'); const path = require('path'); const Sequelize = require('sequelize'); const basename = path.basename(__filename); const env = process.env.NODE_ENV || 'development'; const config = require(__dirname + '/../config/config.json')[env]; const db = {}; // 先初始化sequelize实例 var sequelize = new Sequelize({ dialect: 'sqlite', storage: 'C:/backend/db.sqlite3' }); // 加载所有模型 fs .readdirSync(__dirname) .filter(file => { return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'); }) .forEach(file => { console.log("FILE", file) // 调用模型导出的工厂函数,传入sequelize和DataTypes const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes); db[model.name] = model; }); // 统一调用所有模型的关联方法,此时所有模型已加载完成,不会出现循环依赖问题 Object.keys(db).forEach(modelName => { if (db[modelName].associate) { db[modelName].associate(db); } }); // 原有认证逻辑不变 sequelize .authenticate() .then(() => { console.log('Connection has been established successfully.'); }) .catch(err => { console.error('Unable to connect to the database:', err); }); db.sequelize = sequelize; db.Sequelize = Sequelize; module.exports = db;
关联逻辑编写规范
关联逻辑没有强制要求编写位置,但是上述官方推荐的写法可以完全规避循环依赖问题:所有模型先完成定义存入db对象,再统一执行关联逻辑,不需要手动在顶层导入模型编写关联。
内容的提问来源于stack exchange,提问作者Amon
相关产品推荐
相关产品推荐

