Laravel关联查询返回错误ID问题求助
兄弟我太懂你这种眼看代码逻辑没问题但结果抽风的崩溃感了!咱们直接说问题出在哪:
你同时用了join('users')和with('user'),而records和users两张表都有id字段。当执行join查询时,SQL返回的结果集里,users.id会覆盖掉records.id(因为字段名重复,数据库会保留最后出现的那个值),而Laravel的Record模型会直接把这个返回的id赋值给自己的id属性,所以就出现了“记录id变成用户id”的诡异情况。
而且其实你这里的join完全是多余的!with('user')已经是预加载用户关联了,排序完全可以通过Eloquent的关联查询来实现,不用硬怼join。下面给你两种靠谱的解决办法:
方法一:用关联子查询排序(推荐,更贴合Eloquent用法)
直接去掉join,通过子查询来按用户名称排序:
$records = Record::with('user') ->where('schedule_id', $schedule->id) ->orderBy(User::select('name') ->whereColumn('users.id', 'records.user_id') ) ->get();
这种方式既保留了预加载的性能优势,又能实现按用户名称排序,还完全避免了字段冲突的问题。
方法二:如果一定要用join,明确指定查询字段
要是你非得用join不可,那就要手动指定要查询的字段,确保records.id不会被覆盖:
$records = Record::with('user') ->select('records.*', 'users.name as user_name') // 只选择records的所有字段,按需添加users的字段并起别名 ->join('users', 'users.id', '=', 'records.user_id') ->orderBy('users.name', 'asc') ->where('schedule_id', $schedule->id) ->get();
这里通过select('records.*')明确保留了records表的所有字段,再额外选择需要的users字段(比如name)并起别名,这样返回的结果里id就还是记录的id,不会被用户id覆盖。
另外再提一句:with('user')和join一起用的时候,with的预加载其实是多做了一次查询(因为join已经把用户数据查出来了),如果用方法二的话,其实可以去掉with('user'),直接从查询结果的别名字段里取用户数据,或者继续保留但不会有问题,只是多了一次查询而已。
内容的提问来源于stack exchange,提问作者Poxxac

