我阅读了cookbook,但我无法弄清楚如何在单个查询中合并matching()
和orWhere()
。
示例:我Photo
属于Album
。两者都有active
字段。所以我正在尝试编写findInactive()
方法。 “非活动”照片的active
字段false
或与active
字段为false
的相册相匹配。
这样的事情:
public function findInactive(Query $query, array $options)
{
$query->matching('Albums', function ($q) {
return $q->where(['Albums.active' => false]);
})
->orWhere(['Photos.active' => false])
->enableAutoFields(true);
return $query;
}
但这不起作用:
'SELECT [...] FROM photos Photos INNER JOIN photos_albums Albums ON (Albums.active = :c0 AND Albums.id = (Photos.album_id)) WHERE Photos.active = :c1'
怎么办?感谢。
修改
也许可能的解决方案是使用contain()
:
$query->contain(['Albums => ['fields' => ['active']]])
->where(['Photos.active' => false])
->orWhere(['Albums.active' => false]);
但是无法使用matching()
或innerJoinWith()
吗?
答案 0 :(得分:0)
matching()
或innerJoinWith()
是错误的方法,因为条件被添加到INNER
连接ON
子句中,这将导致{Photo
连接1}} Albums.active
条件不匹配时要排除的行。
如果您只想接收属于相册的照片,则需要使用matching()
或innerJoinWith()
,但您必须将条件添加到主查询中,即:
$query
->innerJoinWith('Albums')
->where(['Albums.active' => false])
->orWhere(['Photos.active' => false])
// ...
如果照片不必属于某个相册,或者它是否属于相册并不重要,则可以使用leftJoin()
,leftJoinWith()
甚至contain()
。
后者可能会使用INNER
joinStrategy
和/或select
strategy
(使用单独的查询),因此您需要照顾确保它使用LEFT
和join
代替。但是,如果你真的想要包含某些内容,通常只会建议使用包含,并且考虑到你的查找器似乎只是过滤器,我会说leftJoinWith()
代替:
$query
->leftJoinWith('Albums')
->where(['Albums.active' => false])
->orWhere(['Photos.active' => false])
// ...