Laravel 8.X Eloquent 中数据库迁移的正确外键约束语法是啥?

Posted

技术标签:

【中文标题】Laravel 8.X Eloquent 中数据库迁移的正确外键约束语法是啥?【英文标题】:What is the correct foreign key constraint syntax for a database migration in Laravel 8.X Eloquent?Laravel 8.X Eloquent 中数据库迁移的正确外键约束语法是什么? 【发布时间】:2021-07-26 17:22:26 【问题描述】:

我是 Laravel 和雄辩的菜鸟。

我正在尝试在“清单项目”表中创建一个简单的外键,该表将“用户”表中的主 ID 作为外键。

这是我的两个数据库迁移:

用户:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    
        Schema::create('users', function (Blueprint $table) 
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        );
    

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    
        Schema::dropIfExists('users');
    


项目:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateItemsTable extends Migration

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    
        Schema::create('items', function (Blueprint $table) 
            $table->id();
            $table->integer('user_id')->unsigned();
            $table->string('itemName');
            $table->string('itemDescription');
            $table->timestamps();
        );
        
        Schema::table('items', function($table) 
            $table->foreign('user_id')->references('id')->on('users');
        );
        
    

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    
        Schema::dropIfExists('items');
    

尝试运行 php artisan migrate 会产生以下错误:

Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.49 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (0.59 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (0.33 seconds)
Migrating: 2021_05_04_085648_create_items_table

   Illuminate\Database\QueryException

  SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL: alter table `items` add constraint `items_user_id_foreign` foreign key (`user_id`) references `users` (`id`))

  at D:\Applications\laragon\www\ToDoApp\vendor\laravel\framework\src\Illuminate\Database\Connection.php:671
    667|         // If an exception occurs when attempting to run a query, we'll format the error
    668|         // message to include the bindings with SQL, which will make this exception a
    669|         // lot more helpful to the developer instead of just the database's errors.
    670|         catch (Exception $e) 
  > 671|             throw new QueryException(
    672|                 $query, $this->prepareBindings($bindings), $e
    673|             );
    674|         
    675|

  1   D:\Applications\laragon\www\ToDoApp\vendor\laravel\framework\src\Illuminate\Database\Connection.php:464
      PDOException::("SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint")

  2   D:\Applications\laragon\www\ToDoApp\vendor\laravel\framework\src\Illuminate\Database\Connection.php:464
      PDOStatement::execute()

需要注意的是,我可以直接在 PHPMyAdmin GUI 中实现我所需要的,或者使用基本的 PHP PDO,但是我不懂 Eloquent,需要了解我做错了什么。

我感觉这与两个表迁移之间的属性定义不匹配有关,但我尝试的几件事导致了替代错误。

【问题讨论】:

【参考方案1】:

列的类型和符号必须相同(有符号或无符号)

$table-&gt;integer('user_id')-&gt;unsigned(); 应该是$table-&gt;bigInteger('user_id')-&gt;unsigned();

【讨论】:

【参考方案2】:

只需为外键 (docs) 创建一个新的迁移文件。像

php artisan make:migration add_columns_to_items_table

为什么对同一张表使用不同的文件?因为我们在制作foreignKey之前先制作表格,对吗? :)

然后在 up() 函数上的迁移文件中:

Schema::table('items', function (Blueprint $table) 
    $table->foreignId('user_id')->constrained();
);

是的,它更短,更适合开发目的

【讨论】:

【参考方案3】:

当您在one-to-many 关系的one 部分之前为many 创建迁移时,会发生这种情况。在您的情况下,我猜您在users 之前为items 创建了迁移。只需根据您的关系重命名您的迁移文件。另请注意,您的关系列必须属于同一类型。在您的情况下,您将 4 字节的 integer 引用到 8 字节的 bigInteger。 (id 列是一个 unsigned 8 字节整数)。

【讨论】:

【参考方案4】:

用以下代码替换您的 items 迁移:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateItemsTable extends Migration

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    
        Schema::create('items', function (Blueprint $table) 
            $table->id();
            $table->integer('user_id')->unsigned();
            $table->string('itemName');
            $table->string('itemDescription');
            $table->timestamps();

            $table->foreign('user_id')->references('id')->on('users');
        );
        
    

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    
        Schema::dropIfExists('items');
    

【讨论】:

以上是关于Laravel 8.X Eloquent 中数据库迁移的正确外键约束语法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Laravel (8.x) 这个多对多过滤问题有更好的 Eloquent 查询吗?

Laravel Eloquent - orWhereHas 方法 - 何时使用以及如何使用

如何在 Laravel/Eloquent 中获得完整的关系

Laravel - 在 Eloquent 模型中返回自定义额外数据

无法在 Controller Laravel belongsToMany 关系中获取正确的数据 - Laravel / Eloquent [关闭]

laravel 5.1 中 Eloquent 和 Query Builder 有啥区别?