You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中不使用Join过滤hasMany关联:子父字段匹配/不匹配

解决方案:无需Join实现HasMany关联的跨模型字段筛选

要实现子模型字段与父模型字段匹配/不匹配的筛选,同时避免Join带来的关联字段丢失问题,直接用Laravel查询构建器的whereColumn方法即可,无需手动Join:

修改Order模型的关联方法

class Order extends Model
{
    public function items()
    {
        return $this->hasMany(OrderItem::class, 'order_id', 'id');
    }

    public function items_removed_by_store()
    {
        return $this->hasMany(OrderItem::class, 'order_id', 'id')
            ->onlyTrashed()
            // 直接对比子模型与父模型的字段,无需Join
            ->whereColumn('order_item.deleted_by', '!=', 'order.customer_id');
    }

    public function items_removed_by_customer()
    {
        return $this->hasMany(OrderItem::class, 'order_id', 'id')
            ->onlyTrashed()
            ->whereColumn('order_item.deleted_by', '=', 'order.customer_id');
    }
}

原理说明

  • whereColumn方法支持直接对比不同表的字段,Laravel会自动处理表名的关联逻辑,因为hasMany本身已经基于order_id建立了Order和OrderItem的关联关系,无需额外Join操作。
  • 这种方式不会破坏OrderItem的其他关联(比如options),因为没有用select限制返回字段,也不会因为Join导致字段覆盖或丢失。
  • 执行Location::has('orders.items_removed_by_customer')->get()时,Laravel会生成嵌套的EXISTS子查询,而非Join查询,既满足筛选需求,又能保证关联数据的完整性。

替代方案(whereRaw)

如果需要更灵活的字段对比逻辑,也可以用whereRaw实现相同效果:

// 客户移除的商品
->whereRaw('order_item.deleted_by = order.customer_id')
// 门店移除的商品
->whereRaw('order_item.deleted_by != order.customer_id')

内容的提问来源于stack exchange,提问作者MonOve

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 09:40:32