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

Laravel中hasOne-ofMany关联如何添加内部过滤条件?

解决Laravel中hasOne+ofMany关联时过滤条件置于子查询内的问题

你的核心问题是原写法中where('autosave', false)被加到了关联查询的外层,导致逻辑变成:先找到每个文档的全局最大revision_id(不管是否自动保存),再过滤掉自动保存的记录——如果这个最大revision_id对应的只有自动保存版本,关联结果就会为空。而我们需要的是先筛选所有手动保存的版本,再从中找出每个文档的最新revision_id。

解决方案1:利用ofMany的回调参数(Laravel 9+)

Laravel 9及以上版本的ofMany方法支持第三个参数作为回调,用来定制聚合查询的约束条件,直接把过滤逻辑放到子查询中:

public function mainRevision()
{
    return $this->hasOne(DocumentRevision::class)
        ->ofMany(
            'revision_id',
            'max',
            function ($query) {
                // 这个where会被放到计算最大revision_id的子查询里
                $query->where('is_autosave', false);
            }
        );
}

解决方案2:手动构建子查询关联(兼容低版本)

如果你的Laravel版本低于9,可以通过joinSub手动构建子查询,先获取每个文档的最新手动revision_id,再关联对应的版本记录:

use Illuminate\Support\Facades\DB;

public function mainRevision()
{
    // 子查询:获取每个文档的最大手动保存revision_id
    $latestManualRevs = DocumentRevision::select(
            'document_id',
            DB::raw('MAX(revision_id) as max_rev_id')
        )
        ->where('is_autosave', false)
        ->groupBy('document_id');

    return $this->hasOne(DocumentRevision::class)
        ->joinSub($latestManualRevs, 'latest_revs', function ($join) {
            $join->on('document_revisions.document_id', '=', 'latest_revs.document_id')
                 ->on('document_revisions.revision_id', '=', 'latest_revs.max_rev_id');
        })
        ->where('is_autosave', false);
}

效果验证

两种写法生成的SQL都会将is_autosave = false的过滤条件放到计算最大revision_id的子查询内部,先筛选出所有手动保存的版本,再找出每个文档的最新revision_id,最后关联对应的完整记录,完全符合你期望的SQL结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 06:33:28