15

我在用户和联系人上有一个 belongsToMany 关联。

我想找到给定用户的联系人。我需要类似的东西

$this->Contacts->find()->contain(['Users' => ['Users.id' => 1]]);

食谱谈到了提供条件来包含,自定义查找器方法和通过关联键唱歌,但我没有找到如何将这些放在一起。

4

2 回答 2

30

使用 Query::matching() 或 Query::innerJoinWith()

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属性中找到所有联系人。

于 2014-11-07T11:26:52.573 回答
3

虽然@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 的用户。还是我过于复杂并且有更好的解决方案?

于 2019-09-10T05:29:43.133 回答