You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.21 09:13:11