使用 Query::matching() 或 Query::innerJoinWith()
从Contacts 表中查询时,您要查找的是Query::matching() 或Query::innerJoinWith(),而不是(仅)Query::contain()。
请注意,通常首选innerJoinWith() 以避免严格分组的问题,因为matching() 会将关联的字段添加到选择列表中,这可能会导致问题,因为它们通常不依赖于功能。
见Cookbook > Database Access & ORM > Query Builder > Filtering by Associated Data
这是一个使用您的表格的示例:
$this->Contacts
->find()
->innerJoinWith('Users', function(\Cake\ORM\Query $q) {
return $q->where(['Users.id' => 1]);
});
这将自动将所需的连接 + 条件添加到生成的查询中,以便仅检索与至少一个 ID 为 1 的用户相关联的联系人。
定位连接表
如果您需要通过hasMany 和belongsTo 手动设置多对多关联,您可以直接定位连接表:
$this->Contacts
->find()
->innerJoinWith('ContactsUsers', function(\Cake\ORM\Query $q) {
return $q->where(['ContactsUsers.user_id' => 1]);
});
包括容器
如果您真的希望在结果中也返回所有关联,那么请继续使用 contain():
$this->Contacts
->find()
->contain('Users')
->innerJoinWith('Users', function(\Cake\ORM\Query $q) {
return $q->where(['Users.id' => 1]);
});
这将包含属于某个联系人的所有用户。
限制收容
如果您有多个匹配项,并且您只想包含这些匹配项,那么您也必须过滤包含。在此示例中,它没有多大意义,因为只有一个匹配项,但在其他情况下它可能很有用,例如,如果您想匹配具有活动用户的所有联系人,并检索仅包括活跃的关联用户:
$this->Contacts
->find()
->contain(['Users' => function(\Cake\ORM\Query $q) {
return $q->where(['Users.active' => true]);
}])
->innerJoinWith('Users', function(\Cake\ORM\Query $q) {
return $q->where(['Users.active' => true]);
})
->group('Contacts.id');
鉴于可能存在重复,即单个联系人的多个活动用户,您可能需要相应地对事物进行分组,以避免检索重复的联系人记录。
深度关联
您还可以通过使用Query::contain() 中已知的点表示路径语法来定位更深层次的关联。例如,假设您有一个 Users hasOne Profiles 关联,并且您只想匹配那些想要接收通知的用户,这可能看起来像这样:
->innerJoinWith('Users.Profiles', function(\Cake\ORM\Query $q) {
return $q->where(['Profiles.receive_notifications' => true]);
})
这将自动创建所有必需的附加连接。
改为从另一个表中选择
通过这些关联和您的简单要求,您还可以轻松地从另一端查询,即通过Users 表并仅使用Query::contain() 来包含关联的联系人,例如
$this->Users
->find()
->contain('Contacts')
->where([
'Users.id' => 1
])
->first();
然后可以在实体contacts 属性中找到所有联系人。