已注册并同步Sequelize Models,如何执行CRUD操作?
问题:Sequelize调用模型自定义方法报错「Quote.addQuote is not a function」
背景
通过Udemy课程入门Sequelize,因仅使用ES模块做了部分调整,已完成Models的注册与同步并生成数据库表,但调用模型自定义方法时出现错误。本人主要开发PHP,JS仅局限于客户端使用。
代码细节
模型注册代码
import Quote from './quote.js'; import Variant from './variant.js'; import Version from './version.js'; import Log from './log.js'; let imports = [Variant, Version, Log, Quote]; let models = {}; export function registerModels(sequelize) { imports.forEach((item) => { models[item.constructor.name] = item(sequelize); } ) sequelize.models = models; } export default models;
模型示例(以Log模型为例)
import { Model, DataTypes } from 'sequelize'; export default (sequelize) => { class Log extends Model { static associate(models) { Log.Quote_id = Quote.hasOne(models.Version); } static async newEntry() { return sequelize.transaction(async() => { // 创建新quote的逻辑 await Log.create({queueMicrotaskuote_id, user, action}); }) } } Log.init({ id:{ type: DataTypes.INTEGER, allowNull: false, primaryKey: true, autoIncrement: true }, quote_id: { type: DataTypes.INTEGER, allowNull: false }, user: { type: DataTypes.INTEGER, allowNull: false }, action: { type: DataTypes.TEXT, allowNull: false } }, { sequelize, modelName: 'Log' } ); return Log; }
模型同步代码
// 注册模型 registerModels(this.connection); // 同步模型 await this.sync();
问题场景代码(调用自定义方法)
import { Router } from 'express'; import Quote from '../models/quote.js'; import asyncWrapper from '../utils/asyncWrapper.js'; const router = Router(); router.get('/', asyncWrapper(async (req, res) => { await Quote.addQuote(); return res.status(200).send({success: true}) })) export { router };
错误信息:Quote.addQuote is not a function
原课程示例代码
import { Router } from 'express'; import models from '../../models'; import asyncWrapper from '../../utils/asyncWrapper'; import JWTUtils from '../../utils/jwt-utils'; const router = Router(); const { User } = models; router.post( '/register', asyncWrapper(async (req, res) => { const { email } = req.body; const user = await User.findOne({ where: { email } }); if (user) { return res .status(200) .send({ success: false, message: 'User already exists' }); } const payload = { email }; const accessToken = JWTUtils.generateAccessToken(payload); const refreshToken = JWTUtils.generateRefreshToken(payload); await User.createNewUser({ ...req.body, refreshToken }); return res.status(200).send({ success: true, message: 'User successfully registered', data: { accessToken, refreshToken, }, }); }) ); export default router;
原因分析与解决办法
核心问题:你直接导入的
Quote是一个工厂函数(返回Model类的函数),不是已经初始化好的Sequelize模型类,所以它没有addQuote这个静态方法。错误点拆解:
- 模型文件导出的是接收
sequelize实例的函数,只有调用这个函数并传入sequelize实例后,才会返回带有静态方法的Model类。 - 路由里直接导入工厂函数,调用
Quote.addQuote()相当于在函数上找方法,自然不存在。
- 模型文件导出的是接收
解决步骤:
- 不要直接从模型文件导入,而是从注册后的
models对象中获取初始化好的模型:import { Router } from 'express'; import models from '../models/index.js'; // 导入注册后的models对象 import asyncWrapper from '../utils/asyncWrapper.js'; const router = Router(); const { Quote } = models; // 从models中拿初始化好的模型 router.get('/', asyncWrapper(async (req, res) => { await Quote.addQuote(); return res.status(200).send({success: true}) })) export { router }; - 修复模型注册代码的键名错误:
item.constructor.name会导致模型键名异常(比如工厂函数的constructor是Function,name为"Function"),应该用模型内部定义的modelName:imports.forEach((item) => { const model = item(sequelize); models[model.modelName] = model; // 用模型的modelName作为键名 }) - 确保
registerModels在路由加载前执行,保证models对象已经填充了初始化好的模型实例。
- 不要直接从模型文件导入,而是从注册后的
额外说明:原课程代码直接从
models导入,因为课程里的模型是直接导出初始化好的类;而你改成了ES模块的工厂函数模式,所以必须从注册后的models对象获取实例化后的模型。
内容的提问来源于stack exchange,提问作者Daniel Hüpenbecker
相关产品推荐
相关产品推荐

