34

本质上,我和这个人有同样的问题,减去表前缀。因为我没有表前缀,所以他的修复不起作用。http://forums.laravel.com/viewtopic.php?id=972

我正在尝试使用 Laravel 的 Schema Builder 构建一个表,如下所示:

Schema::create('lessons', function($table)
{
    $table->increments('id');
    $table->string('title')->nullable();
    $table->string('summary')->nullable();
    $table->timestamps();
});

Schema::create('tutorials', function($table)
{
    $table->increments('id');
    $table->integer('author');
    $table->integer('lesson');
    $table->string('title')->nullable();
    $table->string('summary')->nullable();
    $table->string('tagline')->nullable();
    $table->text('content')->nullable();
    $table->text('attachments')->nullable();
    $table->timestamps();
});

Schema::table('tutorials', function($table)
{
    $table->foreign('author')->references('id')->on('users');
    $table->foreign('lesson')->references('id')->on('lessons');
});

问题是,当我运行此代码时(在 /setup 路由中),我收到以下错误:

SQLSTATE[HY000]: General error: 1005 Can't create table 'tutorials.#sql-2cff_da' (errno: 150)

SQL: ALTER TABLE `tutorials` ADD CONSTRAINT tutorials_author_foreign FOREIGN KEY (`author`) REFERENCES `users` (`id`)

Bindings: array (
)

基于网络上的帖子和关于如何设置Laravel 的 Eloquent 关系的有限文档,我不确定我做错了什么......

users已经存在并且它确实有一个id字段是auto_increment. 我也在用正确的关系(belongs_tohas_many)设置我的模型,但据我所知,这不是问题——这是数据库设置。数据库InnoDB。

外键到底做错了什么?

4

13 回答 13

81

我一直有同样的问题。我刚刚注意到Laravel Schema 文档最底部的以下注释:

注意:外键中引用的字段很可能是自动递增的,因此会自动成为无符号整数。请确保使用 unsigned() 创建外键字段,因为两个字段必须是完全相同的类型,两个表上的引擎必须设置为 InnoDB,并且必须在具有外键的表之前创建引用的表.

对我来说,只要我这样设置外键字段:

$table->integer('author')->unsigned();

我没有问题。

编辑:另外,确保外部表中的字段已经创建,否则这可能会失败并出现相同的错误。

于 2012-12-12T00:50:56.413 回答
14

我不是 100% 确定这些是否是失败的原因,但有几个指针。如果您使用旧版本的 mySQL 作为数据库,则默认表实现是不支持外键限制的 myISAM。由于您的脚本在外键分配上失败,您最好在 Schema 的 create 方法中使用此语法明确声明您希望 INNODB 作为引擎。

Schema::create('lessons', function($table)
{
    $table->engine = 'InnoDB';

    $table->increments('id');
    $table->string('title')->nullable();
    $table->string('summary')->nullable();
    $table->timestamps();
});

这应该有望缓解您遇到的问题。

此外,虽然您可以事后声明外键,但我会在初始模式中创建外键,因为我可以轻松检查以确保我设置了正确的数据库引擎。

Schema::create('tutorials', function($table)
{
    $table->engine = 'InnoDB';

    $table->increments('id');
    $table->integer('author');
    $table->integer('lesson');
    $table->string('title')->nullable();
    $table->string('summary')->nullable();
    $table->string('tagline')->nullable();
    $table->text('content')->nullable();
    $table->text('attachments')->nullable();
    $table->timestamps();

    $table->foreign('author')->references('id')->on('users');
    $table->foreign('lesson')->references('id')->on('lessons');
});

希望这有助于/解决您的问题。

于 2012-08-10T19:07:22.393 回答
8

已经列出的答案摘要,加上我的:

  1. 外键一般需要InnoDb,所以设置你的默认引擎,或者明确指定

    $table->engine = 'InnoDB';
    
  2. 外键要求被引用的表存在。在创建密钥之前,请确保在较早的迁移中创建了引用的表。考虑在单独的迁移中创建密钥以确保。

  3. 外键要求数据类型一致。检查引用的字段是否相同类型,是否有符号或无符号,长度是否相同(或更少)。

  4. 如果您在手动编码迁移和使用生成器之间切换,请确保检查您正在使用的 id 类型。Artisan 默认使用increments()但 Jeffrey Way 似乎更喜欢integer('id', true)

于 2013-09-20T10:49:43.543 回答
6

我也遇到了这个问题。

我找到的解决方案是,在另一个表可以引用它之前,需要创建包含正在使用的外部 id 的 id 的表。基本上,您正在创建一个表并告诉 MySQL 引用另一个表的主键,但该表还不存在。

在您的示例中,需要首先创建作者和课程表。

