从Yii2中的联结表中检索数据

msf*_*fgt 11 php mysql activerecord yii2

我正在尝试从Yii2中的连接表中获取数据,而无需额外的查询.我有2个模型(用户,组)通过联结表(user_group)关联.在user_group表中,我想为此关系存储额外数据(admin flag,...).

  • 将数据添加到联结表的最佳方法是什么?link方法接受参数extraColumns但我无法弄清楚它是如何工作的.

  • 检索此数据的最佳方法是什么?我写了一个额外的查询来从连接表中获取值.必须有一个更清洁的方法来做到这一点?!

仅供参考,这是我在模型中定义关系的方式:

Group.php

public function getUsers() {
    return $this->hasMany(User::className(), ['id' => 'user_id'])
        ->viaTable('user_group', ['group_id' => 'id']);
}
Run Code Online (Sandbox Code Playgroud)

user.php的

public function getGroups() {
    return $this->hasMany(Group::className(), ['id' => 'group_id'])
        ->viaTable('user_group', ['user_id' => 'id']);
}
Run Code Online (Sandbox Code Playgroud)

Big*_*gie 8

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


官方的Yii Guide 2.0说明了两种使用联结表的方法:使用viaTable()和使用via()(见这里).虽然前者期望联结表的名称作为参数,但后者期望关系名称作为参数.

如果您需要访问联结表中的数据,我会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']);
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,您可以使用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
Run Code Online (Sandbox Code Playgroud)

这一切都可以使用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())
}
Run Code Online (Sandbox Code Playgroud)


msf*_*fgt 3

由于我已经近 14 天没有收到任何答复,我将发布我如何解决这个问题。这并不完全是我想要的,但它有效,现在就足够了。所以...这就是我所做的:

  1. 为联结表添加了模型用户组
  2. 添加了与组的关系

    public function getUserGroups()
    {
        return $this->hasMany(UserGroup::className(), ['user_id' => 'id']);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在我的搜索模型功能中加入 UserGroup

    $query = Group::find()->where('id =' . $id)->with('users')->with('userGroups');
    
    Run Code Online (Sandbox Code Playgroud)

这就是我想要的,包含所有用户的,以及由我的新模型UserGroup表示的来自联结表的数据。

我考虑首先扩展查询构建 Yii2 函数 - 这可能是解决这个问题的更好方法。但由于我还不太了解 Yii2,所以我决定暂时不做。

如果您有更好的解决方案,请告诉我。