Laravel循环读取Seen模型属性报"Attempt to read property on null"错误
问题分析与解决
错误「Attempt to read property "seen" on null」的核心原因是:并非每个Rome的uuid都在Seen表中有对应记录。你循环外测试的是存在对应记录的uuid(比如IcHshOP2V),所以能正常运行,但循环遍历所有romeids时,遇到没有对应Seen记录的uuid,first()会返回null,直接访问$seen->seen就会触发错误。
修复步骤
1. 立即修复:增加空值检查
在访问$seen的属性前,先判断它是否存在:
foreach ($romeids as $uuid) { $seen = Seen::where('message', $uuid) ->where('user', $user) ->first(); // 先判断$seen是否存在,不存在则跳过当前循环 if (!$seen) { continue; } $wasseen = $seen->seen; if ($seen->seen === 0) { $seen->seen = 1; $seen->seen_at = Carbon::now(); $seen->save(); } }
2. 性能优化:避免N+1查询
循环内每次执行数据库查询会导致N+1性能问题,建议先批量查询所有相关Seen记录,再在内存中匹配:
$user = Auth::id(); $romes = Rome::where('room', $request->id)->get(); $romeids = $romes->pluck('uuid')->toArray(); // 批量获取当前用户的所有相关Seen记录,并用uuid作为键快速查找 $seenRecords = Seen::whereIn('message', $romeids) ->where('user', $user) ->get() ->keyBy('message'); foreach ($romeids as $uuid) { $seen = $seenRecords->get($uuid); if (!$seen) { continue; } $wasseen = $seen->seen; if ($seen->seen === 0) { $seen->seen = 1; $seen->seen_at = Carbon::now(); $seen->save(); } }
3. 可选:自动创建缺失的Seen记录
如果需要确保每个Rome消息都有对应的Seen记录,可以在查询不到时自动创建:
foreach ($romeids as $uuid) { // 用firstOrCreate自动创建缺失的记录,可自定义默认值 $seen = Seen::firstOrCreate( ['message' => $uuid, 'user' => $user], ['seen' => 1, 'seen_at' => Carbon::now()] ); $wasseen = $seen->seen; if ($seen->seen === 0) { $seen->seen = 1; $seen->seen_at = Carbon::now(); $seen->save(); } }
另外注意:你当前返回的$wasseen只会保留循环最后一次的值,若需要返回所有消息的已读状态,建议将结果存入数组后再返回。
内容的提问来源于stack exchange,提问作者eddbreuer
相关产品推荐
相关产品推荐

