You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中数据库查询聚合逻辑:存服务还是查询目录?

Laravel聚合逻辑代码的放置建议:服务类优先,按需拆分查询逻辑

一、优先选择服务类的原因

这段代码不仅包含数据库查询,还涉及查询后的聚合统计(计算各类总额、净利润),属于一个完整的业务场景(比如生成车辆采购日报表),放到服务类更合适:

  • 封装完整业务流程:将查询、分组、聚合的整个流程封装成单一方法,控制器只需调用服务类接口,保持控制器极简,符合Laravel“胖服务瘦控制器”的最佳实践。
  • 提升复用性:后续其他模块(比如定时任务导出报表、管理后台的统计页面)需要相同数据时,直接调用服务类方法即可,避免重复编写逻辑。
  • 职责边界清晰:服务类专注于业务逻辑的编排,对外暴露明确的业务接口,其他层无需关心内部的查询和聚合细节。

示例服务类实现:

// app/Services/CarReportService.php
namespace App\Services;

use Illuminate\Http\Request;
use App\Models\Car;

class CarReportService
{
    public function getDailyPurchaseSummary(Request $request)
    {
        $carsByDate = Car::filterQuery($request)
            ->select([
                'id',
                'purchase_date',
                'purchase_time',
                'sale_date',
                'sale_time',
                'duration',
                'make',
                'model',
                'colour',
                'purchase_price',
                'sale_price',
                'quantity',
                'gross_profit',
                'tax',
                'handling_fee',
                'delivery_fee',
            ])
            ->orderBy('purchase_date', 'asc')
            ->orderBy('purchase_time', 'asc')
            ->get()
            ->groupBy('purchase_date');

        $summary = $carsByDate->map(function ($cars) {
            return [
                'volume_total' => $cars->sum('quantity'),
                'gross_profit_total' => $cars->sum('gross_profit'),
                'tax_total' => $cars->sum('tax'),
                'handling_fees_total' => $cars->sum('handling_fee'),
                'delivery_fees_total' => $cars->sum('delivery_fee'),
                'net_profit_total' => $cars->sum('net_profit'),
            ];
        });

        return compact('carsByDate', 'summary');
    }
}

二、何时考虑拆分到查询类

如果你的项目采用查询对象模式(比如在app/Queries目录封装独立查询逻辑),可以将纯数据库查询部分(从filterQuery到get()之前的代码)拆分到查询类中,聚合统计逻辑仍保留在服务类:

  • 查询类(比如CarDailyPurchaseQuery)专注于构建过滤、排序后的数据库查询,返回原始车辆集合;
  • 服务类调用查询类获取数据后,执行聚合统计完成业务流程。

这种拆分适合查询逻辑复杂且需要在多个业务场景中复用的情况,能进一步解耦查询逻辑与业务处理逻辑。

三、关于“Eloquent无需仓库模式”的说明

Eloquent本身是ActiveRecord模式,模型类已经封装了数据访问逻辑,确实不需要额外的仓库层来抽象数据操作。但服务类和查询类不属于仓库模式范畴:

  • 服务类是业务逻辑的载体,与数据访问无关;
  • 查询类是对Eloquent查询的封装,用于复用复杂查询逻辑,而非替代仓库。

内容的提问来源于stack exchange,提问作者NoLimitLondon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 13:03:10