Sequelize 踩坑指南(持续更新中...)

2,086 阅读2分钟

1.TypeError: Class constructor Model cannot be invoked without 'new'

  • 故事背景:sequelize + typescript + ES2015
  • 原因分析:不支持 ES2015 语法
  • 解决方案:Typescript => ES6 => ES5

tsconfig.json

将 compilerOptions 配置中的 target 变更成 es6

babel.config.json

在项目根目录下下 babel.config.json 配置文件中添加预设 @babel/preset-env

package.json

  • 在 devDependencies 中添加 @babel/node 和 @babel/preset-env
  • 使用 babel-node 启动项目 tsc && babel-node build/index.js

2.Cannot read properties of undefined (reading 'length')

  • 错误定位在 sequelize/lib/model.js 的 141 行 primaryKeyAttributes 不存在。
      if (this.constructor.primaryKeyAttributes.length) {
        this.constructor.primaryKeyAttributes.forEach(primaryKeyAttribute => {
          if (!Object.prototype.hasOwnProperty.call(defaults, primaryKeyAttribute)) {
            defaults[primaryKeyAttribute] = null;
          }
        });
      }
  • 错误原因:没有调用 sequelize 初始化方法。泪崩。
const sequelize = new Sequelize(config.database, config.username, config.password, {
  host: config.host,
  dialect: config.dialect,
});

3. Role is associated to User using an alias. You've included an alias (roles), but it does not match the alias(es) defined in your association (Roles).

  • 需求背景:user 和 role 是多对多的关系。获取用户信息的时候连带将用户所有的角色信息都拿到。
  • 原因分析:在获取 user 信息的时候使用了别名 roles。但是在定义的时候没有定义别名 roles。
    await User.findAll({
      include: [
        {
          model: Role,
          as: "roles",
        },
      ],
    });
  • 解决方案:
User.belongsToMany(Role, {
  through: UserRole,
  as: 'roles'
});

4. 一对一关系关联新增失败

user 和 auth 之间是一对一的关系

UserModel.belongsTo(AuthModel);
AuthModel.hasOne(UserModel);

当新增 auth 的时候调用 setUser 方法报错。

  const auth = await Auth.create({
    username: username,
    password: password,
  });
  await auth.setUser({
    user_name: username
  });

错误原因:setUser 接受的参数应该是一个 Model 类型的对象。

解决方案:创建一个 Model 类型的 user,然后调用 setUser 方法。

  await auth.setUser(
    User.create({
      user_name: username,
    })
  );

5. SequelizeEagerLoadingError

user 和 role 之间是多对多的关系

RoleModel.belongsToMany(UserModel, {
  through: "UserRole",
});
UserModel.belongsToMany(RoleModel, {
  through: "UserRole",
});

获取 user 时期望预加载 role 的信息

  await User.findOne({
    where: {
      user_id: id,
    },
    include: [
      {
        model: Role,
        as: "roles",
      },
    ],
  });

发现报错 SequelizeEagerLoadingError 报错原因是无法识别 roles 别名。使用别名的前提是定义别名,使用别名的前提是定义别名,使用别名的前提是定义别名。可是在user 和 role 的关联定义中并没有发现有别名的定义。 解决方案:

RoleModel.belongsToMany(UserModel, {
  through: "UserRole",
  as: "users",
});
UserModel.belongsToMany(RoleModel, {
  through: "UserRole",
  as: "roles",
});

6. 数据库连接成功但是没有创建表

const sequelize = new Sequelize(database, username, password, {
  dialect: "mysql",
  host: "localhost",
  port: 3306,
  define: {
    freezeTableName: true,
  },
  sync: {
    force: true
  }
});
...

原因是:在创建 sequelize 实例时已经设置了 sync: { force: true } 此时,将表同步到数据库中,此时没有表,因此是空的。应该先建立数据表,然后调用同步方法。

const sequelize = new Sequelize(database, username, password, {
  dialect: "mysql",
  host: "localhost",
  port: 3306,
  define: {
    freezeTableName: true,
  },
});
...
定义 schema 的逻辑 
...
  try {
    await sequelize.authenticate();
    // await sequelize.sync({ force: true });
    console.log("Connection has been established successfully.");
  } catch (error) {
    console.error("Unable to connect to the database:", error);
  }

7. createError (createError.js:17:15)

很明显,创建时报错。怎么就报错了呢,没问题啊。

router.get("/user", async function (req, res) {
  try {
    const res = await User.findAll();
    res.status(200).send(res);
  } catch (err) {
    res.status(500).send(err);
  }
});

仔细一看发现,send(res)有问题。查询的结果被赋值给变量 res。可是 res 可是 response 啊。重写了 res,使用重写后的 res 返回请求。正确的做法:

router.get("/user", async function (req, res) {
  try {
    const data = await User.findAll();
    res.status(200).send(data);
  } catch (err) {
    res.status(500).send(err);
  }
});