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

Laravel Eloquent关联预加载仅首条返回latest关联结果怎么解决?

问题原因

在hasMany关联上直接加take(1)的作用范围是整个关联查询的结果集,而非为每个Site模型各取1条关联数据。预加载时会一次性查询所有符合条件的Test记录后仅保留全局最新的1条,因此只有第一个匹配的Site能拿到关联数据。另外你原代码里关联方法名是latestTests(复数),但预加载时写的是latestTest(单数),注意要保持命名一致。

解决方案

方案1:Laravel 8.42+ 官方推荐写法(性能最优)

Laravel 8.42版本开始提供ofMany系列方法,专门用于获取hasMany关联的单条最新/最旧记录,预加载时会自动优化查询逻辑,不会加载全量Test数据。
修改Site模型的关联定义即可:

class Site extends Model
{
    use HasFactory;

    public function tests() {
        return $this->hasMany(Test::class,'requestedUrl','frontpage');
    }

    public function latestTest() {
        return $this->hasOne(Test::class,'requestedUrl','frontpage')
            ->latestOfMany();
    }   
}

原有查询代码无需修改,直接使用即可:

$sites = Site::
    ->with('latestTest')
    ->orderBy($sort, $direction)
    ->paginate($size);

方案2:低版本Laravel 子查询实现

如果使用的Laravel版本低于8.42,可以通过子查询实现相同效果:

public function latestTest()
{
    return $this->hasOne(Test::class, 'requestedUrl', 'frontpage')
        ->where('id', function ($query) {
            // 若按created_at排序取最新,可替换为selectRaw('max(created_at)'),同时把where条件的id改为created_at
            $query->selectRaw('max(id)')
                ->from('tests')
                ->whereColumn('tests.requestedUrl', 'sites.frontpage');
        });
}

性能优化建议

  • 给tests表的requestedUrl字段添加普通索引,可大幅提升关联查询的执行效率。
  • 若需要自定义排序规则,latestOfMany支持传入排序字段和排序方向参数,也支持链式调用where添加额外筛选条件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 23:27:04