Laravel使用嵌套with关联truckHistory与trukInvoice报错如何解决
问题原因&修正方案
核心错误点
- 关联定义位置错误:
trukInvoice关联放错了模型。该关联依赖invoice_details表的invoice_id字段,应该定义在InvoiceDetail模型中,而不是Truck模型中。 - 控制器查询逻辑错误:
Truck::find($id)会直接执行SQL返回对应id的模型实例,后续调用with()会重新开启查询构造器,最后的first()会返回trucks表的第一条数据,完全不符合需求。 - 预加载写法冗余:嵌套预加载无需写闭包,Laravel支持
关联.子关联的语法直接加载多级关联。
修正步骤
1. 调整关联定义
将Truck模型中的trukInvoice方法迁移到InvoiceDetail模型中:
// app/Models/InvoiceDetail.php 新增关联 public function trukInvoice() { return $this->belongsTo(Invoice::class, 'invoice_id', 'id'); }
删除Truck模型中原本的trukInvoice方法。
2. 修正控制器查询代码
public function getTruck($id) { // 直接使用嵌套预加载语法加载关联 $truck = Truck::with('truckHistory.trukInvoice')->find($id); return $truck; }
如果需要给truckHistory加额外查询条件,再使用闭包写法:
public function getTruck($id) { $truck = Truck::with([ 'truckHistory' => function($query) { // 此处可加自定义查询条件,例:$query->where('created_at', '>', '2024-01-01'); $query->with('trukInvoice'); } ])->find($id); return $truck; }
额外优化建议
你当前定义的getCompanyNameAttribute访问器中,$this->companys()->first()->name每次调用都会触发新的SQL查询,存在N+1性能问题。建议修改为:
public function getCompanyNameAttribute() { return optional($this->companys)->name; }
查询时同步预加载companys关联即可:Truck::with(['companys', 'truckHistory.trukInvoice'])->find($id);
内容的提问来源于stack exchange,提问作者Tuana
相关产品推荐
相关产品推荐

