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

Laravel Eloquent:如何在单查询中预加载自定义属性total_duration_days?

解决Laravel中Subscription模型自定义属性的N+1查询问题

你遇到的问题根源在于:自定义属性每次被访问时,都会单独执行一次关联表的sum查询,当处理多个Subscription实例时就会触发N+1查询。要在单查询中预加载这个聚合值,有两种实用方案:

方案一:自定义查询作用域 + 访问器

在Subscription模型中定义查询作用域,通过子查询将总时长直接查询出来并作为字段返回:

// app/Models/Subscription.php
public function scopeWithTotalDurationDays($query)
{
    return $query->addSelect([
        'total_duration_days' => \App\Models\Payment::selectRaw('SUM(duration_days)')
            ->whereColumn('subscription_id', 'subscriptions.id')
    ]);
}

给模型添加访问器,直接读取查询返回的字段值:

public function getTotalDurationDaysAttribute()
{
    return $this->attributes['total_duration_days'] ?? 0;
}

控制器中调用该作用域即可:

$subscriptions = Subscription::withTotalDurationDays()->get();

方案二:使用Laravel自带的withSum方法

Laravel提供了withSum快捷方法,专门用于预加载关联表的聚合值,代码更简洁:

// 控制器中查询
$subscriptions = Subscription::withSum('payments', 'duration_days')->get();

添加访问器适配框架自动生成的字段名(格式为关联名_sum_字段名):

// app/Models/Subscription.php
public function getTotalDurationDaysAttribute()
{
    return $this->payments_sum_duration_days ?? 0;
}

两种方案都能让总时长在初始查询中一次性获取,彻底解决N+1问题。其中withSum适用于简单求和场景,自定义作用域则更灵活,可应对带额外筛选条件的复杂聚合逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 20:02:36