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

如何不使用Attribute为Eloquent模型添加查询来源字段?

Eloquent原生实现:一次性添加查询来源字段到模型实例

下面几种Eloquent原生方案可以解决你遇到的重复查询问题,都是一次性把字段数据加载到模型实例中,不会每次访问都触发数据库请求:

1. 使用selectRaw直接在主查询中注入字段

这是最直接的方式,在查询模型时,通过selectRaw把需要的查询字段直接包含进主SQL,加载模型时该字段就会成为模型的原生属性,无需额外查询。

比如你要给Post模型添加comment_count字段,统计关联评论数:

$posts = Post::select('posts.*')
    ->selectRaw('(SELECT COUNT(*) FROM comments WHERE comments.post_id = posts.id) as comment_count')
    ->get();

// 直接访问,不会触发额外查询
echo $posts[0]->comment_count;

如果是更复杂的关联查询,也可以用join配合select实现,本质都是把需要的字段一次性查出来。

2. 利用withCount/withSum等聚合预加载(针对关联聚合场景)

如果你的字段是关联模型的聚合数据(数量、求和等),Eloquent提供了原生的withCount、withSum等方法,会一次性把聚合结果加载到模型中,字段名默认是{关联名}_count/{关联名}_sum:

// 假设Post模型有comments关联
$posts = Post::withCount('comments')->get();

// 直接访问,无额外查询
echo $posts[0]->comments_count;

你还可以自定义聚合字段名:

$posts = Post::withCount([
    'comments as approved_comment_count' => function ($query) {
        $query->where('approved', true);
    }
])->get();

echo $posts[0]->approved_comment_count;

3. 自定义预加载(with)+ 模型事件赋值

如果需要的字段来自关联模型的特定数据,可以定义一个自定义关联,通过with预加载后,利用模型的retrieved事件把关联数据赋值到模型属性中:

比如给User模型添加latest_order_date字段,来自最新的订单:

// User模型中定义关联
public function latestOrder()
{
    return $this->hasOne(Order::class)->latest();
}

// 查询时预加载
$users = User::with('latestOrder')->get();

// 在User模型的boot方法中注册事件
protected static function boot()
{
    parent::boot();

    static::retrieved(function ($user) {
        $user->setAttribute('latest_order_date', $user->latestOrder?->created_at);
        // 可选:清理关联释放内存
        $user->unsetRelation('latestOrder');
    });
}

// 直接访问字段
echo $users[0]->latest_order_date;

4. 自定义查询作用域(Scope)封装逻辑

可以把selectRaw或聚合预加载的逻辑封装到Scope中,方便复用:

// Post模型中定义Scope
public function scopeWithCommentCount($query)
{
    return $query->selectRaw('posts.*, (SELECT COUNT(*) FROM comments WHERE comments.post_id = posts.id) as comment_count');
}

// 使用时直接调用Scope
$posts = Post::withCommentCount()->get();
echo $posts[0]->comment_count;

以上几种方式都是Eloquent原生支持的,核心思路都是把需要的字段数据在模型初始查询时一次性加载完成,避免后续访问时重复触发数据库请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 20:35:16