能否在传递至GridView前移除Active Data Provider记录?如何拆分数据提供者?
同一视图拆分单次查询数据为两个独立DataProvider并渲染GridView
一、单次查询后拆分数据为两个独立DataProvider
要避免多次数据库查询,你可以先执行一次完整查询获取所有需要的数据,再按业务规则拆分后分别构建DataProvider。这里推荐用ArrayDataProvider封装拆分后的数据集,它直接基于内存中的模型数组,无需再次发起数据库请求。
后端控制器代码示例:
use yii\data\ArrayDataProvider; use app\models\YourModel; public function actionIndex() { // 1. 单次查询获取所有符合条件的数据(按需添加where/join等条件) $query = YourModel::find()->where(['status' => 1]); $allModels = $query->all(); // 2. 按规则拆分数据(示例:按type字段拆分) $typeAModels = array_filter($allModels, function($model) { return $model->type === 'type_a'; }); $typeBModels = array_filter($allModels, function($model) { return $model->type === 'type_b'; }); // 3. 分别构建两个独立的DataProvider $dataProviderA = new ArrayDataProvider([ 'allModels' => $typeAModels, 'pagination' => ['pageSize' => 20], // 按需设置分页 'sort' => [ 'attributes' => ['id', 'name', 'created_at'], // 支持排序的字段 ], ]); $dataProviderB = new ArrayDataProvider([ 'allModels' => $typeBModels, 'pagination' => ['pageSize' => 20], 'sort' => [ 'attributes' => ['id', 'name', 'created_at'], ], ]); return $this->render('index', [ 'dataProviderA' => $dataProviderA, 'dataProviderB' => $dataProviderB, ]); }
前端视图代码示例:
<!-- 第一个GridView --> <?= \yii\grid\GridView::widget([ 'dataProvider' => $dataProviderA, 'columns' => [ 'id', 'name', 'created_at:datetime', // 其他列配置 ], ]) ?> <!-- 第二个GridView --> <?= \yii\grid\GridView::widget([ 'dataProvider' => $dataProviderB, 'columns' => [ 'id', 'name', 'type', // 其他列配置 ], ]) ?>
二、在传递至GridView前从ActiveDataProvider移除记录
可以实现,分两种场景选择最优方案:
方案1:数据库层面过滤(推荐)
如果过滤规则能通过SQL条件实现,直接修改ActiveDataProvider的查询条件即可,性能远高于内存过滤:
$dataProvider = new \yii\data\ActiveDataProvider([ 'query' => YourModel::find()->where(['status' => 1]), ]); // 移除status为deleted的记录(直接修改查询条件) $dataProvider->query->andWhere(['!=', 'status', 'deleted']);
方案2:内存层面过滤(仅当无法用SQL实现时使用)
如果必须在内存中过滤已查询到的模型,可先获取ActiveDataProvider的模型数组,过滤后重新封装为ArrayDataProvider(不建议直接修改ActiveDataProvider的models属性,因为它依赖原始查询的延迟加载逻辑):
$activeDataProvider = new \yii\data\ActiveDataProvider([ 'query' => YourModel::find()->where(['status' => 1]), ]); // 获取已查询的模型数组 $models = $activeDataProvider->getModels(); // 过滤掉不需要的记录 $filteredModels = array_filter($models, function($model) { return $model->is_valid === true; }); // 构建过滤后的DataProvider $filteredDataProvider = new ArrayDataProvider([ 'allModels' => $filteredModels, 'pagination' => $activeDataProvider->pagination, 'sort' => $activeDataProvider->sort, ]);
之后将$filteredDataProvider传给GridView即可。
注意事项
- 若需要分页,单次查询时应先处理分页逻辑(通过
offset和limit获取当前页数据),避免加载全量数据导致性能问题。 - 拆分规则需明确,确保两个数据集无重叠或遗漏,根据业务需求调整
array_filter的回调逻辑。
内容的提问来源于stack exchange,提问作者Leenard
相关产品推荐
相关产品推荐

