Laravel 8迁移报错:无法创建category_menu表(外键约束错误)
解决Laravel迁移中“Foreign key constraint is incorrectly formed”错误
这个错误我之前在做Laravel关联表迁移时也碰到过,核心问题是外键字段的类型和关联表的主键类型不匹配,咱们来拆解下你的代码问题:
问题根源
- 你的
menus表用了$table->id(),在Laravel里这个方法默认生成的是bigint unsigned类型的主键; - 但
category_menu中间表里的menu_id用的是integer()(对应MySQL的int类型),两者类型不兼容,MySQL没办法创建合法的外键约束,所以抛出了这个错误。 - 顺带提一句,你的
categories表用的是$table->increments('id')(对应int unsigned类型),category_menu里的category_id是integer()->unsigned(),这部分是匹配的,没问题。
修复方案
1. 修正外键字段类型(最小改动)
只需要把category_menu里的menu_id字段类型改成和menus表主键一致的unsignedBigInteger:
// 把原来的这行 $table->integer('menu_id')->unsigned()->nullable(); // 改成 $table->unsignedBigInteger('menu_id')->nullable();
2. (推荐)统一所有表的主键类型
为了避免后续再出现类似问题,建议把categories表的主键也改成$table->id()(和menus保持一致的bigint unsigned),同时对应修改category_menu里的category_id类型:
// categories表的主键修改 $table->id(); // 替换原来的$table->increments('id'); // category_menu里的category_id修改 $table->unsignedBigInteger('category_id')->nullable(); // 替换原来的integer类型
3. (可选优化)中间表用联合主键
对于多对多关联的中间表,其实不需要单独的自增id,用menu_id和category_id组成联合主键更合理,还能避免重复关联:
Schema::create('category_menu', function (Blueprint $table) { // 移除自增id $table->unsignedBigInteger('menu_id')->nullable(); $table->foreign('menu_id')->references('id')->on('menus')->onDelete('cascade'); $table->unsignedBigInteger('category_id')->nullable(); $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade'); // 设置联合主键 $table->primary(['menu_id', 'category_id']); $table->timestamps(); });
完整修改后的迁移代码
Schema::create('menus', function (Blueprint $table) { $table->id(); $table->string('name')->unique(); $table->string('slug')->unique(); $table->integer('price'); $table->text('description'); $table->timestamps(); }); Schema::create('categories', function (Blueprint $table) { $table->id(); $table->string('name')->unique(); $table->string('slug')->unique(); $table->timestamps(); }); Schema::create('category_menu', function (Blueprint $table) { $table->unsignedBigInteger('menu_id')->nullable(); $table->foreign('menu_id')->references('id')->on('menus')->onDelete('cascade'); $table->unsignedBigInteger('category_id')->nullable(); $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade'); $table->primary(['menu_id', 'category_id']); $table->timestamps(); });
后续操作
如果已经执行过之前的迁移,先运行php artisan migrate:rollback回滚迁移,修改代码后再执行php artisan migrate。如果回滚遇到问题,也可以直接删除数据库中已创建的这三张表,再重新执行迁移(注意备份数据);或者使用php artisan migrate:fresh(这个命令会清空所有数据库表,生产环境谨慎使用!)
内容的提问来源于stack exchange,提问作者user14777223
相关产品推荐
相关产品推荐

