使用 Sequelize 的多对多关系的简单示例

本教程将介绍使用 Sequelize 的多对多关系的简单示例的处理方法,这篇教程是从别的地方看到的,然后加了一些国外程序员的疑问与解答,希望能对你有所帮助,好了,下面开始学习吧。

使用 Sequelize 的多对多关系的简单示例 教程 第1张

问题描述

我正在尝试使用 Sequelize 构建表之间多对多关系的简单示例.但是,这似乎比我预期的要棘手.

这是我目前拥有的代码(./db.js 文件导出 Sequelize 连接实例).

const Sequelize = require("sequelize");
const sequelize = require("./db");

var Mentee = sequelize.define('mentee', {
 id: {
  type: Sequelize.INTEGER,
  primaryKey: true,
  autoIncrement: true
 },
 name: {
  type: Sequelize.STRING
 }
});

var Question = sequelize.define('question', {
 id: {
  type: Sequelize.INTEGER,
  primaryKey: true,
  autoIncrement: true
 },
 text: {
  type: Sequelize.STRING
 }
});

var MenteeQuestion = sequelize.define('menteequestion', {
// answer: {
//  type: Sequelize.STRING
// }
});

// A mentee can answer several questions
Mentee.belongsToMany(Question, { as: "Questions", through: MenteeQuestion });

// And a question can be answered by several mentees
Question.belongsToMany(Mentee, { as: "Mentees", through: MenteeQuestion });

let currentQuestion = null;
Promise.all([
 Mentee.sync({ force: true })
  , Question.sync({ force: true })
  , MenteeQuestion.sync({ force: true })
]).then(() => {
 return Mentee.destroy({where: {}})
}).then(() => {
 return Question.destroy({ where: {} })
}).then(() => {
 return Question.create({
  text: "What is 42?"
 });
}).then(question => {
 currentQuestion = question;
 return Mentee.create({
  name: "Johnny"
 })
}).then(mentee => {
 console.log("Adding question");
 return mentee.addQuestion(currentQuestion);
}).then(() => {
 return MenteeQuestion.findAll({
  where: {}
, include: [Mentee]
 })
}).then(menteeQuestions => {
 return MenteeQuestion.findAll({
  where: {
menteeId: 1
  }
, include: [Mentee]
 })
}).then(menteeQuestion => {
 console.log(menteeQuestion.toJSON());
}).catch(e => {
 console.error(e);
});

运行时我得到:

不能添加外键约束

我认为这是因为 id 类型——但我不知道它出现的原因以及我们怎么修复它.

前一个错误不会出现时出现的另一个错误是:

执行(默认):

错误:被指导者与被指导者问题没有关联!

另外,我得到的另一个错误——我认为这是因为 sync 中的 force:true——是:

ER_ROW_IS_REFERENCED:无法删除或更新父行:外键约束失败

怎么解决这些问题?

再次,我只需要一个多对多 crud 操作的最小示例(在这种情况下只是插入和读取),但这似乎超出了我的理解.为此苦苦挣扎了两天.

推荐答案

迁移

我建议你使用 sequelize migrations 而不是 sync() 在每个模型上.有一个模块 - sequelize.cli 可让您轻松管理迁移和种子.它以某种方式通过在项目的 /models 目录中创建初始化文件 index.js 来强制项目结构.它假定您的所有模型定义都将在此目录中.此脚本遍历所有模型文件(每个模型定义在单独的文件中,例如 mentee.jsquestion.js)并执行 sequelize.import() 以便将这些模型分配给 sequelize 实例 - 这允许您稍后通过 sequelize[modelName] 访问它们,例如sequelize.question.

注意: 创建迁移文件时请记住时间戳字段 - createdAtupdatedAt 以及最终的 deletedAt.

我个人仅在运行测试时使用 sync() - 这可能分三个步骤显示

    执行 sequelize.sync({ force: true }) 以同步所有模型

    运行一些数据库seeds(也可以通过sequelize-cli来完成),

    运行测试.

    perform sequelize.sync({ force: true }) in order to synchronize all models

    run some database seeds (also can be done via sequelize-cli),

    run tests.

这很舒服,因为允许您在运行测试之前清理数据库,并且为了区分开发和测试,测试可以使用不同的数据库,例如project_test,以便开发数据库保持完整.

现在让我们继续讨论您的问题 - 两个模型之间的 m:n 关系.首先,由于您执行 Promise.all()sync 的运行顺序可能与您在其中添加函数的顺序不同.为了避免这种情况,我建议你使用 Bluebird 承诺的 mapSeries 功能,Sequelize 在 sequelize.Promise 下使用和公开(这也是关于删除父行的最后一个错误的原因 - 您尝试删除从 menteequestion 引用的 mentees).

sequelize.Promise.mapSeries([
 Mentee.sync({ force: true })
  , Question.sync({ force: true })
  , MenteeQuestion.sync({ force: true })
], (model) => { return model.destroy({ where: {} }); }).then(() => {

});

mapSeries 的第一个参数是 promise 数组,但是第二个参数是一个函数,它使用每个先前定义的 promise 的结果运行.由于 Model.sync() 会产生模型本身,因此我们可以在每次迭代时执行 model.destroy().

之后,您可以通过create() 向数据库中插入一些数据,就像在示例中一样.现在是时候修复 错误.发生这种情况是因为您已将 MenteeQuestion 相关联,但 MenteeQuestionMentee(或 问题).为了解决这个问题,在 belongsToMany 之后,您可以添加

MenteeQuestion.belongsTo(Mentee, { foreignKey: 'menteeId' });
MenteeQuestion.belongsTo(Question, { foreignKey: 'questionId' });

现在您可以在查询 MenteeQuestion 时添加 include: [Mentee, Question].在执行 toJSON() 时,您还会遇到另一个错误,因为您执行的是返回实例数组的 findAll.你可以做 forEach()

menteeQuestions.forEach(menteeQuestion => {
 console.log(menteeQuestion.toJSON());
});

好了关于使用 Sequelize 的多对多关系的简单示例的教程就到这里就结束了,希望趣模板源码网找到的这篇技术文章能帮助到大家,更多技术教程可以在站内搜索。