代码之家  ›  专栏  ›  技术社区  ›  sharf

用于关系计数的Yii2 GridView搜索模型

  •  1
  • sharf  · 技术社区  · 7 年前

    item 那有一个 hasMany 关系 image 模型在项目中 GridView 项目 有我希望能够按此列进行排序,并且可能能够使用复选框进行筛选以仅显示 项目 没有 形象 s

    我尝试在搜索模型中添加一个检查以进行查询 with images andFilterWhere 形象 计数小于输入值。然而,我不确定拥有这种逻辑的最佳方式,是否有更好的方法 按那个计数过滤的方法?

    使现代化 this question 我已经更新了我的 项目 模型具有返回关系计数的方法。

    然后,我更新了我的搜索模型,如下所示:

    class ItemSearch extends Item
    {
        public $image_count;
    
        /**
         * @inheritdoc
         */
        public function rules()
        {
            return [
                [['id', 'product_id', 'manufacturer_id', 'scale_id', 'owner_id', 'quantity'], 'integer'],
                [['sku_number', 'description', 'details', 'condition'], 'safe'],
                [['price', 'sale_price', 'image_count'], '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 = Item::find();
            $subQuery = Image::find()->select('item_id, COUNT(id) as image_count')->groupBy('item_id');
            $query->leftJoin(['imageCount' => $subQuery], 'imageCount.item_id = id');
    
            // add conditions that should always apply here
    
            $dataProvider = new ActiveDataProvider([
                'query' => $query,
            ]);
    
            $dataProvider->setSort([
                'attributes' => [
                    'id',
                    'product_id',
                    'manufacturer_id',
                    'scale_id',
                    'owner_id',
                    'image_count' => [
                        'asc' => ['imageCount.image_count' => SORT_ASC],
                        'desc' => ['imageCount.image_count' => SORT_DESC],
                        'label' => 'Images'
                    ]
                ]
            ]); 
    
            $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
            if (!empty($this->id)) {
                $query->andFilterWhere([
                    'id' => $this->id,
                ]);
            }
            if (!empty($this->product_id)) {
                $query->andFilterWhere([
                    'product_id' => $this->product_id,
                ]);
            }
            if (!empty($this->manufacturer_id)) {
                $query->andFilterWhere([
                    'manufacturer_id' => $this->manufacturer_id,
                ]);
            }
            if (!empty($this->scale_id)) {
                $query->andFilterWhere([
                    'scale_id' => $this->scale_id,
                ]);
            }
            if (!empty($this->owner_id)) {
                $query->andFilterWhere([
                    'owner_id' => $this->owner_id,
                ]);
            }
            if (!empty($this->image_count)) {
                $query->andWhere(['is','imageCount.image_count',new \yii\db\Expression('null')]);
             }
    
            $query->andFilterWhere(['like', 'sku_number', $this->sku_number])
                ->andFilterWhere(['like', 'description', $this->description])
                ->andFilterWhere(['like', 'details', $this->details])
                ->andFilterWhere(['like', 'condition', $this->condition]);
    
            return $dataProvider;
        }
    }
    

    现在的问题是,上面将生成类似以下内容的查询:

    SELECT `item`.* FROM `item` LEFT JOIN (SELECT `item_id`, COUNT(id) as image_count FROM `image` GROUP BY `item_id`) `imageCount` ON imageCount.item_id = id WHERE `imageCount`.`image_count`=0
    

    问题是 items 形象 将不再显示(选中该框将不显示任何内容),因为联接将在中找不到该id的任何内容 桌子

    2 回复  |  直到 7 年前
        1
  •  3
  •   Muhammad Omer Aslam    7 年前

    你应该检查一下 WHERE imageCount.image_count IS NULL 而不是 WHERE imageCount.image_count=0 因为那些没有任何相关图像的行将显示为 null image_count 并将条件从

    $query->andFilterWhere(['imageCount.image_count' => 0]); 
    

    $query->andWhere(['is','imageCount.image_count',new \yii\db\Expression('null')]);`
    

    您的查询应该像这样生成

    SELECT `item`.* FROM `item` 
    LEFT JOIN
    (
       SELECT `item_id`, COUNT(id) as image_count 
       FROM `image` 
       GROUP BY `item_id`
    ) `imageCount` 
    
    ON imageCount.item_id = id 
    
    WHERE `imageCount`.`image_count` is NULL
    

    使现代化

    您在筛选图像计数为0的项目时遇到问题我没有您所拥有的确切模式,但我将在下面说明一个示例,其中有一个类似的场景 Shoots 以及它们在连接表中的相关标记 ShootTag 模型

    • 射出

    下面是模式和数据的示例

    +----+------------+--------+------------+
    | id | name       | active | shoot_type |
    +----+------------+--------+------------+
    |  1 | aslam omer |      1 | modeling   |
    |  2 | asif       |      1 | modeling   |
    |  3 | saleem     |      1 | modeling   |
    |  4 | sajid      |      1 | modeling   |
    |  5 | tasleem    |      1 | modeling   |
    |  6 | tehseen    |      1 | modeling   |
    |  7 | amjad      |      1 | modeling   |
    |  8 | shaban     |      1 | modeling   |
    |  9 | irfan      |      1 | modeling   |
    +----+------------+--------+------------+
    
    • ShootTags

    下面是模式和数据的示例

    +----------+--------+
    | shoot_id | tag_id |
    +----------+--------+
    |        1 |      1 |
    |        1 |      2 |
    |        1 |      3 |
    |        1 |      4 |
    |        2 |      1 |
    |        2 |      2 |
    |        2 |      3 |
    |        3 |      1 |
    |        4 |      1 |
    |        4 |      4 |
    +----------+--------+
    

    现在考虑到上面的表格和数据,我有一个名为的搜索模型 ShootsSearch 我用它来显示所有的快照,我想显示保存在 模型

    射击搜索 具有以下搜索方法,该方法可正确用于shoottags模型中针对快照的任何计数。

    • 与您的代码不同的是,我正在使用 射击搜索 第一个查询的模型,而不是 射出 使用的模型 Item::find(); 应该是哪一个 ItemSearch::find(); 而是作为您正在使用的别名 图像计数

    • 然后排队 new Expression('if(st.totalTags is NOT NULL,st.totalTags,0) as totalTags') 在主查询中,您需要将空值显示为0,以便在此处使用条件选择。

    • 然后你需要检查一下 if ($this->totalTags == '0') { 申请 $query->andWhere(['IS', 'totalTags', new Expression('null')]); 无效的 对于 totalTags 在没有针对任何 Shoot 在其他部分,您将使用 query->andFilterWhere(['=', 'totalTags', $this->totalTags]);

    这适用于您希望看到下图的所有三种场景

    enter image description here

    搜索totalTags计数为4的快照

    enter image description here

    搜索TotalTags计数为0的快照

    enter image description here

    您应该在代码中替换以下内容

    • public $totalTags 具有 public $image_count
    • 射击标签 具有 Image .
    • shoot_id item_id .
    • 具有 ItemSearch / self

    这是搜索模型,代码已经过测试并运行。

    class ShootsSearch extends Shoots
    {
        /**
         * @var mixed
         */
        public $totalTags;
    
        /**
         * {@inheritdoc}
         */
        public function rules()
        {
            return [
                [['id', 'active', 'totalTags'], 'integer'],
                [['name', 'shoot_type', 'description', 'totalTags'], 'safe']
            ];
        }
    
        /**
         * {@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)
        {
            $subQuery = ShootTag::find()->select(
                [
                    new Expression('shoot_id, COUNT(shoot_id) as totalTags')
                ]
            )->groupBy('shoot_id');
            $query = ShootsSearch::find()->alias('s')
                ->select(
                    [
                        's.*',
                        new Expression('if(st.totalTags is NOT NULL,st.totalTags,0) as totalTags')
                    ]
                )->leftJoin(['st' => $subQuery], 'st.shoot_id=s.id');
    
            // add conditions that should always apply here
    
            $dataProvider = new ActiveDataProvider(
                [
                    'query' => $query
                ]
            );
    
            $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,
                'active' => $this->active
            ]);
    
            $query->andFilterWhere(['like', 'name', $this->name])
                ->andFilterWhere(['like', 'shoot_type', $this->shoot_type])
                ->andFilterWhere(['like', 'description', $this->description]);
    
            if ($this->totalTags == '0') {
                $query->andWhere(['IS', 'totalTags', new Expression('null')]);
            } else {
                $query->andFilterWhere(['=', 'totalTags', $this->totalTags]);
            }
    
            return $dataProvider;
        }
    }
    
        2
  •  1
  •   Luna    7 年前

    我的理解是,您需要计算关联表中的数据量,并根据统计数据进行排序和筛选。

    然后你的 ItemSearch::search()

    public function search($params)
    {
        $query = Item::find()->select('*, (select count(*) from image where image.item_id = item.id) as image_count'); // If the table name of your Image table is image, if the table name of your Item table is item
    
        // add conditions that should always apply here
    
        $dataProvider = new ActiveDataProvider([
            'query' => $query,
        ]);
    
        $dataProvider->setSort([
            'attributes' => [
                'id',
                'product_id',
                'manufacturer_id',
                'scale_id',
                'owner_id',
                'image_count'
            ]
        ]); 
    
        $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
        if (!empty($this->id)) {
            $query->andFilterWhere([
                'id' => $this->id,
            ]);
        }
        if (!empty($this->product_id)) {
            $query->andFilterWhere([
                'product_id' => $this->product_id,
            ]);
        }
        if (!empty($this->manufacturer_id)) {
            $query->andFilterWhere([
                'manufacturer_id' => $this->manufacturer_id,
            ]);
        }
        if (!empty($this->scale_id)) {
            $query->andFilterWhere([
                'scale_id' => $this->scale_id,
            ]);
        }
        if (!empty($this->owner_id)) {
            $query->andFilterWhere([
                'owner_id' => $this->owner_id,
            ]);
        }
        if (!empty($this->image_count)) {
            $query->andWhere([
                'image_count' => $this->image_count,
            ]);
         }
    
        $query->andFilterWhere(['like', 'sku_number', $this->sku_number])
            ->andFilterWhere(['like', 'description', $this->description])
            ->andFilterWhere(['like', 'details', $this->details])
            ->andFilterWhere(['like', 'condition', $this->condition]);
    
        return $dataProvider;
    }
    

    但是,如果图像计数经常需要计算和统计,并且数据量很大,建议您将此字段重新定义到项目表中。

    更新:

    我的错,聚合字段不能按where条件过滤,但您可以使用have:

    $query->andFilterHaving([
        'image_count' => $this->image_count,
    ]);
    
    推荐文章