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

循环复用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 02:33:19