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

仅使用Active Record时Yii2 GridView如何让每行仅调用一次dbFunction

解决方案

方案1:Active Record模型添加临时缓存(最简实现,仅合并两次查询为一次)

步骤1:修改你的Active Record模型类,添加临时缓存属性和查询方法

给对应数据表的AR类增加如下代码,不需要修改数据库结构:

class YourModel extends \yii\db\ActiveRecord
{
    // 临时缓存dbFunction查询结果,不映射数据库字段
    public $_dbFunctionCache = null;

    // 统一获取dbFunction结果的方法,仅首次调用执行查询
    public function getDbFunctionData()
    {
        if ($this->_dbFunctionCache === null) {
            // 修正原代码中SQL漏写的右括号
            $this->_dbFunctionCache = Yii::$app->db->createCommand("SELECT * FROM dbFunction({$this->point_id})")->queryOne();
        }
        return $this->_dbFunctionCache;
    }

    // 原有模型的其他代码保持不变
}

步骤2:修改GridView配置,复用查询结果

列配置修改:

$gridColumns = [
    ['class' => SerialColumn::class],
    [
        'attribute' => 'cap',
        'label' => 'Всего, Зан., Св.',
        'format' => 'raw',
        'value' => function($model) {
            // 直接调用模型的方法获取数据,首次调用才会执行查询
            $data = $model->dbFunctionData;
            $html = <<< HTML
<div class="item">{$data['capacity']}</div>
<div class="item">{$data['occupied']}</div>
<div class="item">{$data['free']}</div>
HTML;       
            return $html;
        },      
    ],  
];

rowOptions配置修改:

echo GridView::widget([
    'id' => 'my-table',
    'columns' => $gridColumns,
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,  
    'rowOptions' => function($model) {
        // 复用已经缓存的查询结果,不会二次执行dbFunction
        $data = $model->dbFunctionData;        
        $class = $data['free'] === 0 ? 'free-point' : '';
                
        if ($data['capacity'] === 0 && $data['occupied'] === 0 && $data['free'] === 0)
            $class = 'd-none';
        
        return [
            'data-id' => $model->id,
            'class' =>  $class,
        ];
    },
]);

方案2:查询阶段预加载数据(彻底解决分页计数错误问题)

如果你需要避免d-none隐藏行导致的分页计数不准,可直接在dataProvider的查询阶段就把dbFunction的结果查出来并过滤无效行,性能最优:
在你的搜索模型的search()方法中修改查询逻辑:

public function search($params)
{
    $query = YourModel::find();
    // 将dbFunction的字段直接加入查询,一次性加载所有行的计算结果
    $query->addSelect([
        '*',
        'capacity' => new \yii\db\Expression('(SELECT capacity FROM dbFunction(point_id))'),
        'occupied' => new \yii\db\Expression('(SELECT occupied FROM dbFunction(point_id))'),
        'free' => new \yii\db\Expression('(SELECT free FROM dbFunction(point_id))'),
    ]);
    // 提前过滤全0的无效行,分页计数会自动匹配实际显示的行数
    $query->andWhere('capacity != 0 OR occupied !=0 OR free !=0');

    // 原有搜索逻辑、dataProvider配置保持不变
    $dataProvider = new ActiveDataProvider([
        'query' => $query,
    ]);
    // ... 原有其他代码
}

修改后不需要再给模型加缓存方法,列配置和rowOptions里直接访问$model->capacity、$model->occupied、$model->free即可,全表仅执行一次包含dbFunction的关联查询。

内容的提问来源于stack exchange,提问作者Федор Досумов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 04:24:04