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

2024-04-15

我正在尝试使用 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类型 - 但我不知道它为什么会出现以及我们如何解决它。

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

执行(默认):插入menteequestions (menteeId,questionId,createdAt,updatedAt) 值 (2,1,'2017-03-17 06:18:01','2017-03-17 06:18:01');

错误:受训者与受训者问题没有关联!

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

如果存在则删除表mentees;

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

这些怎么解决呢?

同样,我只需要一个多对多增删改查操作的最小示例(在本例中只需插入和读取),但这似乎超出了我的理解。为此苦苦挣扎了两天。


迁移

我建议你使用sequelize迁移 http://docs.sequelizejs.com/en/v3/docs/migrations/相反做sync()在每个模型上。有一个模块 -续集.cli https://github.com/sequelize/cli这使您可以轻松管理迁移和种子。它以某种方式通过创建初始化文件来强制项目结构index.js inside /models项目的目录。它假设您的所有模型定义都位于此目录中。该脚本迭代所有模型文件(每个模型定义位于单独的文件中,例如mentee.js, question.js)并执行sequelize.import()为了将这些模型分配给sequelize实例 - 这可以让您稍后通过以下方式访问它们sequelize[modelName] e.g. sequelize.question.

Note:创建迁移文件时请记住时间戳字段 -createdAt, updatedAt并且,最终,deletedAt.

Sync

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

  1. perform sequelize.sync({ force: true })为了同步所有模型
  2. 运行一些数据库seeds(也可以通过sequelize-cli),
  3. 运行测试。

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

多对多

现在让我们继续讨论您的问题 - 两个模型之间的 m:n 关系。首先,由于你执行的事实Promise.all(), the sync可以按照与在其中添加函数不同的顺序运行。为了避免这种情况,我建议您使用mapSeries的特征BluebirdPromise,Sequelize 在下面使用和公开sequelize.Promise(这也是您上次删除父行时出错的原因 - 您尝试删除mentees这是引用自menteequestion).

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(),就像示例中一样。现在是时候修复了错误:受训者与受训者问题没有关联!错误。发生这种情况是因为您关联了Mentee with Question但之间没有关联MenteeQuestion and Mentee (or Question)。为了解决这个问题,之后belongsToMany, 你可以加

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

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

menteeQuestions.forEach(menteeQuestion => {
    console.log(menteeQuestion.toJSON());
});
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