Laravel关联查询中如何基于new_notifications关联数据实现分页?
问题与解决方案
问题背景
需要查询角色ID为3、且关联的property_managements存在new_notifications的用户及关联数据,核心需求是基于new_notifications数据进行整体分页(而非对用户列表分页)。但尝试在关联闭包中使用paginate(10)无法实现预期效果,仍返回全部用户数据。
原查询代码:
$users = User::whereHas('role', function ($q) { $q->where('role_id', 3); }) ->with(['property_managements.new_notifications.type']) ->with(['property_managements.new_notifications' => function ($q){ $q->orderBy('notification_date', 'desc'); }]) ->with(['property_managements' => function ($q) { $q->whereHas('new_notifications'); }]) ->whereHas('property_managements.new_notifications') ->get();
无效的分页尝试:
->with(['property_managements.new_notifications' => function ($q){ $q->orderBy('notification_date', 'desc') ->paginate(10); }])
可行解决方案
方案1:以new_notifications为主模型实现全局分页
既然目标是对通知数据进行整体分页,直接从NewNotification模型出发构建查询是最直接的方案,同时关联所需的用户、物业及通知类型信息,过滤符合角色要求的用户:
$notifications = NewNotification::with([ 'property_management.user.role', 'type' ]) ->whereHas('property_management.user.role', function ($q) { $q->where('role_id', 3); }) ->orderBy('notification_date', 'desc') ->paginate(10);
如果需要将分页后的通知按用户分组展示,可通过集合处理:
$groupedByUser = $notifications->groupBy('property_management.user.id');
方案2:按用户维度实现通知分页
若必须以User作为查询入口,且需要为每个用户单独分页其关联通知,可先获取符合条件的用户,再手动加载分页后的通知(注意配合预加载避免N+1查询):
- 获取目标用户:
$users = User::whereHas('role', fn($q) => $q->where('role_id', 3)) ->whereHas('property_managements.new_notifications') ->with(['property_managements' => fn($q) => $q->whereHas('new_notifications')]) ->get();
- 为每个用户加载分页通知:
$users->each(function ($user) { $user->load(['property_managements.new_notifications' => fn($q) => $q->orderBy('notification_date', 'desc')->paginate(10) ]); });
方案3:利用关联关系实现用户维度的通知分页(Laravel 8+)
在User模型中定义跨表关联allNotifications,然后通过该关联加载分页后的通知:
首先在User模型中添加关联:
public function allNotifications() { return $this->hasManyThrough( NewNotification::class, PropertyManagement::class, 'user_id', // PropertyManagement表关联User的字段 'property_management_id', // NewNotification表关联PropertyManagement的字段 'id', // User表主键 'id' // PropertyManagement表主键 ); }
然后执行查询:
$users = User::whereHas('role', fn($q) => $q->where('role_id', 3)) ->whereHas('allNotifications') ->with(['allNotifications.type' => fn($q) => $q->orderBy('notification_date', 'desc')->paginate(10) ]) ->get();
内容的提问来源于stack exchange,提问作者Chippy Thomas
相关产品推荐
相关产品推荐

