我有两个实体,商品实体和标签实体。这两个实体之间存在ManyToMany关系(文章可以具有0-> N个标签,并且标签可以包含在0-> N个文章中)
我想在某些条件下搜索文章(我必须使用querybuilder,像findBy()这样的魔术方法还不够),在这些条件下的一种是选择恰好包含N个特定标记的文章
我尝试过几次以取得预期的结果,但没有成功。我想我误解了教义如何与联接表一起工作。我的最后尝试:
public function search($titles, $tags, $authors)
{
$query = $this->createQueryBuilder('a') // a = article
->orderBy('a.createdAt', 'DESC')
->setMaxResults($limit)
->setFirstResult($offset);
if($titles !== null){
// ...
}
// tags is an array of string containing names of searched tags (ex : $tags = ['english', 'french', 'game', 'guide'] )
if($tags !== null){
// $query->innerJoin('a.tags', 't');
// $tagsQuery = "";
// foreach ($tags as $id => $tag){
// if($id > 0) $tagsQuery .= " AND ";
// $tagsQuery .= "t.name LIKE :tag_".$id;
// $query->setParameter("tag_".$id, '%'.$tag.'%');
// }
// $query
// ->andWhere($tagsQuery);
$query->leftjoin ('a.tags','t');
foreach ($tags as $id => $tag){
// $query->andWhere("t.name LIKE :tag_".$id);
// $query->setParameter("tag_".$id, '%'.$tag.'%');
$query
->addSelect('t')
->andwhere("t.name LIKE :tag_".$id)
->setParameter("tag_".$id, '%'.$tag.'%');
}
}
// ...
预期结果的一个例子:
有3篇文章:
- id 1
- tags :
- guide
- game
- id 2
- tags :
- english
- id 3
- tags :
- english
- guide
方法search(null, ['guide','english'], null)
必须仅返回ID为3的文章
如果您希望所有的文章都具有至少一个指定的标签,那么您的代码应该是这样的:
public function search($titles, $tags, $authors)
{
return $query = $this->createQueryBuilder('a') // a = article
->innerJoin('a.tags', 't') //on inner join is enough
->where('t.name in (:set)')
->setParameter('set', $tags)
->orderBy('a.createdAt', 'DESC')
->setMaxResults($limit)
->setFirstResult($offset)
->getQuery() //retrieve
->getResult();
}
此第一个SQL将进行联接。提示是使用“ in”运算符。
[如果您希望文章包含所有标签(实际上是所有标签),则应为每个标签添加一个内部联接。技巧是为每个联接添加一个别名,并为别名上的某物添加唯一的名称。
public function search($titles, $tags, $authors)
{
$query = $this->createQueryBuilder('a') // a = article;
foreach ($tags as $index => $tag) {
$query->innerJoin('a.tags', "t$index")
->andWhere("t$index" + ".name in (:tag$index)")
->setParameter("tag$index", $tag)
}
return $query
->orderBy('a.createdAt', 'DESC')
->setMaxResults($limit)
->setFirstResult($offset)
->getQuery() //retrieve
->getResult();
您的请求应该是这样的。我没有测试它们,但这是模板。
感谢Alexandre的技巧,我得到了解决方案:)
如果有人遇到同样的问题,这里的代码:
foreach ($tags as $id => $tag) {
$query->innerJoin('a.tags', "t${id}")
->andWhere("t${id}.name in (:tag${id})")
->setParameter(":tag${id}", $tag);
}