Laravel 9中如何仅通过中间表外键实现HasManyThrough关联?
原生Laravel实现方案
针对你的两个需求,利用Laravel原生的belongsToMany关联即可实现,无需依赖外部扩展。本质上用户与商品是多对多关系,订单表作为中间关联表承载两者的关联关系及额外订单字段。
1. 获取指定用户的所有下单商品
在User模型中定义与Item的多对多关联,指定订单表作为中间表:
// app/Models/User.php public function orderedItems() { return $this->belongsToMany(Item::class, 'orders', 'user_id', 'item_id') ->using(Order::class) // 关联中间模型Order ->withPivot('id', 'created_at', 'quantity') // 按需携带订单表字段 ->distinct(); // 去重,避免同一商品因多次购买重复出现 }
查询示例:
// 获取ID为1的用户所有下单商品 $user = User::find(1); $orderedItems = $user->orderedItems; // 带条件查询(比如筛选30天内下单的商品) $recentOrderedItems = $user->orderedItems() ->where('orders.created_at', '>=', now()->subDays(30)) ->get();
2. 获取指定商品的所有下单用户
在Item模型中定义与User的反向多对多关联:
// app/Models/Item.php public function buyers() { return $this->belongsToMany(User::class, 'orders', 'item_id', 'user_id') ->using(Order::class) ->withPivot('id', 'created_at', 'quantity') ->distinct(); }
查询示例:
// 获取ID为5的商品所有下单用户 $item = Item::find(5); $buyers = $item->buyers; // 带条件查询(比如筛选已支付的下单用户) $paidBuyers = $item->buyers() ->where('orders.is_paid', true) ->get();
方案优势
- 完全基于Laravel原生关联,无需引入外部依赖
- 支持关联缓存、链式查询、预加载等Eloquent特性,性能更优
- 通过
withPivot可直接获取订单表的额外字段,满足业务扩展需求 - 若无需去重(如统计用户重复购买记录),只需移除
distinct()方法即可
内容的提问来源于stack exchange,提问作者Rusurano
相关产品推荐
相关产品推荐

