CakePHP 3 - 计算多对多关联
CakePHP 3 - Count many-to-many Association
我有一个包含 Rounds 和 Users 的数据库。 Rounds belongsToMany Users 和 Users belongsToMany Rounds,因此是多对多关系。为此添加了连接 table rounds_users。
编辑:此处使用了错误的短语。我的意思是 'belongsToMany' 而不是 'hasMany'
现在我想检索回合列表,以及每回合链接的用户数。
在一对多关系的情况下,像下面这样的东西会起作用:
$rounds = $this->Rounds->find()
->contain(['Users' => function ($q)
{
return $q->select(['Users.id', 'number' => 'COUNT(Users.round_id)'])
->group(['Users.round_id']);
}
]);
...根据
但是,在多对多关系中 Users.round_id
不存在。那么,什么可以代替呢?
注:这样的问题已经问了好几个了,但是关于Cake的很少PHP3.x,所以我还是想试试这个。
注意 2:我可以通过使用 PHP 函数 count
来解决这个问题,尽管我宁愿做得更优雅
编辑:如下所示,手动加入似乎可以解决问题:
$rounds_new = $this->Rounds->find()
->select($this->Rounds)
->select(['user_count' => 'COUNT(Rounds.id)'])
->leftJoinWith('Users')
->group('Rounds.id');
...有一个问题!没有用户的回合仍然得到等于 1 的 user_count
。可能是什么问题?
加入协会
正如评论中已经提到的,您始终可以加入协会而不是包含它们(有点像您的 )。
您为没有任何关联用户的回合检索计数 1
的原因是您计算错误 table。计数 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
关联,只要它们被设置为使用具体的连接 table class,可以配置通过关联配置 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'
]);
}
}
计数器缓存将在连接 table class 中设置,在此示例中 RoundsUsersTable
,它将有两个 belongsTo
关联,一个到 Rounds
和一到 Users
:
class RoundsUsersTable extends Table
{
public function initialize(array $config)
{
$this->belongsTo('Rounds');
$this->belongsTo('Users');
$this->addBehavior('CounterCache', [
'Rounds' => ['user_count']
]);
}
}
遏制计数
如果您实际上明确创建了 hasMany
关联(而不是 belongsToMany),那么您将拥有 one Rounds to many RoundsUsers
关系,即您仍然可以使用链接的“ ”示例来自 RoundsUsers
.
但是,这会给您留下一个结构,在该结构中,计数将放置在嵌套实体中,而对于没有任何关联用户的轮次,该实体又会丢失。我想在大多数情况下,这种结构需要重新格式化,所以它可能不是最好的解决方案。然而,为了完整起见,这里有一个例子:
$rounds = $this->Rounds
->find()
->contain(['RoundsUsers' => function (\Cake\ORM\Query $query) {
return $query
->select(function (\Cake\ORM\Query $query) {
return [
'RoundsUsers.round_id',
'number' => $query->func()->count('RoundsUsers.round_id')
];
})
->group(['RoundsUsers.round_id']);
}]
);
另见
- Cookbook > Database Access & ORM > Query Builder > Filtering by Associated Data
- Cookbook > Database Access & ORM > Query Builder > Returning the Total Count of Records
- Cookbook > Database Access & ORM > Behaviors > CounterCache
- Cookbook > Database Access & ORM > Associations - Linking Tables Together > BelongsToMany Associations > Using the ‘through’ Option
我有一个包含 Rounds 和 Users 的数据库。 Rounds belongsToMany Users 和 Users belongsToMany Rounds,因此是多对多关系。为此添加了连接 table rounds_users。 编辑:此处使用了错误的短语。我的意思是 'belongsToMany' 而不是 'hasMany'
现在我想检索回合列表,以及每回合链接的用户数。
在一对多关系的情况下,像下面这样的东西会起作用:
$rounds = $this->Rounds->find()
->contain(['Users' => function ($q)
{
return $q->select(['Users.id', 'number' => 'COUNT(Users.round_id)'])
->group(['Users.round_id']);
}
]);
...根据
但是,在多对多关系中 Users.round_id
不存在。那么,什么可以代替呢?
注:这样的问题已经问了好几个了,但是关于Cake的很少PHP3.x,所以我还是想试试这个。
注意 2:我可以通过使用 PHP 函数 count
来解决这个问题,尽管我宁愿做得更优雅
编辑:如下所示,手动加入似乎可以解决问题:
$rounds_new = $this->Rounds->find()
->select($this->Rounds)
->select(['user_count' => 'COUNT(Rounds.id)'])
->leftJoinWith('Users')
->group('Rounds.id');
...有一个问题!没有用户的回合仍然得到等于 1 的 user_count
。可能是什么问题?
加入协会
正如评论中已经提到的,您始终可以加入协会而不是包含它们(有点像您的
您为没有任何关联用户的回合检索计数 1
的原因是您计算错误 table。计数 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
关联,只要它们被设置为使用具体的连接 table class,可以配置通过关联配置 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'
]);
}
}
计数器缓存将在连接 table class 中设置,在此示例中 RoundsUsersTable
,它将有两个 belongsTo
关联,一个到 Rounds
和一到 Users
:
class RoundsUsersTable extends Table
{
public function initialize(array $config)
{
$this->belongsTo('Rounds');
$this->belongsTo('Users');
$this->addBehavior('CounterCache', [
'Rounds' => ['user_count']
]);
}
}
遏制计数
如果您实际上明确创建了 hasMany
关联(而不是 belongsToMany),那么您将拥有 one Rounds to many RoundsUsers
关系,即您仍然可以使用链接的“RoundsUsers
.
但是,这会给您留下一个结构,在该结构中,计数将放置在嵌套实体中,而对于没有任何关联用户的轮次,该实体又会丢失。我想在大多数情况下,这种结构需要重新格式化,所以它可能不是最好的解决方案。然而,为了完整起见,这里有一个例子:
$rounds = $this->Rounds
->find()
->contain(['RoundsUsers' => function (\Cake\ORM\Query $query) {
return $query
->select(function (\Cake\ORM\Query $query) {
return [
'RoundsUsers.round_id',
'number' => $query->func()->count('RoundsUsers.round_id')
];
})
->group(['RoundsUsers.round_id']);
}]
);
另见
- Cookbook > Database Access & ORM > Query Builder > Filtering by Associated Data
- Cookbook > Database Access & ORM > Query Builder > Returning the Total Count of Records
- Cookbook > Database Access & ORM > Behaviors > CounterCache
- Cookbook > Database Access & ORM > Associations - Linking Tables Together > BelongsToMany Associations > Using the ‘through’ Option