CakePHP 3 - 计算多对多关联

时间:2017-02-15 16:24:14

标签: cakephp count many-to-many cakephp-3.0 query-builder

我有一个包含Rounds和Users的数据库。 Rounds属于许多用户和用户所属的ToMany Rounds,因此是多对多的关系。添加了连接表rounds_users来执行此操作。 编辑:在这里使用了错误的短语。我的意思是'belongsToMany'而不是'hasMany'

现在我想检索一个Rounds列表,以及每轮链接用户的数量。

如果是一对多关系,以下内容将起作用:

$rounds = $this->Rounds->find()
       ->contain(['Users' => function ($q) 
        {
            return $q->select(['Users.id', 'number' => 'COUNT(Users.round_id)'])
                    ->group(['Users.round_id']);
        }
        ]);

......根据Count in contain Cakephp 3

但是,在多对多关系中Users.round_id不存在。那么,有什么可以改变呢?

注意:已经提出了几个这样的问题,但很少有关于CakePHP 3.x的问题,所以我仍然想尝试一下。

注2:我可以通过使用PHP函数count解决这个问题,但我宁愿更优雅地做到这一点

编辑:如下所示,手动加入似乎可以解决问题:

$rounds_new = $this->Rounds->find()
        ->select($this->Rounds)
        ->select(['user_count' => 'COUNT(Rounds.id)'])
        ->leftJoinWith('Users')
        ->group('Rounds.id');

......有一个问题!没有用户的轮次仍然会得到user_count等于1.可能是什么问题?

1 个答案:

答案 0 :(得分:1)

加入协会

正如评论中已经提到的,您可以随时加入关联而不是包含它们(有点像SUM() on ManyToMany question)。

您为没有任何关联用户的回合检索1计数的原因是您指望错误的表。点数Rounds当然会产生至少1的计数,因为总会有至少1轮,没有关联用户的回合。

如此长的故事,请指望Users

$rounds = $this->Rounds
    ->find()
    ->select($this->Rounds)
    ->select(function (\Cake\ORM\Query $query) {
        return [
            'user_count' => $query->func()->count('Users.id')
        ];
    })
    ->leftJoinWith('Users')
    ->group('Rounds.id');

belongsToMany关联的计数器缓存

还有计数器缓存行为,它也适用于belongsToMany关联,只要它们设置为使用具体的连接表类,可以通过关联配置through选项进行配置:

class RoundsTable extends Table
{
    public function initialize(array $config)
    {
        $this->belongsToMany('Users', [
            'through' => 'RoundsUsers'
        ]);
    }
}

class UsersTable extends Table
{
    public function initialize(array $config)
    {
        $this->belongsToMany('Rounds', [
            'through' => 'RoundsUsers'
        ]);
    }
}

计数器缓存将在连接表类中设置,在此示例RoundsUsersTable中,它将有两个belongsTo个关联,一个到Rounds,一个到{{1} }:

Users

计入收容

如果您实际上已经明确创建了class RoundsUsersTable extends Table { public function initialize(array $config) { $this->belongsTo('Rounds'); $this->belongsTo('Users'); $this->addBehavior('CounterCache', [ 'Rounds' => ['user_count'] ]); } } 个关联(而不是belongsToMany),那么您将拥有hasMany关系,即您仍然可以使用链接的“ count in contain “示例来自one Rounds to many RoundsUsers

然而,这将使您得到一个结构,其中计数将被放置在嵌套实体中,而对于没有任何关联用户的轮次,这又会丢失。我想在大多数情况下这种结构需要重新格式化,所以它可能不是最好的解决方案。但是,为了完成,这是一个例子:

RoundsUsers

另见