【问题标题】:search/sort 0 to many relations table in gridview yii2在gridview yii2中搜索/排序0到许多关系表
【发布时间】:2016-05-08 10:30:56
【问题描述】:

我有很多 acc 经理都没有的投标表。我使用 kartik select2 小部件通过 TenderAccManager 模型保存这些小部件。

这里,tender_acc_maanger 表存储了tender 和 acc_manager 表的 id。

现在我想在 gridview 中以逗号分隔的方式显示 acc 经理名称(accManager 是 TenderAccManager 模型中的关系名称), 到目前为止,我想出了这个(在gridview小部件内):

[
    'label' => 'A/C Manager Name',
    'format' => 'raw',
    'value' => function($data) {
        $accManagers = TenderAccManager::find()
            ->where(['tender_id' => $data->id])
            ->all();

        $value = '';
        $i = 0;
        foreach($accManagers as $accManager) {
            if($i > 0) {
                $value .= ', ';
            }
            $value .= $accManager->accManager->name;
            $i++;
        }

        return $value;
    }
],

代码正在运行,但我希望搜索和排序功能也像 gridview 中的其他字段一样,我该怎么做?

【问题讨论】:

    标签: gridview yii2


    【解决方案1】:

    首先,我认为您应该重新考虑在动作开始时使用急切加载(这是延迟加载)获取此信息。目前,您要对每一行执行数据库查询,这是一个昂贵的操作(不需要)。

    我并没有想太多。我的第一个想法是下一个:

    1) 我猜您在网格视图中列出了所有投标,并在其中一列中列出了所有 Acc 经理。加载它们时(我猜是在 Tender Search 模型搜索方法中)你应该执行两个连接(到关系多对多表和 Acc 管理器表)。因此,当这一步完成时,您已经全部加载完毕,并且不必在网格视图中的每一行结果中对数据库执行查询。 (此外,您应该避免在视图中执行查询)。

    2) 好吧,您可以在您的 Tender 模型中拥有公共成员 AccManagers,这将是“安全的”。有这个的时候,在搜索中,配置数据提供者的时候,其实可以为这个属性配置排序。当然,您应该将此属性的查询结果创建为逗号分隔列表,或者您希望它看起来如何。

    当急切地加载数据和排序完成后,您就可以:

    3) 过滤数据。只需在搜索模型中设置搜索条件的 andWhere 部分,这将实际比较您连接的结果字符串,或将每个 AccManagers 名称与插入的值进行比较(这取决于您希望过滤器如何工作)。

    这些只是指导方针,希望对您有所帮助。

    最好的问候

    【讨论】:

    • 我知道我目前做的事情并不正确,但我想不出更好的方法,现在你关于急切加载而不是在视图中查询的指导帮助我理解这个概念,而阿米特昆达里亚的回答帮助我实现了它。所以你的两个答案对我都很有价值。
    • 太棒了。是的,我更喜欢从概念上回答问题,因为我认为当开发人员确切地知道他想要实现什么时,实现是可以相对容易学习/理解的东西。
    【解决方案2】:

    /** * 这是“tender”表的模型类。

    类 Tender 扩展 \yii\db\ActiveRecord {

    public $manager;
    
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'tender';
    }
    
    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['name', 'cost'], 'required'],
            [['cost'], 'number'],
            [['name'], 'string', 'max' => 255],
        ];
    }
    
    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'name' => 'Name',
            'cost' => 'Cost',
        ];
    }
    
    /**
     * @return \yii\db\ActiveQuery
     */
    public function getTenderManagers()
    {
        return $this->hasMany(TenderManager::className(), ['tender_id' => 'id']);
    }
    
    /**
     * @return \yii\db\ActiveQuery
     */
    public function getTenderManagerList()
    {
        $list  = '';
        foreach ($this->tenderMaangers as $managers) {
            $list .=$managers->manager->name.' ';
        }
        return $list;
    }
    

    }

    /** * TenderSearch 表示关于frontend\models\Tender 的搜索表单背后的模型。 */

    类 TenderSearch 扩展了 Tender {

    /**
     * @inheritdoc
     */
    public function rules() {
        return [
            [['id'], 'integer'],
            [['name', 'manager'], 'safe'],
            [['cost'], 'number'],
        ];
    }
    
    /**
     * @inheritdoc
     */
    public function scenarios() {
        // bypass scenarios() implementation in the parent class
        return Model::scenarios();
    }
    
    /**
     * Creates data provider instance with search query applied
     *
     * @param array $params
     *
     * @return ActiveDataProvider
     */
    public function search($params) {
        $query = Tender::find();
        $query->joinWith(['tenderManagers.manager']);
        // add conditions that should always apply here
    
        $dataProvider = new ActiveDataProvider([
            'query' => $query,
        ]);
    
        $dataProvider->sort->attributes['manager'] = [
            'asc' => ['manager.name' => SORT_ASC],
            'desc' => ['manager.name' => SORT_DESC],
        ];
    
        $this->load($params);
    
        if (!$this->validate()) {
            // uncomment the following line if you do not want to return any records when validation fails
            // $query->where('0=1');
            return $dataProvider;
        }
    
        // grid filtering conditions
        $query->andFilterWhere([
            'id' => $this->id,
            'cost' => $this->cost,
        ]);
    
        $query->andFilterWhere(['like', 'tender.name', $this->name]);
        $query->andFilterWhere(['like', 'manager.name', $this->manager]);
    
        return $dataProvider;
    }
    

    }

    /** * 这是表“tender_manager”的模型类。 */

    类 TenderManager 扩展 \yii\db\ActiveRecord {

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'tender_maanger';
    }
    
    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['tender_id', 'manager_id'], 'required'],
            [['tender_id', 'manager_id'], 'integer'],
            [['manager_id'], 'exist', 'skipOnError' => true, 'targetClass' => Manager::className(), 'targetAttribute' => ['manager_id' => 'id']],
            [['tender_id'], 'exist', 'skipOnError' => true, 'targetClass' => Tender::className(), 'targetAttribute' => ['tender_id' => 'id']],
        ];
    }
    
    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'tender_id' => 'Tender ID',
            'manager_id' => 'Manager ID',
        ];
    }
    
    /**
     * @return \yii\db\ActiveQuery
     */
    public function getManager()
    {
        return $this->hasOne(Manager::className(), ['id' => 'manager_id']);
    }
    
    /**
     * @return \yii\db\ActiveQuery
     */
    public function getTender()
    {
        return $this->hasOne(Tender::className(), ['id' => 'tender_id']);
    }
    

    }

    /** * 这是表“经理”的模型类。 */

    类管理器扩展了\yii\db\ActiveRecord {

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'manager';
    }
    
    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['name'], 'required'],
            [['name'], 'string', 'max' => 255],
        ];
    }
    
    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'name' => 'Name',
        ];
    }
    
    /**
     * @return \yii\db\ActiveQuery
     */
    public function getTenderMaangers()
    {
        return $this->hasMany(TenderMaanger::className(), ['manager_id' => 'id']);
    }
    

    /*这是招标索引文件的网格代码。 */

            [
                'attribute' => 'manager',
                'value' => function($model) {
                   return $model->getTenderManagerList();
                },
            ],
    

    【讨论】:

    • 您的代码帮助我清晰地理解事物并成功实施。
    • 我在加入时遇到了一点问题,因为投标有很多 acc_managers,似乎 count 返回相乘的结果,例如,如果我有一个投标条目,但有 3 个 acc man 条目,则查询返回3 而不是 1,我怎么能在这里应用 distinct?
    • 您不能使用 distinct 关键字,而必须使用 Inner Join 仅列出匹配的记录
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-12
    • 2018-08-10
    • 1970-01-01
    • 1970-01-01
    • 2019-12-10
    相关资源
    最近更新 更多