【问题标题】:Sequelize one to many assocation in multiple files在多个文件中序列化一对多关联
【发布时间】:2016-04-26 17:55:45
【问题描述】:

我正在处理与续集的一对多关联。大多数教程和文档都显示了在同一文件中定义两个模型时的示例。 我目前有两个文件,第一个 city.js:

const Promise = require('bluebird');
var Country = require('./country');

var City = sequelize.define("City", {
  id: {
    type: DataTypes.INTEGER,
    field: 'id',
    primaryKey: true,
    autoIncrement: true
  },...
}, {
  freezeTableName: true,
  timestamps: false
});

City.belongsTo(Country, {foreignKey : 'countryId', as: 'Country'});

Promise.promisifyAll(City);
module.exports = City;

还有第二个文件 country.js:

const Promise = require('bluebird');
var City = require('./city');

var Country = sequelize.define("Country", {
  id: {
    type: DataTypes.INTEGER,
    field: 'id',
    primaryKey: true,
    autoIncrement: true
  },
  ...
}, {
  freezeTableName: true,
  timestamps: false,
  paranoid: false
});

Country.hasMany(City, {foreignKey : 'countryId', as: 'Cities'});

Promise.promisifyAll(Country);
module.exports = Country;

当我导入两个模块并尝试实例化对象时:

var City = require('../model/external/city');
var CountryRepository = require('../repository/external/countryRepository');

CountryRepository.findById(1).then(function(country) {
    var city = City.build();
    city.name = 'Paris';
    city.setCountry(country);
    console.log('OK');
});

我收到以下错误:

