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
相关产品推荐
相关产品推荐

