如何为多对多关联构建 sequlize 迁移文件

How to structure seqeulize migration files for many-to-many association

您必须在迁移文件(和模型文件)中放入什么才能在 sequelize 中创建 M:N 关联?我怀疑我的意思是,需要设置什么 references,以及这些对象中所需的键是什么意思,但我不是 100% 确定这就是我的意思。

我正在尝试创建一个 users<->rolls 关联,类似于 here

最初,我将 references 添加到我的 userroll 迁移文件中。然后我意识到 userrolls 加入 table 迁移文件可能还需要 references 另一个方向。我怀疑我已经接近所有可能的设置组合,但不知何故仍然无法正常工作 :)

我的模型文件中的关联:

role.js

static associate(models) {
  models.Role.belongsToMany(models.User, {
    through: models.UserRole
  })
}

user.js

static associate(models) {
  models.User.belongsToMany(models.Role, {
    through: models.UserRole
  })
}

用户role.js

static associate(models) {
  UserRole.belongsTo(models.User, { foreignKey: 'id' });
  UserRole.belongsTo(models.Role, { foreignKey: 'id' }); 
  // UserRole.belongsTo(models.User, { foreignKey: 'userId' }); // <- *
  // UserRole.belongsTo(models.Role, { foreignKey: 'roleId' });
}   

* 在这里和下面,注释掉的行是我尝试过的各种事情,尽管它们可能不考虑所有尝试。

我的迁移文件:

创建用户

'use strict';
module.exports = {
  async up(queryInterface, Sequelize) {
    await queryInterface.createTable('Users', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER,
        /*
        references: {
          model: 'UserRoles',
          key: 'id',
          as: 'userId'
        }
        */
        references: {
          model: 'UserRoles',
          key: 'userId'
        }
      },  
      username: {
        type: Sequelize.STRING
      },
      ...
    });
  },
  async down(queryInterface, Sequelize) {
    await queryInterface.dropTable('Users');
  }
};

create-role.js 文件与上述一致。

创建用户-role.js

'use strict';
module.exports = {
  async up(queryInterface, Sequelize) {
    await queryInterface.createTable('UserRoles', {
      /*
      userId: {
        // allowNull: false,
        primaryKey: true,
        type: Sequelize.INTEGER,
        references: {
          model: 'Users',
          key: 'id'
        }
      },
      */
      userId: {
        // allowNull: false,
        primaryKey: true,
        type: Sequelize.INTEGER,
        references: {
          model: 'Users',
          key: 'id',
          as: 'userId'
        }
      },
      /*
      roleId: {
        // allowNull: false,
        primaryKey: true,
        type: Sequelize.INTEGER,
        references: {
          model: 'Roles',
          key: 'id'
        }
      },
      */
      roleId: {
        // allowNull: false,
        primaryKey: true,
        type: Sequelize.INTEGER,
        references: {
          model: 'Roles',
          key: 'id',
          as: 'roleId'
        }
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
  },
  async down(queryInterface, Sequelize) {
    await queryInterface.dropTable('UserRoles');
  }
};

我had/have这个工作,使用标准,documented method你使用sequelize.define并依赖sync来创建tables,但是似乎我找不到正确的咒语让它与自动加载所有模型的 seqeulize-cli 迁移方法一起工作。在我(相当未经训练的)眼中,生成的 table 看起来是正确的:

sqlite> .schema
CREATE TABLE `Users` (`id` INTEGER PRIMARY KEY AUTOINCREMENT REFERENCES `UserRoles` (`userId`), `username` VARCHAR(255), `email` VARCHAR(255), `password` VARCHAR(255), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL);
CREATE TABLE `Roles` (`id` INTEGER PRIMARY KEY AUTOINCREMENT REFERENCES `UserRoles` (`roleId`), `name` VARCHAR(255), `createdAt` DATETIME, `updatedAt` DATETIME NOT NULL);
CREATE TABLE `UserRoles` (`userId` INTEGER NOT NULL REFERENCES `Users` (`id`), `roleId` INTEGER NOT NULL REFERENCES `Roles` (`id`), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`userId`, `roleId`));

至少最后一个条目看起来类似于他们提供的 PostgreSQL 示例 in the docs,但他们似乎没有提供主要 table 的示例。

但是,无论我做什么,如果我去插入一个用户,它都会抱怨外键不匹配:

Executing (default): INSERT INTO `Users` (`id`,`username`,`email`,`password`,`createdAt`,`updatedAt`) VALUES (NULL,,,,,);
SQLITE_ERROR: foreign key mismatch - "Users" referencing "UserRoles"

我会采取简单的“在您的代码中更改此设置”的答案,但是,正如我在开头提到的,我怀疑这是对需要设置的内容和原因的根本误解,所以...一些非常感谢解释我应该做什么。

如果您需要使用 UserRole UserRole 之间的 M:N 关系,那么 references 选项应该只在 UserRole 中使用,因为只有它有 UserRole.
的外键 此外,您应该在 belongsToMany 中指示与在 belongsTo:

中指示的相同的外键

role.js

models.Role.belongsToMany(models.User, {
    through: models.UserRole,
    foreignKey: 'roleId',
    otherKey: 'userId'
  })

user.js

models.User.belongsToMany(models.Role, {
    through: models.UserRole,
    foreignKey: 'userId',
    otherKey: 'roleId'
  })

用户role.js

static associate(models) {
  UserRole.belongsTo(models.User, { foreignKey: 'userId' });
  UserRole.belongsTo(models.Role, { foreignKey: 'roleId' });
}   

创建user.js

'use strict';
module.exports = {
  async up(queryInterface, Sequelize) {
    await queryInterface.createTable('Users', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER,
      },  
      username: {
        type: Sequelize.STRING
      },
      ...
    });
  },
  async down(queryInterface, Sequelize) {
    await queryInterface.dropTable('Users');
  }
};

主键应该是一个单独的列,就像在 User 模型中一样。
create-user-role.js

'use strict';
module.exports = {
  async up(queryInterface, Sequelize) {
    await queryInterface.createTable('UserRoles', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER,
      },  
      userId: {
        type: Sequelize.INTEGER,
        references: {
          model: 'Users',
          key: 'id'
        }
      },
      roleId: {
        type: Sequelize.INTEGER,
        references: {
          model: 'Roles',
          key: 'id'
        }
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
  },
  async down(queryInterface, Sequelize) {
    await queryInterface.dropTable('UserRoles');
  }
};