循环复用Laravel查询构建器返回空值问题求助
问题:Laravel查询构建器复用后循环后续迭代返回空值
因为Web服务器与数据库服务器分离,为减少数据库连接,尝试在循环中复用Laravel查询构建器,但循环进入第二次及后续迭代时,$_opc和$_tags始终返回空值,直接查询数据库或每次循环重新声明模型时能正常获取数据。
问题代码示例
$opc = M_Opc::query(); $taglist = M_Tags::query(); foreach($collection as $row){ $_opc = $opc->where('opc_name',$row['name'])->first(); $_tags = $taglist->with('plant')->where('id_opc', $_opc->id)->get(); foreach($_tags as $_tag){ $plant_name= strtolower(str_replace(" ","_",$_tag->plant->plant_name)); if(!isset($row[$plant_name]) || $row[$plant_name] == "" || empty($row[$plant_name]) || is_null($row[$nm_plant])){ continue; } $_value = $row[$plant_name]; $model = T_DataOpc::where('id_tag',$_tag->id)->whereDate('sync_date', $this->report_date) ->update(['msdr_value' => $_value, 'harpros_value' => $_value]); } }
修改后正常的代码
foreach($collection as $row){ $_opc = M_Opc::where('opc_name',$row['name'])->first(); $_tags = M_Tags::with('plant')->where('id_opc', $_opc->id)->get(); foreach($_tags as $_tag){ $plant_name= strtolower(str_replace(" ","_",$_tag->plant->plant_name)); if(!isset($row[$plant_name]) || $row[$plant_name] == "" || empty($row[$plant_name]) || is_null($row[$nm_plant])){ continue; } $_value = $row[$plant_name]; $model = T_DataOpc::where('id_tag',$_tag->id)->whereDate('sync_date', $this->report_date) ->update(['msdr_value' => $_value, 'harpros_value' => $_value]); } }
原因及解决方案
核心原因
Laravel查询构建器是状态化的,循环外创建的$opc和$taglist实例,每次循环调用where时会把条件追加到原有查询上,而非重置。比如第一次循环添加where('opc_name', 'name1'),第二次循环会再追加where('opc_name', 'name2'),最终查询条件变成opc_name = 'name1' AND opc_name = 'name2',自然无法返回数据。
解决方法
方法1:复制查询构建器实例
每次循环通过clone复制基础查询实例,避免修改原实例的条件:
$opcBase = M_Opc::query(); $taglistBase = M_Tags::query(); foreach($collection as $row){ $_opc = (clone $opcBase)->where('opc_name',$row['name'])->first(); $_tags = (clone $taglistBase)->with('plant')->where('id_opc', $_opc->id)->get(); // 后续逻辑保持不变 }
方法2:重置查询构建器状态
每次循环调用newQuery()重置查询条件:
$opc = M_Opc::query(); $taglist = M_Tags::query(); foreach($collection as $row){ $_opc = $opc->newQuery()->where('opc_name',$row['name'])->first(); $_tags = $taglist->newQuery()->with('plant')->where('id_opc', $_opc->id)->get(); // 后续逻辑保持不变 }
优化建议(更高效减少连接)
可以通过批量查询替代循环内查询,进一步减少数据库交互次数:
// 1. 提取所有需要的opc名称 $opcNames = $collection->pluck('name')->unique(); // 2. 批量查询opc记录,用名称做索引 $opcs = M_Opc::whereIn('opc_name', $opcNames)->get()->keyBy('opc_name'); // 3. 批量查询所有关联的tags并预加载plant,按opc_id分组 $tags = M_Tags::with('plant') ->whereIn('id_opc', $opcs->pluck('id')) ->get() ->groupBy('id_opc'); foreach($collection as $row){ $_opc = $opcs->get($row['name']); if(!$_opc) continue; $_tags = $tags->get($_opc->id, collect()); // 后续逻辑保持不变 }
这种方式仅需3次数据库查询,比循环内多次查询效率更高,同时达到减少连接的目的。
内容的提问来源于stack exchange,提问作者mjosephabie
相关产品推荐
相关产品推荐

