Sequelize多对多关联报错:TypeError: Members.belongsToMany不是函数
问题:Sequelize多对多关联报错
TypeError: Members.belongsToMany is not a function MySQL数据库存在members和events两张表,二者为多对多关系,尝试通过包含member_id、event_id及event_date的中间表member_events使用Sequelize建模,启动Node.js服务器时出现如下错误:
Members.belongsToMany(models.Events, { through: 'member_events' }) ^ TypeError: Members.belongsToMany is not a function
涉及的三个模型代码如下:
memberEvents.js
module.exports = (sequelize, DataTypes) => { const Members = require('../models/members') const Events = require('../models/events') const MemberEvents = sequelize.define( "MemberEvents", { member_id: { type: DataTypes.INTEGER, allowNull: false, primaryKey: true, }, event_id: { type: DataTypes.INTEGER, allowNull: false, primaryKey: true, }, event_date: { type: DataTypes.DATEONLY, allowNull: false, primaryKey: true, }, }, { tableName: "member_events" } ); Members.belongsToMany(Events, { through: 'member_events' }) Events.belongsToMany(Members, { through: 'member_events' }) return MemberEvents; };
Members.js
module.exports = (sequelize, DataTypes) => { //Below creates the member table in the schema const Members = sequelize.define( "Members", { member_id: { type: DataTypes.INTEGER, autoIncrement: true, allowNull: false, primaryKey: true, }, forename: { type: DataTypes.STRING(35), allowNull: false, }, surname: { type: DataTypes.STRING(35), allowNull: false, }, date_of_birth: { type: DataTypes.DATEONLY, allowNull: false, }, address_1: { type: DataTypes.STRING(35), allowNull: false, }, address_2: { type: DataTypes.STRING(35), }, address_3: { type: DataTypes.STRING(35), }, address_4: { type: DataTypes.STRING(35), }, address_5: { type: DataTypes.STRING(35), }, postcode: { type: DataTypes.STRING(12), allowNull: false, }, directions: { type: DataTypes.TEXT("long"), }, mobile_phone: { type: DataTypes.STRING(12), }, email_address: { type: DataTypes.STRING(255), }, key_safe_code: { type: DataTypes.STRING(8), }, next_of_kin_name: { type: DataTypes.STRING(70), }, next_of_kin_phone: { type: DataTypes.STRING(12), }, next_of_kin_local: { type: DataTypes.STRING(33), }, next_of_kin_relationship: { type: DataTypes.STRING(40), }, doctor_name: { type: DataTypes.STRING(35), }, initial_medical_conditions: { type: DataTypes.TEXT("long"), }, deceased: { type: DataTypes.DATEONLY, }, normally_escorted: { type: DataTypes.STRING(3), }, blue_badge_holder: { type: DataTypes.STRING(3), }, medical_equipment: { type: DataTypes.STRING, }, }, { tableName: "Member" } ); return Members; };
Events.js
module.exports = (sequelize, DataTypes) => { //Below creates the event table in the schema const Events = sequelize.define( "Events", { event_id: { type: DataTypes.INTEGER, autoIncrement: true, allowNull: false, primaryKey: true, }, event_name: { type: DataTypes.STRING(70), allowNull: false, }, staff_id: { type: DataTypes.INTEGER, allowNull: false, }, }, { tableName: "Events" } ); return Events; };
原因分析
- 模型未正确实例化:直接通过
require导入模型文件得到的是模型的定义函数,不是经过Sequelize实例化后的模型对象,这类函数没有belongsToMany等关联方法。 - 关联定义位置错误:在中间表模型内部直接引入并定义关联,会导致循环依赖或模型未完成实例化的问题,触发方法不存在的错误。
解决方法
步骤1:修改中间表模型,移除关联定义
将memberEvents.js中的require语句和关联代码删除,只保留中间表的模型定义:
module.exports = (sequelize, DataTypes) => { const MemberEvents = sequelize.define( "MemberEvents", { member_id: { type: DataTypes.INTEGER, allowNull: false, primaryKey: true, }, event_id: { type: DataTypes.INTEGER, allowNull: false, primaryKey: true, }, event_date: { type: DataTypes.DATEONLY, allowNull: false, primaryKey: true, }, }, { tableName: "member_events" } ); return MemberEvents; };
步骤2:统一在外部定义关联
创建一个专门的关联初始化文件(如associations.js),在所有模型都被Sequelize加载完成后,通过Sequelize的models对象访问实例化后的模型来定义关联:
// 接收已加载所有模型的models对象 module.exports = (models) => { const { Members, Events, MemberEvents } = models; // 定义多对多关联,明确指定中间表模型及外键 Members.belongsToMany(Events, { through: MemberEvents, foreignKey: 'member_id', otherKey: 'event_id' }); Events.belongsToMany(Members, { through: MemberEvents, foreignKey: 'event_id', otherKey: 'member_id' }); };
步骤3:在初始化流程中调用关联设置
在你的数据库初始化文件或服务器入口文件中,先加载所有模型,再调用关联初始化函数:
const sequelize = require('./path-to-your-sequelize-instance'); // 假设models目录下的index.js已导出所有实例化后的模型 const models = require('./models'); // 初始化模型关联 require('./associations')(models); // 后续启动服务器或执行数据库同步操作
注意事项
- 确保所有模型都通过Sequelize实例正确加载,
models对象中的每个模型都是经过sequelize.define实例化后的对象,才会拥有关联方法。 - 关联中指定的
foreignKey和otherKey要与中间表的字段名完全对应,避免Sequelize自动生成错误的字段。 - 不要在单个模型文件内部直接导入其他模型定义关联,避免循环依赖和实例化不完整的问题。
内容的提问来源于stack exchange,提问作者Jess
相关产品推荐
相关产品推荐

