Laravel 5.5中push()方法第二次无法推送关联数据问题
解决Laravel中
push()方法第二次保存关联数据失效的问题 看起来你遇到了Laravel里用push()保存带关联关系的记录时,首次正常但第二次失效的问题。我来帮你拆解下可能的原因和对应的解决办法:
核心问题分析
你代码里直接从Session取出$leaveGenerate实例来复用,这很可能是问题的根源:
- Laravel模型实例会缓存已加载的关联关系,第一次保存后,关联数据的状态会被存在实例里
- 第二次取出Session中的旧实例时,关联关系可能还是第一次保存后的状态,即使你在
setStatus里修改了关联属性,模型可能没把这些变化标记为「脏数据」,导致push()认为关联不需要更新 - Session中持久化模型实例本身就容易引发状态不一致的问题,因为模型的内部状态(比如加载的关联、脏属性)会被序列化存储,再次取出时和数据库实际数据可能不同步
解决方案
1. 避免在Session中存完整模型实例(最佳实践)
只存模型ID,每次从数据库重新获取新鲜实例,彻底避免缓存和状态不一致的问题:
// 存储时只存ID(替换你之前存完整模型的代码) Session::put('_leave-generation', $leaveGenerate->id); // 在store方法中取出并重新获取实例 public function store(Request $request) { if (Session::has('_leave-generation')) { $ids = $request->input('id'); $data = $request->input('data'); // 从数据库获取最新实例,并预加载关联 $leaveGenerate = LeaveGeneration::with('items')->findOrFail(Session::get('_leave-generation')); $leaveGenerate->fill($data); $this->leaveGenerationItemService->setStatus($ids, $leaveGenerate); // 此时push()会正确识别关联的变化并保存 $leaveGenerate->push(); } }
2. 确保关联模型被标记为脏数据
如果一定要复用Session中的模型实例,在修改关联属性后,要手动标记模型为脏,或者直接保存关联模型:
// 在你的leaveGenerationItemService的setStatus方法里修改 public function setStatus($ids, $leaveGenerate) { foreach ($leaveGenerate->items as $item) { if (in_array($item->id, $ids)) { $item->status = '你的目标状态'; // 手动保存单个关联模型,或者标记为脏 $item->save(); // 或者用$item->touch(); 如果你只是需要触发更新时间,让push()识别到变化 } } // 更高效的方式:批量更新关联模型(不需要遍历) // $leaveGenerate->items()->whereIn('id', $ids)->update(['status' => '你的目标状态']); }
3. 手动刷新关联关系
如果坚持用Session实例,在修改前重新加载关联,确保拿到最新的数据:
public function store(Request $request) { if (Session::has('_leave-generation')) { $ids = $request->input('id'); $data = $request->input('data'); $leaveGenerate = Session::get('_leave-generation'); // 重新加载关联,覆盖缓存的旧数据 $leaveGenerate->load('items'); $leaveGenerate->fill($data); $this->leaveGenerationItemService->setStatus($ids, $leaveGenerate); $leaveGenerate->push(); } }
额外提醒
push()方法的工作逻辑是:保存主模型,然后遍历所有**已加载且被修改(脏)**的关联模型并保存。如果关联没被加载,或者没有属性变化,push()会跳过它们,这点要特别注意。
内容的提问来源于stack exchange,提问作者Kosal
相关产品推荐
相关产品推荐

