Laravel同表外键问题:添加分类触发完整性约束错误
分类表外键约束错误的解决方案
问题场景
我拥有名为laravelpro的数据库,其中categories表的创建迁移代码如下:
Schema::create('categories', function (Blueprint $table) { $table->id(); $table->string('name'); $table->unsignedBigInteger('parent')->default(0); $table->foreign('parent')->references('id')->on('categories')->onDelete('cascade'); $table->timestamps(); });
该表通过parent字段实现分类的父子层级结构,将parent设为外键关联自身id字段,目的是删除父分类时级联删除其子分类。迁移执行无报错,但添加分类时触发如下错误:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`laravelpro`.`categories`, CONSTRAINT `categories_parent_foreign` FOREIGN KEY (`parent`) REFERENCES `categories` (`id`) ON DELETE CASCADE) INSERT INTO `categories` (`name`, `parent`, `updated_at`, `created_at`) VALUES (test, 0, 2022-10-06 20:33:41, 2022-10-06 20:33:41)
原因分析
外键约束要求parent字段的值必须存在于categories表的id字段中,但id是自增主键,默认从1开始递增,而你设置parent的默认值为0,插入时0并不存在于id的有效取值范围内,因此触发了完整性约束错误。
解决方案
方案一:将parent字段设为可空(推荐)
修改迁移代码,把parent字段改为可空类型,默认值设为null,用null标识顶级分类:
Schema::create('categories', function (Blueprint $table) { $table->id(); $table->string('name'); // 改为可空的无符号大整数,默认值为null $table->unsignedBigInteger('parent')->nullable()->default(null); $table->foreign('parent')->references('id')->on('categories')->onDelete('cascade'); $table->timestamps(); });
如果已经执行过初始迁移,需要创建新的迁移文件来修改字段:
Schema::table('categories', function (Blueprint $table) { $table->unsignedBigInteger('parent')->nullable()->default(null)->change(); });
执行迁移后,插入顶级分类时parent传null即可,不会触发外键约束错误。
方案二:预先插入id为0的分类记录
如果必须使用0作为顶级分类的标识,可以在迁移完成后,手动插入一条id为0的分类记录:
INSERT INTO `categories` (`id`, `name`, `parent`, `created_at`, `updated_at`) VALUES (0, '顶级分类', 0, NOW(), NOW());
后续插入其他分类时,parent设为0就符合外键约束了。不过这种方式违背了自增主键的常规使用逻辑,不推荐采用。
内容的提问来源于stack exchange,提问作者Erfan Poursina
相关产品推荐
相关产品推荐

