好吧,我正在尝试一些不同的 ORM,目前正在研究 Sequelize。我定义了两个模型:asset 和 asset_category,其中每个 asset 都有与 asset_category 的外键关系。都好! 现在,我想从使用自动增量 id 更改为 uuid,因为它更安全。所以我在数据库中有数据并编写了以下(超长!)迁移:
up: (queryInterface, Sequelize) => {
return queryInterface
.addColumn("asset_categories", "uuid", {
// Add uuid column
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: false,
})
.then(_ => {
return queryInterface.sequelize.query(
// Fill uuid column
`
UPDATE asset_categories SET uuid=uuid()
`,
);
})
.then(_ => {
return queryInterface.addColumn("assets", "category_uuid", {
// Add assets reference uuid column
type: Sequelize.UUID,
allowNull: false,
});
})
.then(_ => {
return queryInterface.sequelize.query(
// Fill assets reference uuid column
`
UPDATE assets
SET category_uuid= (SELECT ac.uuid FROM asset_categories ac WHERE ac.id = assets.category_id)
`,
);
})
.then(_ => {
// Remove assets category_id column
return queryInterface.removeColumn("assets", "category_id");
})
.then(_ => {
// Remove asset_categories id column
return queryInterface.removeColumn("asset_categories", "id");
})
.then(_ => {
// Rename asset_categories uuid to id
return queryInterface.renameColumn("asset_categories", "uuid", "id");
})
.then(_ => {
// Rename assets category_uuid to category_id
return queryInterface.renameColumn(
"assets",
"category_uuid",
"category_id",
);
})
.then(_ => {
return queryInterface.changeColumn("asset_categories", "id", {
// Add primary key to asset_categories id field
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: false,
primaryKey: true,
});
})
.then(_ => {
// Add index to asset_categories id field
return queryInterface.addIndex("asset_categories", ["id"]);
})
.then(_ => {
// Add index to assets category_id field
return queryInterface.addIndex("assets", ["category_id"]);
});
还有:
up: (queryInterface, Sequelize) => {
// Add uuid column
return queryInterface
.addColumn("assets", "uuid", {
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: false,
primaryKey: false,
})
.then(_ => {
// Fill uuid column
return queryInterface.sequelize.query(
`
UPDATE assets SET uuid=uuid()
`,
);
})
.then(_ => {
// Remove assets id column
return queryInterface.removeColumn("assets", "id");
})
.then(_ => {
// Rename assets uuid to id
return queryInterface.renameColumn("assets", "uuid", "id");
})
.then(_ => {
// Add primary key to uuid column
return queryInterface.changeColumn("assets", "id", {
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: false,
primaryKey: true,
});
})
.then(_ => {
// add foreign key on assets category_id
return queryInterface.changeColumn("assets", "category_id", {
type: Sequelize.UUID,
allowNull: false,
references: {
model: {
tableName: "asset_categories",
},
key: "id",
},
});
});
问题是我在最后一步中遇到错误:
错误:引用列“category_id”和外键约束“assets_ibfk_1”中引用的列“id”不兼容。
似乎在所有这些步骤中 asset_category.id 更改为
id
char(36) 字符集 utf8mb4 COLLATE utf8mb4_bin NOT NULL,
虽然 asset.category_id 是
category_id
char(36) COLLATE utf8mb4_general_ci NOT NULL,
我假设这就是我无法将外键添加回来的原因,因为列不完全相同。
对于初学者来说:这是怎么发生的?是什么导致列获得不同的字符集或排序规则?另外:是否有更好的方法来实现这种迁移,因为与使用 Ruby on Rails + Active Record 相比,这看起来完全是垃圾......
最佳答案
DROP
涉及您要删除的ids
的所有 FK。完成转换后为uuid添加FK。- Uuids 应为
CHAR(36) 字符集 ascii COLLATION ascii_general_ci
。 - 如果您的表很大,您应该考虑转换为
BINARY(16)
以节省大量磁盘空间。 - 当前指向其他表中
ids
的任何列也需要变为CHAR(36)...
。 - 采取行动的顺序至关重要。
类似于:
- 备份整个数据集 - 下面的错误可能无法恢复。
- 删除 FK。在继续下一步之前对所有表执行此操作。
- 为每个类似 id 的列添加 COLUMN uuid;每个表中可能有多个。
- 使用新值填充将成为 PK 的 uuid。
- 通过基于现有 ID 执行多表
UPDATE
来填充其他 uuid。 - 更改客户端代码以引用 uuid;测试一下。
- 对于 PK 发生变化的表,DROP PRIMARY KEY 并 ADD PRIMARY KEY(uuid)。
- DROP COLUMN 用于 id 和类似 id 的列。
- 在适当的情况下为 uuid 添加 FK。
如果您选择使用较小的 uuid 格式,则会修改步骤 4、5、6 的详细信息。
呃。
关于mysql - 使用sequelize从使用自动增量id迁移到uuid,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60146888/