如何使用数据库迁移的外键迁移。 (errno:150“外键约束是错误形成的”)?
Codeigniter 4具有方便的迁移和播种机解决方案。没有外国钥匙的使用,一切正常。但是,当我使用外键时,我会“无法添加外键”。
这是因为事件的顺序:
快速示例:
table bar
-------------------
| id | name | fooid |
FOREIGN KEY fooid REFERENCES foo.id
table foo
----------
| id | name|
因此,当我现在运行php php spark迁移
或php park spark迁移:refresh
无法设置外键,因为<代码> bar 表是创建的,但是尚不存在引用的foo
表。
从技术上讲,我可以在迁移后运行一个单独的功能,但是我喜欢php php spark迁移
的一个命令,并且一切都完成了。
解决此问题的正确方法是什么?
这是我的创建表创建代码:
CREATE TABLE `bar` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NULL DEFAULT NULL,
`fooid` int(11) UNSIGNED NOT NULL,
CONSTRAINT `pk_bar` PRIMARY KEY(`id`),
CONSTRAINT `bar_fooid_foreign` FOREIGN KEY(`fooid`) REFERENCES `foo` (`id`) ON DELETE SET NULL,
KEY `fooid` (`fooid`)
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci;
CREATE TABLE `foo` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NULL DEFAULT NULL,
CONSTRAINT `pk_foo` PRIMARY KEY(`id`),
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci;
附录
i think 我找到了问题的方向。 从评论中注意到,这是正确的,表格创建的顺序是不正确的。可以通过更改文件名中的时间戳来解决这一点,以便在foo
bar 之前创建。但是由于这没有解决这个问题,我发现了其他问题: 这是我用来迁移bar
的代码:
class Bar extends Migration
{
public function up()
{
$fields = [
'id' => [
'type' => 'int',
'constraint' => 11,
'unsigned' => true,
'auto_increment' => true,
],
'name' => [
'type' => 'varchar',
'constraint' => 255,
'default' => null,
],
'fooid' => [
'type' => 'int',
'constraint' => 11,
'unsigned' => true,
],
];
$this->forge->addField($fields);
$this->forge->addPrimaryKey('id');
$this->forge->addKey('fooid');
$this->forge->addForeignKey('fooid', 'foo', 'id', '', 'SET NULL');
$this->forge->createTable('bar');
}
public function down()
{
$this->forge->dropTable('bar');
}
}
这会生成fooid int(11)insed nosed not null
。问题是,foodid
不能为null
,但是FK将值设置为delete上的null
。
但是...字段的null
的默认值是'null'=&gt; true
,即使我手动添加此>,它也无法生成可确定的字段。
CodeIgniter 4 has a handy solution for migrations and seeders. Without the usage of foreign keys, everything is working perfectly. But when I use foreign keys I get "Unable to add foreign key".
This is because of the order of happenings:
Quick example:
table bar
-------------------
| id | name | fooid |
FOREIGN KEY fooid REFERENCES foo.id
table foo
----------
| id | name|
So when I now run php spark migrate
or php spark migrate:refresh
the foreign key can not be set because the bar
table is created, but the referenced foo
table does not exist yet.
Technically I could run a separate function that I run after my migration, but I like the one command of php spark migrate
and everything is done.
What is the correct way to solve this issue?
This is my create table created code:
CREATE TABLE `bar` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NULL DEFAULT NULL,
`fooid` int(11) UNSIGNED NOT NULL,
CONSTRAINT `pk_bar` PRIMARY KEY(`id`),
CONSTRAINT `bar_fooid_foreign` FOREIGN KEY(`fooid`) REFERENCES `foo` (`id`) ON DELETE SET NULL,
KEY `fooid` (`fooid`)
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci;
CREATE TABLE `foo` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NULL DEFAULT NULL,
CONSTRAINT `pk_foo` PRIMARY KEY(`id`),
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci;
Addendum
I think I find the direction of the issue.
Noticed from the comments, it is correct, the order of creation of the tables is not correct. This can be fixed by changing the timestamps in the filename, so that foo
gets created before bar
. But as this is not fixing the issue, I found something else:
This is code I'm using to migrate bar
:
class Bar extends Migration
{
public function up()
{
$fields = [
'id' => [
'type' => 'int',
'constraint' => 11,
'unsigned' => true,
'auto_increment' => true,
],
'name' => [
'type' => 'varchar',
'constraint' => 255,
'default' => null,
],
'fooid' => [
'type' => 'int',
'constraint' => 11,
'unsigned' => true,
],
];
$this->forge->addField($fields);
$this->forge->addPrimaryKey('id');
$this->forge->addKey('fooid');
$this->forge->addForeignKey('fooid', 'foo', 'id', '', 'SET NULL');
$this->forge->createTable('bar');
}
public function down()
{
$this->forge->dropTable('bar');
}
}
This generates a fooid int(11) UNSIGNED NOT NULL
. The issue is, that foodid
can not be null
but the fk sets the value to null
on delete.
But... the default for null
of a field is 'null' => true
and even if I add this manually, it is not generating the nullable field.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
只需重命名您的迁移时间戳前缀即可以
foo
的表创建bar
之前。例如,如果迁移文件名称如下:重命名其迁移时间戳前缀,因为引用表(
foo
)首先出现。最后,重新运行即将迁移的迁移。
php spark迁移
。附录1
参考您新编辑的问题描述,将表创建查询
foo
移至bar
之前。即:附录2
2022-02-16-1019_CREATEFOOMIGRATION.PHP
2022-04-22-101819_CREATEBARMIGRATION.PHP
Simply rename your migration timestamp prefixes such that the table creation of
foo
comes before that ofbar
. For example, if the migration file names are as follows:Rename their migration timestamp prefixes in that the referenced table (
foo
) comes first.Lastly, rerun the pending migrations.
php spark migrate
.Addendum 1
In reference to your newly edited question description, move the table creation query of
foo
to come before that ofbar
. I.e:Addendum 2
2022-02-16-101819_CreateFooMigration.php
2022-04-22-101819_CreateBarMigration.php