如何用Query Builder实现类似Eloquent预加载的结构?
解决方案
方法一:利用Eloquent关联与预加载(推荐)
首先在Table1模型中定义与Table2、Table3的关联关系:
// app/Models/Table1.php class Table1 extends Model { // 关联Table2,一个Table1对应多条Table2记录 public function table2Data() { return $this->hasMany(Table2::class, 'table_1_id'); } // 关联Table3,一个Table1对应多条Table3记录 public function table3Data() { return $this->hasMany(Table3::class, 'table_1_id'); } }
查询时直接使用with()方法预加载关联数据,Laravel会自动执行3次高效查询(一次查主表,两次批量查关联表),避免N+1性能问题,同时自动将关联数据附加到每个模型实例:
// 获取带关联数据的Table1记录 $table1Records = Table1::where(...)->where(...)->with(['table2Data', 'table3Data'])->get();
接着将结果转换为你需要的数组结构:
$result = $table1Records->keyBy('id')->map(function ($item) { return [ 'table2_data' => $item->table2Data->toArray(), 'table3_data' => $item->table3Data->toArray(), ]; })->toArray();
最终$result的结构完全符合需求:以Table1的id为键,每个值包含对应关联的Table2、Table3数据数组。
方法二:手动用whereIn查询并组装结构(适合不想定义模型关联的场景)
如果已经先查询了Table1的数据,可手动批量查询关联表并组装结构:
- 提取已查询Table1的所有id:
$table1Ids = $table1Records->pluck('id')->toArray();
- 批量查询Table2、Table3的数据,并按
table_1_id分组:
$table2Groups = Table2::whereIn('table_1_id', $table1Ids)->get()->groupBy('table_1_id')->toArray(); $table3Groups = Table3::whereIn('table_1_id', $table1Ids)->get()->groupBy('table_1_id')->toArray();
- 遍历Table1记录,组装目标结构:
$result = []; foreach ($table1Records as $record) { $result[$record->id] = [ 'table2_data' => $table2Groups[$record->id] ?? [], 'table3_data' => $table3Groups[$record->id] ?? [], ]; }
这种方式也能得到目标结构,但相比Eloquent预加载,代码更繁琐,需自行处理分组和空值情况。
内容的提问来源于stack exchange,提问作者pileup
相关产品推荐
相关产品推荐

