如何为多对多关联构建 sequlize 迁移文件
How to structure seqeulize migration files for many-to-many association
您必须在迁移文件(和模型文件)中放入什么才能在 sequelize 中创建 M:N 关联?我怀疑我的意思是,需要设置什么 references
,以及这些对象中所需的键是什么意思,但我不是 100% 确定这就是我的意思。
我正在尝试创建一个 users<->rolls 关联,类似于 here。
最初,我将 references
添加到我的 user
和 roll
迁移文件中。然后我意识到 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
User
和 Role
之间的 M:N 关系,那么 references
选项应该只在 UserRole
中使用,因为只有它有 User
和 Role
.
的外键
此外,您应该在 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');
}
};
您必须在迁移文件(和模型文件)中放入什么才能在 sequelize 中创建 M:N 关联?我怀疑我的意思是,需要设置什么 references
,以及这些对象中所需的键是什么意思,但我不是 100% 确定这就是我的意思。
我正在尝试创建一个 users<->rolls 关联,类似于 here。
最初,我将 references
添加到我的 user
和 roll
迁移文件中。然后我意识到 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
User
和 Role
之间的 M:N 关系,那么 references
选项应该只在 UserRole
中使用,因为只有它有 User
和 Role
.
的外键
此外,您应该在 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');
}
};