Sequelize调用findOne时抛出TypeError: Cannot read properties of undefined (reading 'constructor')错误求助
Sequelize调用findOne时抛出TypeError: Cannot read properties of undefined (reading 'constructor')错误求助
大家好,我最近在使用Sequelize开发时碰到了一个奇怪的问题,在执行User.findOne()时总是抛出错误,其他服务里完全相同的调用逻辑却能正常运行,实在摸不着头脑,想请各位帮忙排查一下问题所在。
错误详情
TypeError: Cannot read properties of undefined (reading 'constructor') at Function.findOne (/.../node_modules/sequelize/src/model.js:1977:61) at /.../src/api/controllers/execution.ts:22:31
相关代码
执行控制器(execution.ts)
let user = await User.findOne({ where: { id: req.body.externalCustomerId } }); if (!user) { throw new NotFoundError('No such user found'); }
User模型(单独数据库项目中的代码)
import argon2 from 'argon2'; import { Sequelize, Model, DataTypes, Op, QueryTypes } from 'sequelize'; export enum Role { admin = 'Admin', user = 'User', business = 'Business' } const validateEmailRegExp = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; export function validateEmailFormat(candidateEmail: string): boolean { return validateEmailRegExp.test(candidateEmail); } export function checkPasswordRequirements(candidatePassword: string): boolean { let valid = true; if (candidatePassword.length < 8) { valid = false; } // 检查密码是否包含数字 if (/\d/.test(candidatePassword) !== true) { valid = false; } // 检查密码是否包含小写字母 if (/[a-z]/.test(candidatePassword) !== true) { valid = false; } // 检查密码是否包含大写字母 if (/[A-Z]/.test(candidatePassword) !== true) { valid = false; } return valid; } class User extends Model { declare id: number; declare role: string; declare firstName: string; declare lastName: string; declare email: string; declare passcode: string; declare birthdate: string; declare country: string; declare phone: string; declare createdAt: string; declare active: boolean; static async initModel(sequelize: Sequelize) { console.log('Syncing user model...'); this.init({ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, role: { type: DataTypes.ENUM(...Object.values(Role)), allowNull: false, defaultValue: Role.user, validate: { isIn: [ Object.values(Role) ] } }, firstName: { type: DataTypes.STRING, allowNull: false }, lastName: { type: DataTypes.STRING, allowNull: false }, email: { type: DataTypes.STRING, allowNull: false, unique: true, validate: { isEmail: true } }, passcode: { type: DataTypes.STRING, allowNull: false }, birthdate: { type: DataTypes.STRING, allowNull: false }, country: { type: DataTypes.STRING, allowNull: false }, phone: { type: DataTypes.STRING, allowNull: false }, active: { type: DataTypes.BOOLEAN, allowNull: false } }, { sequelize, indexes: [{ unique: true, fields: ['email'] }], }); User.beforeCreate(async (user, options) => { // 保存前统一将邮箱转为小写 user.email = user.email.toLowerCase(); const hashedPassword = await argon2.hash(user.passcode as string); user.passcode = hashedPassword; }); User.beforeUpdate(async (user, options) => { // 如果密码被修改则重新哈希 if (user.changed('passcode')) { const hashedPassword = await argon2.hash(user.passcode as string); user.passcode = hashedPassword; } }); } } export default User;
数据库连接代码
import { Sequelize } from 'sequelize'; import User from '../models/user'; export let sequelize: Sequelize | null = null; export async function connectToDb( dbName: string, dbUser: string, dbPass: string, dbOptions: any ): Promise<Sequelize | null> { try { if (sequelize !== null) { // 返回已存在的连接实例 return sequelize; } console.log(`Connecting to database ${dbName} on host ${dbOptions.host}`); sequelize = new Sequelize(dbName, dbUser, dbPass, dbOptions); try { await sequelize.authenticate(); console.log(`Successfully connected to databse, syncing models...`); await initDbModels(sequelize); console.log('All DB models initialised.'); } catch (error) { console.error(`Error connecting to database ${dbName}`); console.error(error); } return sequelize; } catch (err) { console.error(`Could not connect to database ${dbName}`); console.error(err); return null; } } export async function initDbModels(sequelize: Sequelize) { await User.initModel(sequelize); // ... 其他模型初始化代码 await sequelize.sync(); }
app.ts代码
import cors from 'cors'; import path from 'path'; import dotenv from 'dotenv'; import express from 'express'; import router from './routes/router'; import { morgan } from "./middleware/morgan"; import { connectToDb } from '../modules/commons/tools/db-helper'; import { apiErrorHandler } from '../modules/commons/error-handling/error-handler'; import { dbName, dbUser, dbPass, dbOptions } from '../modules/commons/database/database'; require('ts-node/register'); dotenv.config({ path: `.env.${process.env.NODE_ENV}` }); var corsOptions: cors.CorsOptions = { origin: function (origin, callback) { callback(null, true) } } if (process.env.NODE_ENV !== 'production') { corsOptions.origin = '*'; } var app = express(); const originalSend = app.response.send; app.response.send = function sendOverride(body) { this.responseBody = body; return originalSend.call(this, body); }; connectToDb(dbName, dbUser, dbPass, dbOptions); app.use(cors(corsOptions)); app.use(morgan(':remote-addr [:date[clf]] ":method :url HTTP/:http-version" Input :input Response :status :response-body')); app.use(express.json({ limit: '10mb' })); app.use(express.urlencoded({ limit: '10mb', extended: false })); app.use(express.static(path.join(__dirname, 'public'))); app.use(router); app.use(apiErrorHandler); app.set('trust proxy', true); export default app;
我已经对比过其他正常运行的服务,调用逻辑完全一致,目前猜测会不会是模型初始化或者数据库连接的时机问题?比如在模型还没完成初始化的时候就调用了findOne?但我在app.ts里是先调用connectToDb再挂载路由的,理论上应该不会出现这个情况吧?
希望各位能帮我找出问题所在,谢谢!
备注:内容来源于stack exchange,提问作者VitoCK
相关产品推荐
相关产品推荐

