分组Invoice集合后,如何在控制器实现关联Services表列求和
把关联表求和逻辑移到Laravel控制器的几种方案
嘿,我来帮你搞定这个问题!你现在是在视图里嵌套循环计算关联services的rate总和,想把这部分逻辑挪去控制器对吧?Laravel提供了好几种优雅的方式,既能让代码更整洁,还能提升性能,我给你详细拆解:
方案一:用withSum预加载关联总和(Laravel 8+首选)
如果你用的是Laravel 8或更高版本,withSum简直是为这个场景量身定做的!它能直接帮你预加载每个Invoice对应的services的rate总和,不用再在视图里绕圈子。
修改你的控制器代码就行:
use Carbon\Carbon; $invoices = \App\Invoice::with('services') // 给每个Invoice加个service_rate_sum字段,存关联services的rate总和 ->withSum('services', 'rate') ->orderBy('date') ->get() ->groupBy(function($item) { return Carbon::createFromFormat('Y-m-d', $item->date)->format('Y-M'); });
然后视图里直接用预计算好的字段,再也不用嵌套循环了:
@foreach ($invoices as $key=>$group) <tr> <td>{{$key}}</td> <td class="text-right">{{$group->sum('discount')}}</td> <td class="text-right"> {{$group->sum('service_rate_sum')}} </td> </tr> @endforeach
方案二:直接用数据库查询分组聚合(大数据量更高效)
如果你的数据量比较大,Eloquent集合分组可能有点慢,那直接让数据库来做分组和聚合会更高效,所有计算都在数据库层面完成,性能拉满。
控制器代码改成这样(注意替换成你实际的关联外键,假设services表的外键是invoice_id):
use Illuminate\Support\Facades\DB; use Carbon\Carbon; $invoices = DB::table('invoices') ->join('services', 'invoices.id', '=', 'services.invoice_id') ->select( // 格式化日期成你要的Y-M格式 DB::raw("DATE_FORMAT(invoices.date, '%Y-%b') as month"), // 计算分组后的总discount DB::raw('SUM(invoices.discount) as total_discount'), // 计算分组后的总service rate DB::raw('SUM(services.rate) as total_service_rate') ) ->groupBy('month') ->orderBy('month') ->get();
视图就更简单了,直接遍历结果就行:
@foreach ($invoices as $item) <tr> <td>{{$item->month}}</td> <td class="text-right">{{$item->total_discount}}</td> <td class="text-right">{{$item->total_service_rate}}</td> </tr> @endforeach
给老版本Laravel的补充方案(7及以下)
如果你还在用Laravel 7或更早的版本,没有withSum,那可以用leftJoin配合select手动计算总和:
use Carbon\Carbon; use Illuminate\Support\Facades\DB; $invoices = \App\Invoice::with('services') ->select('invoices.*', DB::raw('SUM(services.rate) as service_rate_sum')) ->leftJoin('services', 'invoices.id', '=', 'services.invoice_id') ->groupBy('invoices.id') ->orderBy('date') ->get() ->groupBy(function($item) { return Carbon::createFromFormat('Y-m-d', $item->date)->format('Y-M'); });
这样同样能在控制器里拿到每个Invoice的service rate总和,视图里还是用$group->sum('service_rate_sum')就行。
把计算逻辑从视图移到控制器(甚至数据库层),不仅让视图只专注于展示内容,代码也更好维护,数据量大的时候性能提升还特别明显!
内容的提问来源于stack exchange,提问作者paul B
相关产品推荐
相关产品推荐

