【问题标题】:Sequelize targetKey not working续集targetKey不起作用
【发布时间】:2018-09-23 21:31:18
【问题描述】:

我正在尝试使用 sequelize 关联两个模型“Note”和“Resource”。但是,targetKey 没有按预期工作。

备注模态

module.exports = function(sequelize, DataTypes) {
  return sequelize.define('note', {
    NoteID: {
      type: DataTypes.INTEGER(11),
      allowNull: false,
      primaryKey: true,
      autoIncrement: true
    },
    Title: {
      type: DataTypes.STRING(50),
      allowNull: true
    },
    Note: {
      type: DataTypes.STRING(500),
      allowNull: false
    },
    CreatedBy: {
      type: DataTypes.INTEGER(11),
      allowNull: false,
      references: {
        model: 'resource',
        key: 'ResourceID'
      }
    },
    UpdatedBy: {
      type: DataTypes.INTEGER(11),
      allowNull: true,
      references: {
        model: 'resource',
        key: 'ResourceID'
      }
    }
  }, {
    tableName: 'note'
  });
};

资源模式

module.exports = function(sequelize, DataTypes) {
  return sequelize.define('resource', {
    ResourceID: {
      type: DataTypes.INTEGER(11),
      allowNull: false,
      primaryKey: true,
      autoIncrement: true
    },
    FirstName: {
      type: DataTypes.STRING(250),
      allowNull: false
    },
    LastName: {
      type: DataTypes.STRING(250),
      allowNull: false
    }
  }, {
    tableName: 'resource'
  });
};

协会

Resource.belongsTo(Note,{
    foreignKey: 'UpdatedBy',
    as: 'Resource_Updated_Note'
});

Note.hasOne(Resource,{
    foreignKey: 'ResourceID',
    targetKey: 'UpdatedBy',
    as: 'Note_Updated_By'
});

Resource.belongsTo(Note,{
    foreignKey: 'CreatedBy',
    as: 'Resource_Created_Note'
});

Note.hasOne(Resource,{
    foreignKey: 'ResourceID',
    targetKey: 'CreatedBy',
    as: 'Note_Created_By'
});

虽然我在关联时提到了targetKey,但在加入表格时它正在使用PrimaryKey。

执行

Note.findAll({
        include: [{
            model: Resource,
            as: 'Note_Updated_By'
        }],
        where: {
            Status: {
                [SQLOP.or]: ['Active', 'ACTIVE']
            }
        }
    }).then(function (response) {
        callback(response);
    });

根据执行,生成此选择查询。

SELECT * FROM `note` LEFT OUTER JOIN `resource` AS `Note_Updated_By` ON `note`.`NoteID` = `Note_Updated_By`.`ResourceID`;

应该是note.UpdatedBy,而不是note.NoteID

