在Laravel中如何使用Eloquent排除无关联销售记录的库存商品?
Eloquent实现库存商品按最新销售记录排序方案
需求为筛选有销售记录的商品、按最新销售时间排序,以下两种实现方式均可:
一、优化你现有JOIN写法
你原有代码逻辑没问题,但存在两个兼容风险:
- 若MySQL开启了
ONLY_FULL_GROUP_BY严格模式,仅按inventory_sell_records.product_id分组会触发字段不兼容报错 - 直接拼接
$order_by变量存在SQL注入风险
优化后代码:
// 提前校验排序方向,仅允许asc/desc $orderDirection = in_array(strtolower($order_by), ['asc', 'desc']) ? $order_by : 'desc'; $inventory = Inventory::where('inventory.client_id', $user->client_id) ->join('inventory_sell_records', 'inventory_sell_records.product_id', '=', 'inventory.id') // 按库存表主键分组,兼容SQL严格模式校验 ->groupBy('inventory.id') // 用参数绑定传入排序方向,避免注入风险 ->orderByRaw("MAX(inventory_sell_records.created_at) ?", [$orderDirection]) ->paginate(100);
二、更符合Eloquent规范的关联写法
无需手动编写JOIN逻辑,代码可读性和可维护性更高,首先先在Inventory模型中定义一对多关联:
// app/Models/Inventory.php public function sellRecords() { return $this->hasMany(SellRecord::class, 'product_id', 'id'); }
后续查询直接调用关联方法即可:
$orderDirection = in_array(strtolower($order_by), ['asc', 'desc']) ? $order_by : 'desc'; $inventory = Inventory::where('client_id', $user->client_id) // 自动排除无销售记录的商品 ->whereHas('sellRecords') // 关联查询获取该商品最新的销售记录时间,生成字段latest_sold_at ->withMax('sellRecords as latest_sold_at', 'created_at') // 按最新销售时间排序 ->orderBy('latest_sold_at', $orderDirection) ->paginate(100);
该写法优势:
- 无需手动处理关联逻辑,Eloquent自动生成查询语句
- 天然兼容SQL严格模式,不会出现分组报错
- 查询结果附带
latest_sold_at字段,可直接用于前端展示最新销售时间 - 配合排序方向白名单校验,完全避免SQL注入风险
内容的提问来源于stack exchange,提问作者bohdan baida
相关产品推荐
相关产品推荐

