Laravel多对多关系下按最新状态筛选订单异常问题
解决方案
1. 优化Order模型关联
在Order模型中新增关联,专门获取订单的最新状态记录:
// Order.php public function latestStatus() { return $this->hasOne(OrderStatus::class)->latest('created_at'); }
注:若未创建OrderStatus模型(对应order_status表),建议补充创建,便于后续查询操作。
2. 正确筛选最新状态的订单
要确保筛选的是每条订单的最新状态,而非旧状态,可通过以下两种方式实现:
方法一:子查询筛选
$targetStatusId = 2; // 目标状态ID $orders = Order::query() ->with(['latestStatus.status']) // 预加载最新状态及关联的Status模型 ->whereHas('latestStatus', function ($query) use ($targetStatusId) { $query->where('status_id', $targetStatusId); }) ->paginate(13);
方法二:Join关联最新状态记录
若追求更高查询效率,可通过Join关联最新状态的子查询结果:
$targetStatusId = 2; $orders = Order::query() ->select('orders.*') ->joinSub( OrderStatus::select('order_id', 'status_id') ->selectRaw('MAX(created_at) as latest_created') ->groupBy('order_id'), 'latest_order_status', function ($join) { $join->on('orders.id', '=', 'latest_order_status.order_id'); } ) ->join('order_status', function ($join) { $join->on('orders.id', '=', 'order_status.order_id') ->on('order_status.created_at', '=', 'latest_order_status.latest_created'); }) ->where('order_status.status_id', $targetStatusId) ->with(['latestStatus.status']) ->paginate(13);
3. 修复分页异常问题
之前分页仅返回最后一批数据,核心原因是查询逻辑错误地对关联表记录分页,而非主订单表。上述两种方法均基于Order模型查询构建器调用paginate(),会正确对订单数据分页,每页返回13条符合条件的订单。
关键注意点
- 必须确保筛选条件针对每条订单的最新状态记录,否则会出现筛选出含旧状态订单的问题;
- 使用
with(['latestStatus.status'])预加载关联数据,可避免N+1查询,提升性能。
内容的提问来源于stack exchange,提问作者Jafrul tripto
相关产品推荐
相关产品推荐