创建表的顺序取决于工匠和您创建迁移文件的顺序。

我的意见是清空所有表的数据库并更改迁移文件名中的时间戳(或删除它们并以正确的顺序重新创建它们),以便在教程表之前创建作者和课程表。

于 2013-04-03T23:28:13.903 回答
5

我收到了同样的错误,因为我忘记在引用的表上将表类型设置为 InnoDB:

$table->engine = 'InnoDB';
于 2013-03-29T10:22:16.637 回答
4

Laravel5、MySQL55、CentOS65

就我而言,错误与此相同。

错误:[Illuminate\Database\QueryException]
SQLSTATE[HY000]:一般错误:1005 Can't create table 'nabsh.#sql-5b0_e' (errno: 121) (SQL: alter table usermetaadd constraint usermeta_uid_foreign foreign key ( uid) 引用 users( id) 删除级联)。

我在这个问题的已批准答案中找到了一个很好的提示: 错误:错误 1005:无法创建表(错误号:121)

提示:如果您尝试添加名称已在其他地方使用过的约束,您将收到此消息。

在我的情况下,这个错误意味着已经尝试添加的约束已经存在于某处(但我在任何地方都看不到它们)。

我复制了输出错误查询并在 sequel pro 中执行它,然后希望我再次看到相同的错误。正如提示所说,我将约束名称更改为其他名称,然后它没有任何错误影响,因此 laravel5 + MySQL55 + CentOS65 中的约束名称生成器存在问题。

解决方案:尝试通过在表模式中的外部方法处发送第二个参数来重命名约束。

Schema::table('tutorials', function($table)
{
    $table->foreign('author')->references('id')->on('users');
    $table->foreign('lesson')->references('id')->on('lessons');
});

到->

Schema::table('tutorials', function($table)
{
    $table->foreign('author', 'fk_tutorials_author')->references('id')->on('users');
    $table->foreign('lesson', 'fk_tutorials_lesson')->references('id')->on('lessons');
});

我希望它有帮助。它适用于我的情况

于 2015-10-04T20:21:25.670 回答
1

最简单的方法是禁用外键检查:

DB::statement('set foreign_key_checks=0');

Schema::table( ... );

DB::statement('set foreign_key_checks=1');
于 2015-11-04T13:42:03.347 回答
1

使用外键时,请确保您的外键是unsigned. 这对我有用

于 2016-02-29T16:40:25.990 回答
1

这在 Yii Framework 1.x 迁移中也发生在我身上。原来,与上面的 Laravel 解决方案类似,它可能是由

  • 拼写错误(或尚不存在)的表名
  • 拼写错误(或尚不存在)的列名
  • 在不同表中使用同一数据库中的重复外键名称
于 2016-01-22T16:48:05.500 回答
0

基本上,您会收到此错误,因为迁移命令创建表的顺序与您为表提供的 FK 引用不匹配。

就像如果你想创建一个应该引用用户表中的 id 的 FK,那么用户表必须存在。

在您的示例中,需要首先创建作者和课程表。

因此,我通过按这样的顺序(一个接一个)创建表来解决这个问题,在那里我可以成功地将 FK 引用到现有表。这样 Php Artisan Migration 就无法决定顺序。

另一种解决方案是,您可以简单地重命名迁移命令提供的表或时间戳。

于 2020-12-08T21:38:47.593 回答
0

这是我在 Laravel 5 中所做的:

// CREATING TABLE
Schema::create('your_table_name', function (Blueprint $table) {
    $table->engine = 'InnoDB';
    $table->increments('id'); // index field example sample
    $table->string('field2'); // some varchar/string field sample
    $table->integer('field3'); // some integer field sample
    $table->integer('field_some_table_id')->unsigned; //for field that contains foreign key constraint
});

// FOREIGN KEY CONSTRAINT
Schema::table('stock', function ($table) {
    $table->foreign('field_some_table_id')->references('id')->on('some_table')->onDelete('cascade')->onUpdate('cascade');
});

这就是结论,它对我有用。

于 2015-12-10T04:09:13.520 回答
0

你必须在 Laravel 5.4 中给整数一个无符号标志,像这样:

public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        $table->increments('post_id');
        $table->text('title');
        $table->text('text');
        $table->integer('employee_post_id_number')->unsigned();
        $table->foreign('employee_post_id_number')->references 
        ('employee_id_number')->on('employees');
        $table->timestamps();
    });
}
于 2017-10-20T08:17:23.827 回答
0

通过使用:

 $table->unsignedInteger('author');

代替:

 $table->integer('author');

问题将得到解决。

问题是整数生成一个 int(11) 变量,而您需要一个 int(10) 变量。unsignedInteger 将为您完成。

于 2021-09-28T06:30:22.257 回答