Node.js / Sequelize.js / Express.js - 如何插入多对多关联? (同步/异步?)

Posted

技术标签:

【中文标题】Node.js / Sequelize.js / Express.js - 如何插入多对多关联? (同步/异步?)【英文标题】:Node.js / Sequelize.js / Express.js - How to insert into many-to-many association? (sync/async?) 【发布时间】:2015-05-09 08:58:05 【问题描述】:

我有两个模型(个人、电子邮件)并尝试使用 Sequelize 命令插入到创建的“个人电子邮件”表中。当 Sequelize 正在创建所需的表时,它在尝试向该表添加/获取/设置/从该表中返回以下错误:“对象 [object Promise] 没有方法 'addEmail'”。我错过了什么?

Sequelize 文档说,如果模型是 User 和 Project,“这会将方法 getUsers、setUsers、addUsers 添加到 Project,并将 getProjects、setProjects 和 addProject 添加到 User。”

这让我相信(查看 Promise)我可能误解了如何使用 Node.js 的异步特性。我尝试了同步和异步版本的插入,都返回了上面相同的消息。

续集文档:http://docs.sequelizejs.com/en/latest/docs/associations/

代码:

routes/index.js

var express = require('express');
var router = express.Router();
var models  = require('../models');

/* GET home page. */
router.get('/', function(req, res, next) 
    'use strict';

    var tIndividual, tEmail;
    tIndividual = models.Individual.create(
        name: "Test"
    );
    tEmail = models.Email.create(
        address: "test@gmail.com"
    );
    console.log(tEmail);

    res.render('index',  title: 'Express' );
);

module.exports = router;

/* GET home page. */
router.get('/', function(req, res, next) 
    'use strict';

    var tIndividual, tEmail;    
    tIndividual = models.Individual.create(
        name: "Test"
    ).then(function()
        tEmail = models.Email.create(
            address: "test@gmail.com"
        ).then(function()
            tIndividual.addEmail(tEmail).then(function()
                console.log("Success");
            );
        )
    );

    res.render('index',  title: 'Express' );
);

module.exports = router;

models/index.js

db.Individual.hasMany(db.Email, 
    as: 'Email',
    through: 'Individual_Email'
);
db.Email.hasMany(db.Individual, 
    as: 'Individual',
    through: 'Individual_Email'
);

如何以最佳方式添加到“Individual_Email”表中?我假设我需要同步执行以等待更新,但我愿意接受任何建议。谢谢!

【问题讨论】:

【参考方案1】:

我想出了如何以一种方式解决它,但如果有更好的方法,请告诉我。

我的解决方案: 由于 .create() 返回了一个承诺,我改为使用 .build() 返回一个实例,并且仅在两者同步保存后才添加到“Individual_Email”。然后我在从 .build() 返回的实例上调用 add 方法并插入到表中。

我的代码:

var tIndividual, tEmail;
tIndividual = models.Individual.build(
    name: "Test"
);
tEmail = models.Email.build(
    address: 'test@gmail.com'
);
tIndividual.save()
    .success(function()
        tEmail.save()
        .success(function()
            tIndividual.addEmail(tEmail);
        );
);

【讨论】:

最好将thens链接起来,而不是无缘无故地嵌套它们。 嘿,您可以在构建对象时添加电子邮件,然后再实际创建它吗?我问的原因是我想确保整个插入是否成功,否则甚至不用费心在任何表中创建任何东西【参考方案2】:

当您调用 .save().create() 或其他返回 Promise 的方法时,您应该在该 Promise 上调用 .then()。当它解析时——也就是说,当对象被保存/创建/其他东西时——你的then函数将被调用,并将接收保存/创建的对象作为参数。

所以你的第一次尝试可以重写为:

models.Individual.create(
  name: "Test"
).then(function(createdIndividual)  // note the argument
  models.Email.create(
    address: "test@gmail.com"
  ).then(function(createdEmail)  // note the argument
    createdIndividual.addEmail(createdEmail)
      .then(function(addedEmail)  // note th-- well you get the idea :)
        console.log("Success");
      );
  )
);

上面的代码缺少一些重要的东西,例如returning 用于更好的链接和错误处理的承诺,但这是一个开始。我建议Bluebird's documentation 解决这个问题(这是 Sequelize 使用的 Promise 库,但还有其他几个)

【讨论】:

您可以在创建电子邮件时一次性添加吗?而不是先创建然后添加电子邮件? @MortezaShahriariNia 请注意,此关联是 N:M,因为个人和电子邮件都已配置为 hasMany。所以最后有三个表(Emails、Individuals 和 EmailIndividual)。上面的代码在实践中会生成三个 INSERT 语句,你不能得到更少的,因为要填充三个表。 @MortezaShahriariNia 就是说,我曾经遇到过类似的情况,我在这个问题中解决了:***.com/questions/28751483/…【参考方案3】:

您可以使用最佳方式的承诺来缓解“Pyramid of Doom”:

var createdIndividual;
models.Individual.create(
  name: "Test"
).then(function(createdIn)  // note the argument
  createdIndividual = createdIn;
  return models.Email.create(
    address: "test@gmail.com"
  );
).then(function(createdEmail)  // note the argument
  return createdIndividual.addEmail(createdEmail);
).then(function(addedEmail)  // note th-- well you get the idea :)
  console.log("Success");
);

【讨论】:

以上是关于Node.js / Sequelize.js / Express.js - 如何插入多对多关联? (同步/异步?)的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Node.JS 中向 sequelize.js 添加自定义函数?

使用 Node JS + Sequelize JS 时出错

获取由 sequelize.js 生成的原始查询 [重复]

sequelize.js - 你需要手动安装 mysql 包

sequelize.js TIMESTAMP 不是 DATETIME

使用 PostgreSQL 进行一对多设计的 Sequelize.js 最佳实践 [关闭]