我得到了以下查询
SELECT news.*, count(*) AS common_tags
FROM news
JOIN news_news_tag ON news.id = news_news_tag.news_id
WHERE news_tag_id IN
(SELECT news_tag_id FROM news_news_tag WHERE news_id = 2 )
AND news.id != 2 GROUP BY news.id ORDER BY common_tags DESC
我想要实现的是通过提供的新闻id获得按公共标签数量排序的水合新闻对象。News
和Tag
与news_news_tag
联接表是多对多关系。
CCD_ 4实体具有更多的其他关系。这就是为什么我不想自己创建一个本地查询来处理所有其他关系。我想将上面的查询转换为与查询生成器一起使用。我无法使用DQL,因为我的where
语句使用了联接(junction(表,而且我还需要在该表上使用join
。
总而言之,我有两个问题:
如何创建DQL子查询以从多对多联接表中选择内容(?如果我知道我可以做一些类似的事情:
->where($queryBuilder->expr()->in('u.id', $mySubQueryAsDQL))
如何在
where
语句中添加我可以使用news_tag_id
的join
语句?
如果不可能,我认为我需要创建两个双向的一对多和多对一关系,而不是多对多,并处理特殊的连接实体。
我终于想出了以下解决方案。我决定将该查询拆分为两个单独的查询。首先,我可以使用简单的原始查询,因为我只需要where
语句的结果。第二个查询可以使用查询生成器以正常方式构建。你只需要在末尾去掉一个多余的计数列。
然而,如果有人知道如何在查询生成器中直接使用我的第一个原始查询作为where语句的原始子查询的解决方案,请与我分享。
public function getRelatedNews($newsId, $limit = 6)
$connection = $this->getEntityManager()->getConnection();
$sql = 'SELECT news_tag_id FROM news_news_tag WHERE news_id = :newsId';
try {
$stmt = $connection->prepare($sql);
} catch (DBALException $e) {
return [];
}
$stmt->execute(['newsId' => $newsId]);
$newsTagId = $stmt->fetchAll();
if (empty($newsTagId)) {
return [];
}
$newsTagId = array_column($newsTagId, 'news_tag_id');
$query = $this->createQueryBuilder('n')
->addSelect('COUNT(n.id) as common_tags_count')
->innerJoin("n.tags", "t")
->andWhere('t.id IN(:tagsId)')->setParameter('tagsId', array_values($newsTagId))
->andWhere('n.id != :newsId')->setParameter('newsId', $newsId)
->orderBy('common_tags_count', 'DESC')
->setMaxResults($limit)
->groupBy('n.id')
;
$results = $query->getQuery()->getResult();
$news = [];
foreach ($results as $result) {
$news[] = $result[0];
}
return $news;
}