Laravel Eloquent join多表后如何在select中包含with关联返回字段
Laravel Eloquent关联查询问题解决方案
1 join+select场景预加载关联结果的问题
错误原因
with()预加载是独立于主查询的二次查询机制,执行逻辑是先跑完主表查询拿到结果集,再根据主表结果的外键值查关联表,最后把关联数据挂载到对应主表模型的属性上,根本不需要在主查询的select中声明关联字段。你之前报错是因为把关联关系名manual_ticket_log当成了manual_tickets表的真实字段。
修复方案
只需要保证主查询select中保留manual_tickets.id(也就是manual_ticket_log关联用的外键对应的主表主键),删除select里错误声明的manual_tickets.manual_ticket_log as manual_ticket_log_id即可,预加载的manual_ticket_log会自动作为模型属性存在。
修复后的代码:
$display_tickets = ManualTicket::select( 'u.name as name', 'i.name as initiator', 'manual_tickets.status as status', 'manual_tickets.description as description', 'manual_tickets.location as location', 'manual_tickets.created_at as created_at', 'manual_tickets.initiator_id as initiator_id', 'manual_tickets.id as manual_ticket_id' ) ->leftJoin('users as u', 'u.id', '=', 'manual_tickets.user_id') ->leftJoin('users as i', 'i.id', '=', 'manual_tickets.initiator_id') ->where(function ($checkClients) use($target_client_id){ $checkClients->where('u.client_id', '=', $target_client_id) ->orWhere('i.client_id', '=', $target_client_id); }) ->whereBetween('manual_tickets.created_at', [$start_date->toDateString(), $end_date->addDays(1)->toDateString()]) ->with('manual_ticket_log') ->orderBy("created_at", "DESC") ->get();
查询结果中每个ManualTicket实例都会自动携带manual_ticket_log属性,你可以直接通过$ticket->manual_ticket_log访问关联数据。
2 whereHas段报错strtolower() expects parameter 1 to be string, object given问题
错误原因
orWhere()方法的第一个参数需要传入字段名字符串或者闭包,你在代码中直接把$checkClients->whereHas(...)返回的查询构造器对象作为参数传给了orWhere(),导致参数类型不符合要求报错。
修复方案
直接链式调用orWhereHas()即可,不需要额外套orWhere()包裹。
修复后的代码:
$display_tickets = ManualTicket::select('*') ->with('user', 'initiator', 'manual_ticket_log') ->where(function ($checkClients) use($target_client_id){ $checkClients->whereHas('user', function ($checkClient) use($target_client_id){ $checkClient->where('client_id', '=', $target_client_id); }) ->orWhereHas('initiator', function ($checkClient2) use($target_client_id){ $checkClient2->where('client_id', '=', $target_client_id); }); }) ->whereBetween('manual_tickets.created_at', [$start_date->toDateString(), $end_date->addDays(1)->toDateString()]) ->orderBy("created_at", "DESC") ->get();
内容的提问来源于stack exchange,提问作者Yeo Bryan
相关产品推荐
相关产品推荐

