我在用户和联系人上有一个 belongsToMany 关联。
我想找到给定用户的联系人。我需要类似的东西
$this->Contacts->find()->contain(['Users' => ['Users.id' => 1]]);
食谱谈到了提供条件来包含,自定义查找器方法和通过关联键唱歌,但我没有找到如何将这些放在一起。
我在用户和联系人上有一个 belongsToMany 关联。
我想找到给定用户的联系人。我需要类似的东西
$this->Contacts->find()->contain(['Users' => ['Users.id' => 1]]);
食谱谈到了提供条件来包含,自定义查找器方法和通过关联键唱歌,但我没有找到如何将这些放在一起。
从Contacts
表中查询时,您要查找的是Query::matching()
or Query::innerJoinWith()
,而不是 (only) Query::contain()
。
请注意,这innerJoinWith()
通常是首选,以避免严格分组的问题,因为matching()
会将关联的字段添加到选择列表中,这可能会导致问题,因为它们通常不依赖于功能。
请参阅Cookbook > 数据库访问和 ORM > 查询构建器 > 按关联数据过滤
这是使用您的表格的示例:
$this->Contacts
->find()
->innerJoinWith('Users', function(\Cake\ORM\Query $q) {
return $q->where(['Users.id' => 1]);
});
这将自动将所需的连接 + 条件添加到生成的查询中,以便仅检索与至少一个具有 id 的用户相关联的联系人1
。
hasMany
如果您通过and手动设置多对多关联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
属性中找到所有联系人。
虽然@ndm 的回答让我遇到了类似的问题,但解决方案需要稍作调整。问题是让用户通过 joinTable 上的数据过滤,添加匹配没有返回用户。所以这就是我最终的结果,希望它会对某人有所帮助。
$this->Contacts
->find()
->contain('Users', function(\Cake\ORM\Query $q) {
return $q->matching('ContactsUsers', function(\Cake\ORM\Query $q) {
return $q->where(['ContactsUsers.some_field' => 1]);
}
});
这让我联系了在关联表中将 some_field 设置为 1 的用户。还是我过于复杂并且有更好的解决方案?