Sequelize 6.28中hasMany/hasOne关联报错,求MVC架构下优化方案
问题
在MVC项目中使用Sequelize(v6.28,PostgreSQL数据库)时,每次调用hasOne或hasMany方法都会抛出错误:perfis.hasMany called with something that's not a subclass of Sequelize.Model。
有人建议将所有模型放在单个文件中,或者创建associations.js专门处理关联,这种方法可行,但并非最优解,希望找到更好的替代方案。
现有代码
Perfil.js
const { Sequelize, DataTypes } = require('sequelize') const db = require('../../db/conn') // MODELS const User = require('./Usuario') const Perfil = db.define('perfis', { id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, allowNull: false }, nome: DataTypes.STRING(90), descricao: DataTypes.TEXT('long') }, { schema: "acesso", underscored: true }) Perfil.hasMany(User) module.exports = Perfil
Usuarios.js
const { Sequelize, DataTypes } = require('sequelize') const db = require('../../db/conn') // MODELS const Perfil = require('./Perfil') const Usuario = db.define('usuarios', { id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true, allowNull: false }, nome: { type: DataTypes.STRING(255), allowNull: false }, nome_exibicao: DataTypes.STRING(50), sexo: DataTypes.STRING(45), email: { type: DataTypes.STRING(60), allowNull: false }, password: { type: DataTypes.STRING(60), allowNull: false }, status: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 1 } }, { schema: "acesso", underscored: true }); Usuario.belongsTo(Perfil) module.exports = Usuario
解决方案
这个错误是循环依赖导致的:Perfil模型加载时引入了Usuario,而Usuario加载时又引入了Perfil,此时其中一个模型还没完成定义,传递给关联方法的不是完整的Sequelize.Model子类。
以下是两种更优的处理方式:
方式1:统一初始化关联
修改模型文件先导出模型,再在一个单独的入口文件中统一定义关联,确保所有模型加载完成后再创建关联:
调整后的Perfil.js
const { Sequelize, DataTypes } = require('sequelize') const db = require('../../db/conn') const Perfil = db.define('perfis', { id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, allowNull: false }, nome: DataTypes.STRING(90), descricao: DataTypes.TEXT('long') }, { schema: "acesso", underscored: true }) module.exports = Perfil
调整后的Usuarios.js
const { Sequelize, DataTypes } = require('sequelize') const db = require('../../db/conn') const Usuario = db.define('usuarios', { id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true, allowNull: false }, nome: { type: DataTypes.STRING(255), allowNull: false }, nome_exibicao: DataTypes.STRING(50), sexo: DataTypes.STRING(45), email: { type: DataTypes.STRING(60), allowNull: false }, password: { type: DataTypes.STRING(60), allowNull: false }, status: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 1 } }, { schema: "acesso", underscored: true }); module.exports = Usuario
创建模型入口文件(models/index.js)
const db = require('../db/conn') const Perfil = require('./Perfil') const Usuario = require('./Usuario') // 统一定义关联 Perfil.hasMany(Usuario) Usuario.belongsTo(Perfil) module.exports = { db, Perfil, Usuario }
之后项目中所有使用模型的地方,都从这个index.js导入即可。
方式2:利用钩子延迟关联定义
在模型中使用Sequelize的afterDefine钩子,等待模型完全定义完成后再加载关联模型并创建关联,避免循环依赖:
修改Perfil.js
const { Sequelize, DataTypes } = require('sequelize') const db = require('../../db/conn') const Perfil = db.define('perfis', { id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, allowNull: false }, nome: DataTypes.STRING(90), descricao: DataTypes.TEXT('long') }, { schema: "acesso", underscored: true }) // 模型定义完成后再加载关联 Perfil.afterDefine(() => { const Usuario = require('./Usuario') Perfil.hasMany(Usuario) }) module.exports = Perfil
修改Usuarios.js
const { Sequelize, DataTypes } = require('sequelize') const db = require('../../db/conn') const Usuario = db.define('usuarios', { id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true, allowNull: false }, nome: { type: DataTypes.STRING(255), allowNull: false }, nome_exibicao: DataTypes.STRING(50), sexo: DataTypes.STRING(45), email: { type: DataTypes.STRING(60), allowNull: false }, password: { type: DataTypes.STRING(60), allowNull: false }, status: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 1 } }, { schema: "acesso", underscored: true }); // 模型定义完成后再加载关联 Usuario.afterDefine(() => { const Perfil = require('./Perfil') Usuario.belongsTo(Perfil) }) module.exports = Usuario
这种方式不需要额外的入口文件,保持模型文件的独立性,同时解决循环依赖问题。
内容的提问来源于stack exchange,提问作者Luís
相关产品推荐
相关产品推荐

