codeigniter 如何将外键迁移与数据库迁移一起使用,(错误号:150“外键约束的格式不正确”)?

kiz8lqtg  于 2022-12-07  发布在  其他
关注(0)|答案(1)|浏览(206)

CodeIgniter 4有一个方便的迁移和播种器解决方案。没有使用外键,一切都运行得很完美。但是当我使用外键时,我得到“无法添加外键”。
这是因为发生的顺序:
快速示例:

table bar
 -------------------
| id | name | fooid |
FOREIGN KEY fooid REFERENCES foo.id

table foo
 ----------
| id | name|

因此,当我现在运行php spark migratephp spark migrate:refresh时,无法设置外键,因为创建了bar表,但引用的foo表尚不存在。
从技术上讲,我可以在迁移后运行一个单独的函数,但我喜欢php spark migrate的一个命令,一切都完成了。
解决这个问题的正确方法是什么?
这是我创建表时创建的代码:

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;
附录

认为我找到了问题的方向。从评论中注意到,它是正确的,但表的创建顺序不正确。这可以通过更改文件名中的时间戳来修复,这样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) UNSIGNED NOT NULL。问题是,foodid不能是null,但fk在删除时将值设置为null
但是...字段的null的默认值是'null' => true,即使我手动添加它,它也不会生成可为空的字段。

sshcrbum

sshcrbum1#

只需 * 重命名 * 移植时间戳前缀,使foo的表创建先于bar的表创建。例如,如果移植文件名如下:

app/Database/Migrations/2022-02-16-101819_CreateBarMigration.php
app/Database/Migrations/2022-04-22-101819_CreateFooMigration.php ❌

重命名它们的迁移时间戳前缀,因为引用的表(foo)优先。

app/Database/Migrations/2022-04-22-101819_CreateBarMigration.php
app/Database/Migrations/2022-02-16-101819_CreateFooMigration.php ✅

最后,重新运行挂起的迁移。php spark migrate

附录1

参照您新编辑的问题描述,将foo的建表查询移动到bar的建表查询之前,即:

CREATE TABLE `foo` ( ...)

CREATE TABLE `bar` ( ...)
附录2

2022 - 02 - 16 - 101819_创建一个文件名为foomigration.php的文件

<?php

namespace App\Database\Migrations;

use CodeIgniter\Database\Migration;

class CreateFooMigration extends Migration
{
    public function up()
    {
        $this->forge->addField([
            'id'          => [
                'type'           => 'INT',
                'constraint'     => 11,
                'unsigned'       => true,
                'auto_increment' => true,
            ],
            'name'       => [
                'type'       => 'VARCHAR',
                'constraint' => '100',
            ]
        ]);
        $this->forge->addKey('id', true);
        $this->forge->createTable('foo');
    }

    public function down()
    {
        $this->forge->dropTable('foo');
    }
}

2022 - 04 - 22 - 101819_创建条迁移. php

<?php

namespace App\Database\Migrations;

use CodeIgniter\Database\Migration;

class CreateBarMigration extends Migration
{
    public function up()
    {
        $this->forge->addField([
            'id'          => [
                'type'           => 'INT',
                'constraint'     => 11,
                'unsigned'       => true,
                'auto_increment' => true,
            ],
            'name'       => [
                'type'       => 'VARCHAR',
                'constraint' => '100',
            ],
            'foo_id' => [
                'type' => 'INT',
                'constraint'     => 11,
                'unsigned'       => true,
                'null' => true,
            ],
        ]);
        $this->forge->addKey('id', true);
        $this->forge->addForeignKey('foo_id', 'foo', 'id', 'CASCADE', 'RESTRICT' );
        $this->forge->createTable('bar');
    }

    public function down()
    {
        $this->forge->dropTable('bar');
    }
}

相关问题