我正在尝试从Yii2的联接表中获取数据,而没有其他查询。我有2个通过联结表(user_group)关联的模型(用户,组)。在user_group表中,我想为此关系存储额外的数据(管理标志,...)。

  • 将数据添加到联结表的最佳方法是什么? 链接方法接受参数extraColumns,但是我不知道它是如何工作的。
  • 检索此数据的最佳方法是什么? 我编写了一个附加查询,以从联结表中获取值。必须有一种更清洁的方式来做到这一点?!

  • 仅供引用,这就是我在模型中定义关系的方式:

    Group.php
    public function getUsers() {
        return $this->hasMany(User::className(), ['id' => 'user_id'])
            ->viaTable('user_group', ['group_id' => 'id']);
    }
    

    User.php
    public function getGroups() {
        return $this->hasMany(Group::className(), ['id' => 'group_id'])
            ->viaTable('user_group', ['user_id' => 'id']);
    }
    

    最佳答案

    简而言之:像您建议的那样对联结表使用ActiveRecord是恕我直言,因为您可以将via()设置为使用该现有ActiveRecord。这允许您使用Yii的link()方法在联结表中创建项目,同时添加数据(例如您的admin标志)。

    官方的Yii指南2.0声明了使用联结表的两种方式:使用viaTable()和使用via()(请参阅here)。前者期望将联结表的名称作为参数,而后者期望将关系名称作为参数。

    如果您需要访问联结表中的数据,则可以按照您的建议为联结表使用ActiveRecord,并使用via():

    class User extends ActiveRecord
    {
        public function getUserGroups() {
            // one-to-many
            return $this->hasMany(UserGroup::className(), ['user_id' => 'id']);
        }
    }
    
    class Group extends ActiveRecord
    {
        public function getUserGroups() {
            // one-to-many
            return $this->hasMany(UserGroup::className(), ['group_id' => 'id']);
        }
    
        public function getUsers()
        {
            // many-to-many: uses userGroups relation above which uses an ActiveRecord class
            return $this->hasMany(User::className(), ['id' => 'user_id'])
                ->via('userGroups');
        }
    }
    
    class UserGroup extends ActiveRecord
    {
        public function getUser() {
            // one-to-one
            return $this->hasOne(User::className(), ['id' => 'user_id']);
        }
    
        public function getGroup() {
            // one-to-one
            return $this->hasOne(Group::className(), ['id' => 'userh_id']);
        }
    }
    

    这样,您就可以使用userGroups关系(与任何其他一对多关系一样)获取联结表的数据而无需其他查询:
    $group = Group::find()->where(['id' => $id])->with('userGroups.user')->one();
    // --> 3 queries: find group, find user_group, find user
    // $group->userGroups contains data of the junction table, for example:
    $isAdmin = $group->userGroups[0]->adminFlag
    // and the user is also fetched:
    $userName = $group->userGroups[0]->user->name
    

    所有这些都可以使用hasMany关系完成。因此,您可能会问为什么应该使用via()声明多对多关系:因为您可以使用Yii的link()方法在联结表中创建项目:
    $userGroup = new UserGroup();
    // load data from form into $userGroup and validate
    if ($userGroup->load(Yii::$app->request->post()) && $userGroup->validate()) {
        // all data in $userGroup is valid
        // --> create item in junction table incl. additional data
        $group->link('users', $user, $userGroup->getDirtyAttributes())
    }
    

    09-17 06:30