Laravel Eloquent条件式预加载实现:仅加载非当前用户的发送方与接收方
解决方案:Laravel Eloquent 条件式预加载
刚好碰到过类似的需求,Laravel 的 Eloquent 预加载功能支持通过闭包来添加条件,完美满足你要的「仅当指定字段不等于当前用户 ID 时才加载关联」的需求。
修改后的查询代码
首先,我们可以直接在 with() 方法中传入闭包来过滤关联模型,同时优化一下原来的 where 逻辑(用闭包包裹避免后续添加条件时出现逻辑冲突):
$userId = Auth::user()->id; $inboxs = Inbox::select("id", "sender_id", "receiver_id") ->where(function ($query) use ($userId) { $query->where('sender_id', $userId) ->orWhere('receiver_id', $userId); }) ->with(['sender' => function ($query) use ($userId) { // 仅当 sender 的 ID 不等于当前用户时加载该关联 $query->where('id', '!=', $userId); }]) ->with(['receiver' => function ($query) use ($userId) { // 仅当 receiver 的 ID 不等于当前用户时加载该关联 $query->where('id', '!=', $userId); }]) ->orderBy('id', 'desc') ->paginate(5);
代码解释
- 优化查询条件:把原来的
where + orWhere包裹在闭包里,确保后续如果添加其他where条件时,不会破坏原有的逻辑(避免出现(A OR B) AND C变成A OR (B AND C)的错误)。 - 条件预加载:在
with()的闭包中,我们给关联查询添加了where('id', '!=', $userId)的条件。这样:- 如果当前 inbox 的
sender_id等于当前用户 ID,那么 sender 关联的查询会返回空结果,Eloquent 会自动把该 inbox 对象的sender属性设为null; - 如果
sender_id不等于当前用户 ID,就会正常加载对应的用户数据。
- 如果当前 inbox 的
- 性能友好:这种方式依然是「预加载」,只会执行两次额外的关联查询(一次查所有符合条件的 sender,一次查所有符合条件的 receiver),不会出现 N+1 查询问题。
可选优化:更简洁的写法(PHP 7.4+)
如果你用的是 PHP 7.4 及以上版本,可以用短闭包让代码更简洁:
$userId = Auth::id(); $inboxs = Inbox::select("id", "sender_id", "receiver_id") ->where(fn($query) => $query->where('sender_id', $userId)->orWhere('receiver_id', $userId)) ->with(['sender' => fn($q) => $q->where('id', '!=', $userId)]) ->with(['receiver' => fn($q) => $q->where('id', '!=', $userId)]) ->orderBy('id', 'desc') ->paginate(5);
内容的提问来源于stack exchange,提问作者d3ridi
相关产品推荐
相关产品推荐

