如何在Join查询中使用Eloquent的With关联查询?
问题分析与解决方案
错误原因
你在join()的闭包中调用了with()方法,而with()是Eloquent查询构建器(Illuminate\Database\Eloquent\Builder)的专属方法,并非JoinClause实例的方法,这直接导致了"Call to undefined method"错误。
修正方案
方案一:通过主查询链加载关联关系
前提是ManualTicketLog模型已定义与ManualTicket的关联:
- 在
ManualTicketLog模型中添加关联:
// app/Models/ManualTicketLog.php public function manualTicket() { return $this->belongsTo(ManualTicket::class, 'manual_ticket_id'); }
- 修改查询代码,将
with()移到主查询链上,指定加载manualTicket的prior_rerouted_ticket关联:
$manual_tickets = ManualTicketLog::select('*') ->where('manual_ticket_logs.user_id', '=', $user->id) ->where(function ($checkStatus) { $checkStatus->where('manual_ticket_logs.status', '=', 'Created') ->orWhere('manual_ticket_logs.status', '=', 'Started'); }) ->whereIn('manual_ticket_logs.id', function($q){ $q->select(DB::raw('MAX(id) FROM manual_ticket_logs WHERE (manual_ticket_logs.status != "ClockedOutUser" and manual_ticket_logs.status != "ClockedOutSupervisor" and manual_ticket_logs.status != "AssignByLocation" and manual_ticket_logs.status != "Queued") GROUP BY manual_ticket_logs.manual_ticket_id')); }) ->join('manual_tickets', function ($join) { $join->on('manual_ticket_logs.manual_ticket_id', '=', 'manual_tickets.id') ->where('manual_tickets.hidden', '=', null); // 移除此处的with()调用 }) ->select('manual_tickets.*', 'manual_ticket_logs.id as manual_ticket_logs_id') ->with(['manualTicket.prior_rerouted_ticket']) // 在此处加载关联关系 ->get();
方案二:切换查询主体为ManualTicket(更符合Eloquent设计)
如果你的核心目标是获取ManualTicket数据,直接从ManualTicket模型发起查询逻辑更清晰:
- 在
ManualTicket模型中添加关联:
// app/Models/ManualTicket.php public function logs() { return $this->hasMany(ManualTicketLog::class, 'manual_ticket_id'); }
- 重构查询代码:
$manual_tickets = ManualTicket::where('hidden', '=', null) ->whereHas('logs', function ($logQuery) use ($user) { $logQuery->where('user_id', '=', $user->id) ->where(function ($checkStatus) { $checkStatus->where('status', '=', 'Created') ->orWhere('status', '=', 'Started'); }) ->whereIn('id', function($q){ $q->select(DB::raw('MAX(id) FROM manual_ticket_logs WHERE (status != "ClockedOutUser" and status != "ClockedOutSupervisor" and status != "AssignByLocation" and status != "Queued") GROUP BY manual_ticket_id')); }); }) ->with('prior_rerouted_ticket') // 直接加载当前模型的关联 ->join('manual_ticket_logs', function ($join) use ($user) { $join->on('manual_tickets.id', '=', 'manual_ticket_logs.manual_ticket_id') ->where('manual_ticket_logs.user_id', '=', $user->id) ->where(function ($checkStatus) { $checkStatus->where('status', '=', 'Created') ->orWhere('status', '=', 'Started'); }) ->whereIn('manual_ticket_logs.id', function($q){ $q->select(DB::raw('MAX(id) FROM manual_ticket_logs WHERE (status != "ClockedOutUser" and status != "ClockedOutSupervisor" and status != "AssignByLocation" and status != "Queued") GROUP BY manual_ticket_id')); }); }) ->select('manual_tickets.*', 'manual_ticket_logs.id as manual_ticket_logs_id') ->get();
核心逻辑说明
with()的作用是预加载Eloquent模型的关联关系,它只能作用于Eloquent查询构建器实例,不能在处理SQL JOIN子句的JoinClause闭包中使用。必须将其放在主查询链上,明确指向需要加载的模型关联路径。
内容的提问来源于stack exchange,提问作者Yeo Bryan
相关产品推荐
相关产品推荐

