仅使用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,提问作者Федор Досумов
相关产品推荐
相关产品推荐