抛出新错误(this.name + '.' + Utils.lowercaseFirst(Type.toString()) + ' 用某些东西调用 那不是 Sequelize.Model 的实例)

是模型在从模型中导出之前被承诺的问题还是我遗漏了什么?

【问题讨论】:

    标签: node.js sequelize.js bluebird


    【解决方案1】:

    我不确定您的代码到底有什么问题,需要运行它才能确定。

    但是当您在寻找示例时,请查看来自Sequelize Github 的示例。

    它在不同的文件中声明模型并将它们关联到index.js

    稍后您可以使用简单的model 属性引用您的其他模型model.Country

    City.belongsTo(model.Country, {foreignKey : 'countryId', as: 'Country'});
    

    例如,user.js

    【讨论】:

    • 谢谢,稍微修改一下 index.js 就得到了我想要的结果
    • 你能否详细说明一下,当我必须将代码与 user.js 完全相同但无法收到类似 { SequelizeEagerLoadingError: ticket is not associated to ticketComment!跨度>
    • 我遇到了同样的问题,并按照这个建议解决了这个问题(即在一个文件中定义所有关联)。但这真的是个好主意吗?要查看模型的信息,您必须查看模型声明和关联文件。我想知道模型声明和关联是否可以存储在一个文件中
    • 链接已失效。
    【解决方案2】:

    您必须在导出所有模型后声明关联

    我遇到了同样的问题!

    【讨论】:

      【解决方案3】:

      我创建了一种我认为非常棒的技术,甚至允许跨外键使用复合唯一键。

      我将举一个带有基本 user.js 模型类文件的示例

      models/user.js

      const { Model, DataTypes } = require('sequelize');
      module.exports = function(sequelize){
          class User extends Model {}
          return User.init({
            id: {
              type: DataTypes.INTEGER,
              primaryKey: true,
              autoIncrement: true
            },
            name: {
                type: DataTypes.STRING,
                allowNull: false
            },
            trading_system_key: {
                type: DataTypes.STRING,
                allowNull: false
            },
          }, {
            sequelize,
            modelName: 'User',
            indexes: [{ unique: true, fields: ['trading_system_key'] }]
          });
      };
      

      这显示了一个简单的用户类示例,还没有关联,但下一个文件将使用它。

      models/algorithm.js

      const { Model, DataTypes } = require('sequelize');
      const User = require('../models/user');
      
      module.exports = function(sequelize){
          class Algorithm extends Model {}
          UserModel = User(sequelize);//@JA - Gets a defined version of user class
      
          var AlgorithmFrame = Algorithm.init({
              id: {
                  type: DataTypes.INTEGER,
                  primaryKey: true,
                  autoIncrement: true
              },
              name: {
                  type: DataTypes.STRING,
                  allowNull: false,
              },
              user_Id: {
                  type: DataTypes.INTEGER,
                  references: { 
                      model: UserModel,
                      key: 'id',
                  },
              }
          }, {
            sequelize,
            modelName: 'Algorithm',
            indexes: [{ unique: true, fields: ['name','user_id'] }]
          });
      
          return AlgorithmFrame
      };
      

      这个例子展示了如何创建一个外键引用,而不必说belongsTo或HasOne等...当你需要创建复合键时,这会派上用场。

      例如,注意我把indexes: [{ unique: true, fields: ['name','user_id'] }]

      这使得 name 和 user_id 不能相同(复合键)。因此,例如,如果名称是 Joe 并且 user_id 是 1,并且我尝试创建另一个具有相同详细信息的记录,它会拒绝它,但如果我创建名称为 Rachel 和 user_id 1 的东西,它会允许它,因为它只是唯一的如果两者相同。

      据我所知,除非您以这种方式设置,否则无法使用复合键。

      此技术的另一个优点是模型位于单独的文件中并定义为类!

      那么我该如何使用这些呢?

      (在您的文件中定义续集连接...) api.js

      const { Sequelize, DataTypes, Model } = require('sequelize');
      const User = require('../models/user');
      const Algorithm = require('../models/algorithm');
      
      const sequelize = new Sequelize('database', 'username', 'passwordhere', {
            host: 'db',
            dialect: 'mysql' /* one of 'mysql' | 'mariadb' | 'postgres' | 'mssql' */
          });
      
      const UserModel = User(sequelize);
      const AlogorithmModel = Algorithm(sequelize);
      
      (async () => {
            try {
              await sequelize.authenticate();
              await UserModel.sync({ alter: true });
              await AlogorithmModel.sync({ alter: true });
      
              //Do something with the models now....
              //Etc...
      
            } catch (error) {
              console.error('Unable to connect to the database:', error);
            }
      
      });
      

      这种技术之所以有效,是因为类文件是如何定义的。在典型的软件开发中,您包含类并引用它并实例化它,但在这种情况下我们已经在传递它的实例化版本

      例如,您会注意到在类文件中我定义了class user extends model {},它里面只是空的。然后我们返回该类的实例化版本。当您以这种方式使用 module.exports 时,它实际上需要一个 sequelize 连接实例的参数。

      这就是为什么在 api.js 文件中我说 const User = require('../models/user');,这会引用文件返回的“函数”。

      除非你将它传递给 sequelize,否则该函数不会做任何事情,所以你看到的下一行...

      const UserModel = User(sequelize);
      

      通过这样做,您可以将模型放在单独的文件中,并将它们作为类,它们仍然可以具有关联甚至复合索引!

      希望对你有所帮助。

      更新::

      如果您想要 onUpdate 或 onDelete 级联选项,只需像这样使用模型定义它。

       algorithm_id: {
                  type: DataTypes.INTEGER,
                  allowNull: false,
                  onDelete: 'CASCADE',
                  onUpdate: 'CASCADE',
                  references: { 
                      model: AlgorithmModel,
                      key: 'id',
                  }
              },
      

      您也可以设置是否希望它为空,但是,请记住 allowNull 将无法与“alter”表命令一起使用,除非首先删除了外键! onUpdate 和 onDelete 似乎可以与 alter 一起使用。

      【讨论】:

      • 我没有考虑到的一件事是 onUpdate 和 onDelete 级联选项设置,我还不确定将它们放在哪里。因此,如果有人可以修改我的答案,我将不胜感激!
      • 好消息,我知道如何执行 onUpdate 和 on Delete cascade 选项!将更新我的答案
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-23
      • 2011-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-28
      相关资源
      最近更新 更多