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

Laravel Blade嵌套循环仅外层首次迭代有结果问题求助

问题分析与解决方法

问题原因

你的$subjects变量是Laravel Query Builder实例,它属于可变对象。第一次内层循环调用->where('subject_id', $id->subject_id)时,会直接在原Query Builder上追加该条件;后续循环再调用where时,条件会叠加成transaction_id = ? AND subject_id = 第一个ID AND subject_id = 当前ID,这种矛盾的查询条件自然无法返回数据。


解决方法

方法1:提前查询并分组数据(最优,避免N+1查询)

在控制器中先把所有关联的subjects查询出来,再按subject_id分组,模板直接取对应分组的数据,无需多次查询:

控制器修改:

public function show(string $id)
{
    $transaction = Transaction::findOrFail($id);
    $subject_ids = DB::connection('transfer')
        ->table('subjects')
        ->join('transactions_subjects', 'transactions_subjects.subject_id', '=', 'subjects.id')
        ->where('transactions_subjects.transaction_id', '=',  $transaction->id)
        ->distinct()
        ->get(['subject_id', 'name', 'hours']);

    // 查询所有数据后按subject_id分组
    $groupedSubjects = DB::connection('transfer')
        ->table('subjects')
        ->join('transactions_subjects', 'transactions_subjects.transferable_id', '=', 'subjects.id')
        ->where('transactions_subjects.transaction_id', '=',  $transaction->id)
        ->get()
        ->groupBy('subject_id');

    return view('transfer.transactions.details', [
        'transaction'   => $transaction,
        'subject_ids'   => $subject_ids,
        'groupedSubjects' => $groupedSubjects,
    ]);
}

模板修改:

@foreach ($subject_ids as $id)
    <div class="row wrapper table-responsive table text-center">
        <div class="col-2">
            <div>{{ $id->subject_id }}</div>
        </div>
        <div class="col-2">
            <div>{{ $id->hours }}</div>
        </div>
        {{-- 直接取对应分组,无数据时用空集合兜底 --}}
        @foreach ($groupedSubjects[$id->subject_id] ?? [] as $subject)
            <div class="col-2">
                <div>{{ $subject->code }}</div>
            </div>
            <div class="col-2">
                <div>{{ $subject->name }}</div>
            </div>
            <div class="col-2">
                <div>{{ $subject->hours }}</div>
            </div>
            <div class="col-2"></div>
            <div class="col-2"></div>
            <div class="col-2"></div>
        @endforeach
        <hr>
    </div>
@endforeach

方法2:提前查询所有数据,在集合上筛选

如果不需要分组,也可以提前把所有subjects查询为集合,集合的where方法会返回新集合,不会修改原数据:

控制器修改:

// 直接执行查询,将Query Builder转为Collection
$subjects = DB::connection('transfer')
    ->table('subjects')
    ->join('transactions_subjects', 'transactions_subjects.transferable_id', '=', 'subjects.id')
    ->where('transactions_subjects.transaction_id', '=',  $transaction->id)
    ->get();

模板修改:

{{-- 去掉->get(),直接使用集合的where方法筛选 --}}
@foreach ($subjects->where('subject_id', $id->subject_id) as $subject)
    {{-- 原有代码不变 --}}
@endforeach

方法3:每次循环克隆Query Builder(适合大数据量场景)

如果数据量过大,不想一次性查询所有数据,可以每次循环克隆原Query Builder,保证每次查询都是独立的:

模板修改:

{{-- 克隆原Query Builder,避免修改原实例的查询条件 --}}
@foreach ((clone $subjects)->where('subject_id', $id->subject_id)->get() as $subject)
    {{-- 原有代码不变 --}}
@endforeach

注意:此方法会产生N+1查询(外层循环多少次就执行多少次数据库查询),数据量大时可能影响性能,需谨慎使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 15:16:00