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

Laravel Eager Load关联中使用Limit/Take仅返回单条记录如何解决

问题原因

你写的关联在预加载时不生效,核心原因是Eloquent预加载关联的逻辑是先查询所有符合条件的父模型(Person),再一次性查询所有关联的Activity数据,最后把关联数据匹配到对应的父模型上。你加的limit(1)是作用于整个Activity关联查询的结果集,只会返回全局最新的1条活动,自然只能匹配到第一个Person模型。

解决方法

下面给出3种不同场景的原生解决方案,无需引入额外扩展:

方案1:集合过滤(开发成本最低,适合小数据量场景)

先定义正常的多对多关联,再通过模型访问器从关联集合中过滤最新单条活动,预加载时直接加载全量关联即可。

代码实现

// Person模型内代码
class Person extends Model
{
    // 正常的多对多活动关联
    public function activities()
    {
        return $this->belongsToMany(Activity::class, 'activity_job', 'job_id', 'activity_id');
    }

    // 最新活动访问器
    public function getLastActivityAttribute()
    {
        return $this->activities->sortByDesc('created_at')->first();
    }
}

使用方式

// 预加载时直接加载activities关联即可
$persons = Person::with('activities')->get();
// 直接取每个人员的最新活动
foreach ($persons as $person) {
    echo $person->last_activity->title ?? '无活动';
}

适用场景

单页展示人员数≤100、每人关联活动数≤100的场景,写法最简洁,没有SQL优化成本。

方案2:子查询过滤(性能最优,适合大数据量场景)

通过whereRaw子查询在SQL层面就为每个人员过滤出最新的1条活动,返回的关联结果每条人员只会对应1条活动,没有冗余数据。

代码实现

// Person模型内关联代码
public function lastActivity()
{
    return $this->belongsToMany(Activity::class, 'activity_job', 'job_id', 'activity_id')
        ->orderByDesc('created_at')
        ->whereRaw(
            '(SELECT COUNT(*) 
              FROM activity_job AS aj2 
              INNER JOIN activities AS a2 ON aj2.activity_id = a2.id
              WHERE aj2.job_id = activity_job.job_id 
              AND a2.created_at >= activities.created_at) = 1'
        );
}

使用方式

// 直接预加载lastActivity关联即可
$persons = Person::with('lastActivity')->get();
foreach ($persons as $person) {
    echo $person->lastActivity->title ?? '无活动';
}

适用场景

人员或活动数据量较大的场景,SQL层面直接过滤冗余数据,查询性能更高,兼容Laravel 5.8及以上所有版本。

方案3:latestOfMany语法(Laravel 8.42+ 推荐,写法最优雅)

Laravel 8.42版本新增了latestOfMany()、oldestOfMany()方法,专门用于获取单条最新/最早的关联数据,针对多对多场景可以通过中间表模型中转实现。

代码实现

  1. 先创建中间表模型ActivityJob
  2. 在Person模型中定义通过中间表的hasOne关联
// Person模型内代码
public function lastActivity()
{
    return $this->hasOne(ActivityJob::class, 'job_id')
        ->latestOfMany('created_at')
        ->with('activity');
}
  1. 在ActivityJob模型中定义关联Activity的belongsTo关联
// ActivityJob模型内代码
public function activity()
{
    return $this->belongsTo(Activity::class);
}

使用方式

$persons = Person::with('lastActivity.activity')->get();
foreach ($persons as $person) {
    echo $person->lastActivity?->activity?->title ?? '无活动';
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 12:54:10