【问题讨论】:

    标签: node.js associations sequelize.js


    【解决方案1】:

    您必须同时设置hasMany({ sourceKeybelongsTo({ targetKey

    这是 sequelize docs 又一次让我们失望了,每一方都有不同的名称,我们必须同时设置它们,例如:

    const Country = sequelize.define('Country', {
      country_name: { type: DataTypes.STRING, unique: true },
    });
    const City = sequelize.define('City', {
      parent_country: { type: DataTypes.STRING },
      city_name: { type: DataTypes.STRING },
    });
    Country.hasMany(City, { foreignKey: 'parent_country', sourceKey: 'country_name' } )
    City.belongsTo(Country, { foreignKey: 'parent_country', targetKey: 'country_name' } )
    

    如果只设置sourceKey,那么查询会出错,两者都需要。

    最小的可运行示例:

    main.js

    #!/usr/bin/env node
    const assert = require('assert')
    const path = require('path')
    const { DataTypes, Sequelize } = require('sequelize')
    let sequelize
    if (process.argv[2] === 'p') {
      sequelize = new Sequelize('tmp', undefined, undefined, {
        dialect: 'postgres',
        host: '/var/run/postgresql',
      })
    } else {
      sequelize = new Sequelize({
        dialect: 'sqlite',
        storage: 'tmp.sqlite'
      })
    }
    ;(async () => {
    const Country = sequelize.define('Country', {
      country_name: { type: DataTypes.STRING, unique: true },
    });
    const City = sequelize.define('City', {
      parent_country: { type: DataTypes.STRING },
      city_name: { type: DataTypes.STRING },
    });
    Country.hasMany(City, { foreignKey: 'parent_country', sourceKey: 'country_name' } )
    City.belongsTo(Country, { foreignKey: 'parent_country', targetKey: 'country_name' } )
    await sequelize.sync({force: true});
    await Country.create({country_name: 'germany'})
    await Country.create({country_name: 'france'})
    await City.create({parent_country: 'germany', city_name: 'berlin'});
    await City.create({parent_country: 'germany', city_name: 'munich'});
    await City.create({parent_country: 'france', city_name: 'paris'});
    const rows = await City.findAll({
      where: { parent_country: 'germany' },
      include: {
        model: Country,
      }
    });
    assert.strictEqual(rows[0].Country.country_name, 'germany')
    assert.strictEqual(rows[1].Country.country_name, 'germany')
    assert.strictEqual(rows.length, 2)
    })().finally(() => { return sequelize.close() })
    

    package.json

    {
      "name": "tmp",
      "private": true,
      "version": "1.0.0",
      "dependencies": {
        "pg": "8.5.1",
        "pg-hstore": "2.3.3",
        "sequelize": "6.14.0",
        "sqlite3": "5.0.2"
      }
    }
    

    根据需要生成查询:

    Executing (default): DROP TABLE IF EXISTS `Cities`;
    Executing (default): DROP TABLE IF EXISTS `Countries`;
    Executing (default): DROP TABLE IF EXISTS `Countries`;
    Executing (default): CREATE TABLE IF NOT EXISTS `Countries` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `country_name` VARCHAR(255) UNIQUE);
    Executing (default): PRAGMA INDEX_LIST(`Countries`)
    Executing (default): PRAGMA INDEX_INFO(`sqlite_autoindex_Countries_1`)
    Executing (default): DROP TABLE IF EXISTS `Cities`;
    Executing (default): CREATE TABLE IF NOT EXISTS `Cities` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `parent_country` VARCHAR(255) REFERENCES `Countries` (`country_name`) ON DELETE CASCADE ON UPDATE CASCADE, `city_name` VARCHAR(255));
    Executing (default): PRAGMA INDEX_LIST(`Cities`)
    Executing (default): INSERT INTO `Countries` (`id`,`country_name`) VALUES (NULL,$1);
    Executing (default): INSERT INTO `Countries` (`id`,`country_name`) VALUES (NULL,$1);
    Executing (default): INSERT INTO `Cities` (`id`,`parent_country`,`city_name`) VALUES (NULL,$1,$2);
    Executing (default): INSERT INTO `Cities` (`id`,`parent_country`,`city_name`) VALUES (NULL,$1,$2);
    Executing (default): INSERT INTO `Cities` (`id`,`parent_country`,`city_name`) VALUES (NULL,$1,$2);
    Executing (default): SELECT `City`.`id`, `City`.`parent_country`, `City`.`city_name`, `Country`.`id` AS `Country.id`, `Country`.`country_name` AS `Country.country_name` FROM `Cities` AS `City` LEFT OUTER JOIN `Countries` AS `Country` ON `City`.`parent_country` = `Country`.`country_name` WHERE `City`.`parent_country` = 'germany';
    

    值得注意的是,我们有所需的REFERENES

    CREATE TABLE IF NOT EXISTS `Cities` (
      `id` INTEGER PRIMARY KEY AUTOINCREMENT,
      `parent_country` VARCHAR(255) REFERENCES `Countries` (`country_name`) ON DELETE CASCADE ON UPDATE CASCADE,
      `city_name` VARCHAR(255));
    

    他想要加入:

    ON `City`.`parent_country` = `Country`.`country_name`
    

    使用自定义列。

    在 SQLite 和 PostgreSQL 13.5 上测试。

    相关:

    【讨论】:

      【解决方案2】:

      从我使用的新版本开始"sequelize": "^5.8.12" 使用sourceKey 而不是targetKey 代表hasOnehasMany 关系对我有用。

      ModelName.hasOne(ModelName1, {
        as: 'SomeAlias',
        foreignKey: 'foreign_key',
        onDelete: 'NO ACTION',
        onUpdate: 'NO ACTION',
        sourceKey: 'YOUR_CUSTOM_ASSOCIATION_KEY'
      });
      

      【讨论】:

        【解决方案3】:

        对于未来的访问者,截至 2018 年 8 月,这仍然是带有续集的 known issue

        【讨论】:

          猜你喜欢
          • 2014-07-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-01-21
          • 2016-02-20
          • 1970-01-01
          • 2020-02-08
          • 1970-01-01
          相关资源
          最近更新 更多