Laravel Eloquent迁移合并字段后仍查找原字段,求排查解决
迁移Laravel Blocks表后仍提示查找page_id字段的问题
问题背景
我编写了两个Laravel Eloquent迁移:
- 第一个迁移为
blocks表新增parent_id和parent_type字段,并从该表的page_id、post_id、event_id、global_id四个互斥字段(同一时刻仅一个非空)取值填充,代码如下:
public function up() { Schema::table('blocks', function (Blueprint $table) { $table->integer('parent_id')->nullable()->after('type'); $table->string('parent_type')->nullable()->after('parent_id'); }); $blocks = Block::select('id', 'page_id', 'post_id', 'event_id', 'global_id')->get(); foreach ($blocks as $block) { if ($block['post_id'] !== null) { $block->parent_id = $block['post_id']; $block->parent_type = 'post'; } elseif ($block['page_id'] !== null) { $block->parent_id = $block['page_id']; $block->parent_type = 'page'; } elseif ($block['event_id'] !== null) { $block->parent_id = $block['event_id']; $block->parent_type = 'post'; } elseif ($block['global_id'] !== null) { $block->parent_id = $block['global_id']; $block->parent_type = 'global'; } else { $block->parent_id = null; } $block->save(); } }
- 第二个迁移用于删除四个原字段,代码如下:
public function up() { Schema::table('blocks', function (Blueprint $table) { $table->dropColumn('page_id'); $table->dropColumn('post_id'); $table->dropColumn('event_id'); $table->dropColumn('global_id'); }); }
模型关联代码如下:
- Block.php:
public function blocks() { return $this->hasMany('App\Block')->orderby('section'); }
- Page.php:
public function page() { return $this->belongsTo('App\Page', 'parent_id'); }
我已替换代码库中所有对原字段的引用,但Laravel仍提示查找block.page_id。请问当前迁移方式是否正确?该如何解决此问题?
问题分析与解决方法
迁移方式的合理性
迁移逻辑本身没问题,但拆分两个迁移会存在中间状态风险:执行完第一个迁移后,旧字段仍存在,若此时有代码/队列任务依赖旧字段逻辑,或缓存未更新,会引发后续报错。另外第一个迁移中event_id映射的parent_type写成post是明显笔误,需修正为event。
具体解决步骤
1. 修正模型关联的错误
当前关联定义不符合多态关联的规范,这很可能是报错的核心原因:
- Block模型需添加多态关联方法:
// Block.php public function parent() { return $this->morphTo(); } - Page/Post/Event模型需对应添加
morphMany关联:
原Page.php中的// Page.php public function blocks() { return $this->morphMany(Block::class, 'parent'); }page()关联方法名混淆且逻辑错误,直接删除即可。
2. 清理所有缓存
Laravel的缓存可能保留了旧的模型结构或关联定义,执行以下命令清理:
php artisan cache:clear php artisan config:clear php artisan route:clear php artisan view:clear
若使用了OPcache或PHP-FPM,重启Web服务器/PHP-FPM,确保新代码生效;若有队列服务,重启队列Worker,避免旧任务残留。
3. 检查遗留代码
- 搜索代码库中是否存在硬编码SQL查询(如
DB::select)仍引用page_id等旧字段,这类查询不会被模型关联覆盖,需手动替换为parent_id+parent_type的条件。 - 检查Blade模板、API返回等场景是否有遗漏的
$block->page_id调用。
4. 优化迁移(可选但推荐)
将两个迁移合并为一个,避免中间状态的风险,同时优化数据更新效率(用批量更新替代循环save):
public function up() { Schema::table('blocks', function (Blueprint $table) { $table->integer('parent_id')->nullable()->after('type'); $table->string('parent_type')->nullable()->after('parent_id'); }); // 分批处理数据,避免内存溢出 Block::chunk(100, function ($blocks) { foreach ($blocks as $block) { $updateData = []; if ($block->post_id) { $updateData = ['parent_id' => $block->post_id, 'parent_type' => 'post']; } elseif ($block->page_id) { $updateData = ['parent_id' => $block->page_id, 'parent_type' => 'page']; } elseif ($block->event_id) { $updateData = ['parent_id' => $block->event_id, 'parent_type' => 'event']; // 修正笔误 } elseif ($block->global_id) { $updateData = ['parent_id' => $block->global_id, 'parent_type' => 'global']; } if (!empty($updateData)) { Block::where('id', $block->id)->update($updateData); } } }); Schema::table('blocks', function (Blueprint $table) { $table->dropColumn(['page_id', 'post_id', 'event_id', 'global_id']); }); } public function down() { // 回滚逻辑,重新创建旧字段并恢复数据 Schema::table('blocks', function (Blueprint $table) { $table->integer('page_id')->nullable(); $table->integer('post_id')->nullable(); $table->integer('event_id')->nullable(); $table->integer('global_id')->nullable(); }); Block::chunk(100, function ($blocks) { foreach ($blocks as $block) { $updateData = []; match ($block->parent_type) { 'page' => $updateData['page_id'] = $block->parent_id, 'post' => $updateData['post_id'] = $block->parent_id, 'event' => $updateData['event_id'] = $block->parent_id, 'global' => $updateData['global_id'] = $block->parent_id, }; if (!empty($updateData)) { Block::where('id', $block->id)->update($updateData); } } }); Schema::table('blocks', function (Blueprint $table) { $table->dropColumn(['parent_id', 'parent_type']); }); }
内容的提问来源于stack exchange,提问作者octaviandd
相关产品推荐
相关产品推荐

