node.js - 在sequelize 中创建行时如何引用关联而不假定外键列名称?

标签 node.js sequelize.js

我有以下代码:

#!/usr/bin/env node
'use strict';
var Sequelize = require('sequelize');
var sequelize = new Sequelize('sqlite:file.sqlite');

var User = sequelize.define('User', { email: Sequelize.STRING});
var Thing = sequelize.define('Thing', { name: Sequelize.STRING});
Thing.belongsTo(User);

sequelize.sync({force: true}).then(function () {
  return User.create({email: 'asdf@example.org'});
}).then(function (user) {
  return Thing.create({
    name: 'A thing',
    User: user
  }, {
    include: [User]
  });
}).then(function (thing) {
  return Thing.findOne({where: {id: thing.id}, include: [User]});
}).then(function (thing) {
  console.log(JSON.stringify(thing));
});

我得到以下输出:

ohnobinki@gibby ~/public_html/turbocase1 $ ./sqltest.js
Executing (default): INSERT INTO `Users` (`id`,`email`,`updatedAt`,`createdAt`) VALUES (NULL,'asdf@example.org','2015-12-03 06:11:36.904 +00:00','2015-12-03 06:11:36.904 +00:00');
Executing (default): INSERT INTO `Users` (`id`,`email`,`createdAt`,`updatedAt`) VALUES (1,'asdf@example.org','2015-12-03 06:11:36.904 +00:00','2015-12-03 06:11:37.022 +00:00');
Unhandled rejection SequelizeUniqueConstraintError: Validation error
    at Query.formatError (/home/ohnobinki/public_html/turbocase1/node_modules/sequelize/lib/dialects/sqlite/query.js:231:14)
    at Statement.<anonymous> (/home/ohnobinki/public_html/turbocase1/node_modules/sequelize/lib/dialects/sqlite/query.js:47:29)
    at Statement.replacement (/home/ohnobinki/public_html/turbocase1/node_modules/sqlite3/lib/trace.js:20:31)

似乎指定 {include: [User]}指示 Sequelize 创建一个新的 Useruser 的内容匹配的实例。那不是我的目标。事实上,我很难相信这种行为会有用——至少我没有用。我希望能够长寿User记录在数据库中并在任意时间创建新的 Thing指的是User 。在我展示的示例中,我等待 User被创建,但在实际代码中它可能是通过 User.findOne() 重新加载的.

我见过other questionsanswers说我必须显式指定隐式创建的 UserId我的专栏Thing.create()称呼。当 Sequelize 提供像 Thing.belongsTo(User) 这样的 API 时,我不应该必须意识到 Thing.UserId字段已创建。那么创建新的 Thing 的干净的 API 尊重方式是什么?它指的是特定的 User无需猜测 UserId 的名称字段?当我加载Thing时并指定{include: [User]} ,我通过 thing.User 访问加载的用户属性(property)。我认为我不应该知道或尝试访问 thing.UserId field 。在我的Thing.belongsTo(User)打电话,我从来没有指定 UserId ,我只是将其视为我不应该关心的实现细节。在创建 Thing 时,如何继续避免关心该实现细节? ?

Thing.create()调用有效,但对我来说看起来不对:

Thing.create({
  name: 'A thing',
  UserId: user.id
});

最佳答案

选项 1 - 存在数据库不一致的风险

Sequelize 动态生成用于在实例上设置关联的方法,例如thing.setUser(用户);。在您的用例中:

sequelize.sync({force: true})
.then(function () {
  return Promise.all([
    User.create({email: 'asdf@example.org'}),
    Thing.create({name: 'A thing'})  
  ]);
})
.spread(function(user, thing) {
  return thing.setUser(user);
})
.then(function(thing) {
  console.log(JSON.stringify(thing));
});

选项 2 - 不起作用/有问题

它没有记录,但从代码潜水我认为以下应该有效。事实并非如此,但这似乎是因为一些错误:

// ...
.then(function () {
  return models.User.create({email: 'asdf@example.org'});
})
.then(function(user) {
  // Fails with SequelizeUniqueConstraintError - the User instance inherits isNewRecord from the Thing instance, but it has already been saved
  return models.Thing.create({
    name: 'thingthing',
    User: user
  }, {
    include: [{
      model: models.User
    }],
    fields: ['name'] // seems nec to specify all non-included fields because of line 277 in instance.js - another bug?
  });
})

models.User.build 替换 models.User.create 不起作用,因为已构建但未保存的实例的主键为 null。 Instance#_setInclude 如果实例的主键为 null,则忽略该实例。

选项 3

将事物的create 包装在事务中可以防止不一致的状态。

sq.sync({ force: true })
.then(models.User.create.bind(models.User, { email: 'asdf@example.org' }))
.then(function(user) {
  return sq.transaction(function(tr) {
    return models.Thing.create({name: 'A thing'})
    .then(function(thing) { return thing.setUser(user); });
  });
})
.then(print_result.bind(null, 'Thing with User...'))
.catch(swallow_rejected_promise.bind(null, 'main promise chain'))
.finally(function() {
  return sq.close();
});

我上传了一个演示选项 2 和选项 3 的脚本 here

关于node.js - 在sequelize 中创建行时如何引用关联而不假定外键列名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34059081/

相关文章:

javascript - 将连接对象传递给模块更好还是在模块本身内进行连接更好?

javascript - 如何在 Angular 5 中解密,同时在express.js 中使用 crypto.js 加密数据

mysql - Sequelize 验证错误被忽略

postgresql - Sequelize Aggregate count 函数使用 where 子句返回错误值

postgresql - JS、expressJS、sequelize、postgres 等

node.js - NodeJs - Sequelize - 无法识别的属性数据类型

javascript - 需要帮助使该翻译函数能够处理数组输入

javascript - React Native x OneSignal 不显示通知

node.js - 如何将 IBM Cloud Functions 上的操作与数据库连接?

javascript - 使用 Sequelize 保存对象