You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel无法将外键deleted_by设为NULL的问题求助

Laravel 外键字段deleted_by已设nullable但仍无法存入NULL

尝试将外键字段deleted_by设为NULL,但该字段不允许保存NULL作为值。使用工厂生成Product时因无法设置该字段为NULL导致数据库填充失败,报错信息如下:

PDOException::("SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'deleted_by' cannot be null")

相关代码

Product 表迁移代码

Schema::create('products', function (Blueprint $table) {
    $table->id();
    $table->string('title', 2000);
    $table->string('slug', 2000);
    $table->string('image', 2000)->nullable();
    $table->string('image_mime')->nullable();
    $table->integer('image_size')->nullable();
    $table->longText('description')->nullable();
    $table->decimal('price', 10, 2);
    $table->foreignId('created_by')->references('id')->on('users')->nullable();
    $table->foreignId('updated_by')->references('id')->on('users')->nullable();
    $table->softDeletes();
    $table->foreignId('deleted_by')->references('id')->on('users')->nullable()->constrained();
    $table->timestamps();
});

User 表迁移代码

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();
});

Product 工厂代码

public function definition()
{
    return [
        'title' => fake()->text(),
        'image' =>fake()->imageUrl(),
        'description' => fake()->realText(200),
        'price' => fake()->randomFloat(2, 2, 5),
        'created_at' => now(),
        'updated_at' => now(),
        'created_by' => 1,
        'updated_by' => 1,
        'deleted_by' => NULL,
    ];
}

解决办法

1. 修正迁移文件的外键定义顺序

Laravel中constrained()方法会自动处理外键约束,但如果先调用nullable()再调用constrained(),可能导致nullable设置被覆盖。调整方法顺序或拆分字段与外键定义:

方案A:调整方法调用顺序

// 原代码
$table->foreignId('deleted_by')->references('id')->on('users')->nullable()->constrained();

// 修改为
$table->foreignId('deleted_by')->constrained()->nullable();

方案B:拆分字段与外键定义

如果方案A无效,可拆分为两步定义:

// 先定义可为空的字段
$table->unsignedBigInteger('deleted_by')->nullable();
// 再单独添加外键约束
$table->foreign('deleted_by')->references('id')->on('users');

2. 更新数据库表结构

修改迁移文件后,需执行迁移更新表结构:

  • 开发环境可直接刷新迁移(会清空数据):
php artisan migrate:refresh
  • 生产环境建议创建新迁移文件修改字段:
php artisan make:migration update_deleted_by_column_in_products_table

新迁移文件内容:

public function up()
{
    Schema::table('products', function (Blueprint $table) {
        $table->dropForeign(['deleted_by']);
        $table->unsignedBigInteger('deleted_by')->nullable()->change();
        $table->foreign('deleted_by')->references('id')->on('users');
    });
}

public function down()
{
    Schema::table('products', function (Blueprint $table) {
        $table->dropForeign(['deleted_by']);
        $table->unsignedBigInteger('deleted_by')->nullable(false)->change();
        $table->foreign('deleted_by')->references('id')->on('users');
    });
}

执行迁移:

php artisan migrate

3. 优化工厂定义

确认字段允许NULL后,工厂中可省略deleted_by字段(Laravel自动用NULL填充),或显式设置为小写null(符合PHP规范):

public function definition()
{
    return [
        'title' => fake()->text(),
        'image' => fake()->imageUrl(),
        'description' => fake()->realText(200),
        'price' => fake()->randomFloat(2, 2, 5),
        'created_at' => now(),
        'updated_at' => now(),
        'created_by' => 1,
        'updated_by' => 1,
        'deleted_by' => null,
    ];
}

内容的提问来源于stack exchange,提问作者daniel davies

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 06:35:19