Laravel :: 更新外键的最佳方法

49

我有这个迁移文件

Schema::create('table_one', function(Blueprint $table) 
{ 
    $table->increments('id'); 
    $table->string('name'); 
    $table->integer('table_two_id')->unsigned(); 
    $table->foreign('table_two_id')->references('id')->on('table_two'); 
    $table->timestamps(); 
});

我希望更新它为->onDelete('cascade');

$table->foreign('table_two_id')->references('id')->on('table_two')->onDelete('cascade');

怎样做是最好的?

是否有类似于 ->change(); 的东西?

谢谢

5个回答

82

删除外键,然后再添加它,最后运行迁移命令。

public function up()
{
    Schema::table('table_one', function (Blueprint $table) {
        $table->dropForeign(['table_two_id']);

        $table->foreign('table_two_id')
            ->references('id')
            ->on('table_two')
            ->onDelete('cascade');
    });
}

1
这是有道理的,因为MySQL也会以同样的方式处理,对于这种情况没有“变化”。然而,我期望在Laravel层面上有一个包装器/单一命令来处理这种情况。谢谢。 - Yevgeniy Afanasyev
1
如果有数据,就不能删除它,那我怎么再次获取数据呢?在这种情况下,应该创建一个新列,然后编写一个脚本将旧列中的数据复制到新列中,然后删除旧列,但这不是最好的方法,这是我的意见。我们可以安装:composer require doctrine/dbal然后很容易进行更改:$table->foreignId('table_two_id') ->nullable()->change() - Abdlrahman Saber
1
这在生产环境下运行不会很危险吗? - Dazzle

10

Christopher K.说得对,Laravel文档中写道:

要删除外键,可以使用dropForeign方法。外键约束遵循与索引相同的命名约定。因此,我们将把表名和约束中的列连接起来,然后在名称后缀中添加"_foreign"

$table->dropForeign('posts_user_id_foreign'); 

或者,您可以传递一个数组值,当删除时会自动使用传统的约束名称:

$table->dropForeign(['user_id']);

https://laravel.com/docs/5.7/migrations#foreign-key-constraints


谢谢您的回答,但是这种命名约定既不是强制性的,也不是可靠的。我经常遇到 foreign_key_name_length 的限制,并且重命名列并不会重命名依赖的外键。所以我很满意 @Borut Flis 的答案。 - Yevgeniy Afanasyev

5
您需要删除这个。
     public function up()
    {
        Schema::table('<tableName>', function (Blueprint $table) {
            $table->dropForeign('<FK-name>');
            $table->dropColumn('<FK-columnName>');
        });
        Schema::table('<tableName>', function (Blueprint $table) {
            $table->foreignId('<FK-columnName>')->constrained()->cascadeOnDelete();
        });

    }

使用两个查询。正在使用 Laravel 8


5
  1. composer require doctrine/dbal
  2. 在您的迁移文件中,执行以下操作:
    Schema::table('table_one', function (Blueprint $table) {
        $table->foreignId('table_two_id')
              ->change()
              ->constrained('table_two')
              ->onDelete('cascade');
    });
  1. php artisan migrate

2
当通过重新定义“constrained”更新外键时,将引发错误“SQLSTATE [23000]:完整性约束冲突:1022无法写入;表中的重复键...”,因此只需删除“constrained”并说出您只需要更新并将其与“->change()”链接即可。在我的情况下,我只是将外键更新为可为空,我不需要重新定义约束,因为它应该在创建迁移时调用,而不是在更改迁移中调用,除非您想要将约束更改为另一个表。 - fsevenm

-18

如何通过控制器实现

1- 设置路由:
Route::get('foreignkeyforimg', "foreignkey@index"); 2- 创建带有外键名称的控制器。
3- 外键控制器继承自迁移类。
4- 进入数据库并手动从表中删除旧的主键。

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

class Foreignkey extends Migration
{
    function index(){

        Schema::table('images', function (Blueprint $table) {


            $table->foreign('sub_cat_id')
               ->references('id')
                ->on('subcategories')
                ->onDelete('cascade');
        });
    }
}

3
你能解释一下为什么有人应该使用控制器吗?而且你所说的“去数据库删除”是什么意思?如果你为这样的东西编写迁移,为什么还要手动运行呢? - Nico Haase
因为通过迁移可能会影响其他数据库表。这是更新任何表的外键的简单方法,对于新手来说非常简单。 - Ajmal Sarim
3
请通过编辑您的答案进一步解释:您所说的“受伤”是什么意思?大多数主要的PHP脚本在迁移中运行此类内容,我从未听说过更改索引会对任何数据库造成损害。 - Nico Haase
如果外键已经存在,你的函数不会进行更新,而是会创建一个新的外键。这个问题是关于如何更新外键的。 - Yevgeniy Afanasyev
阅读第4点... 4- 进入数据库并手动从表中删除旧的主键。 - Ajmal Sarim
这个回答太搞笑了。 - BozanicJosip

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接