Doctrine 原则2:按标签检索实体,将所有标签保留在结果中
我有三个Doctrine2实体,相互作用如下:Doctrine 原则2:按标签检索实体,将所有标签保留在结果中,doctrine,many-to-many,query-builder,Doctrine,Many To Many,Query Builder,我有三个Doctrine2实体,相互作用如下: /** * @var ArrayCollection * * @ORM\ManyToMany(targetEntity="MyPackage\MyBundle\Entity\Tag",cascade={"persist"}, * inversedBy="bookmarks") * @ORM\JoinTable(name="bookmark_tag", * joinColumns={@ORM\JoinColumn(n
/**
* @var ArrayCollection
*
* @ORM\ManyToMany(targetEntity="MyPackage\MyBundle\Entity\Tag",cascade={"persist"},
* inversedBy="bookmarks")
* @ORM\JoinTable(name="bookmark_tag",
* joinColumns={@ORM\JoinColumn(name="bkm_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="tag_id", referencedColumnName="id")}
* )
*/
protected $tags;
/**
* @var ArrayCollection
*
* @ORM\ManyToMany(targetEntity="MyPackage\MyBundle\Entity\Tag",cascade={"persist"},
* inversedBy="bookmarks")
* @ORM\JoinTable(name="bookmark_tag",
* joinColumns={@ORM\JoinColumn(name="bkm_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="tag_id", referencedColumnName="id")}
* )
*/
protected $tags;
我需要检索所有带有特定标记的书签,遵守以下规则:
$qb
变量)。我的代码如下所示:
$qb ->select( array('r','t') )
->from('Bookmark', 'r')
->leftJoin('r.tags', 't')
->where( 'r.public = 1')
->andWhere( 't.slug= :slug' )
->orWhere(
$qb->expr()->andX(
'r.user=:uid',
't.slug=:slug'
))
->setParameter('uid', $userId )
->setParameter('slug', $tagSlug );
这个查询的问题是,当我运行
$qb->getQuery()->execute()
时,返回的书签
实体在$tags
下只有一个标记,即由$tagSlug
标识的标记(因此,不符合规则#2)。如果您想获得每个条目的所有标记,您可以使用它。例如,您有带有字段标记的书签实体
/**
* @ORM\OneToMany(targetEntity="Tag", mappedBy="bookmark", cascade={"persist"})
*/
private $tags;
和对书签的引用
/**
* @ORM\ManyToOne(targetEntity="Bookmark",inversedBy="tags")
* @ORM\JoinColumn(name="bookmark_id", referencedColumnName="id")
*/
private $bookmark;
最后一步是创建数组集合
public function __construct()
{
$this->tags = new ArrayCollection();
}
就是这样。现在您可以访问每个书签的所有标记
{% for bookmark in bookmarks %}
<p>{{ bookmark.title }}</p>
{% for tag in bookmark.tags %}
<b>{{ tag.name }}</b>
{% endfor %}
{% endfor %}
{%用于书签中的书签%}
{{bookmark.title}
{bookmark.tags%中标记的%s}
{{tag.name}
{%endfor%}
{%endfor%}
如果您想获得每个条目的所有标签,您可以使用。例如,您有带有字段标记的书签实体
/**
* @ORM\OneToMany(targetEntity="Tag", mappedBy="bookmark", cascade={"persist"})
*/
private $tags;
和对书签的引用
/**
* @ORM\ManyToOne(targetEntity="Bookmark",inversedBy="tags")
* @ORM\JoinColumn(name="bookmark_id", referencedColumnName="id")
*/
private $bookmark;
最后一步是创建数组集合
public function __construct()
{
$this->tags = new ArrayCollection();
}
就是这样。现在您可以访问每个书签的所有标记
{% for bookmark in bookmarks %}
<p>{{ bookmark.title }}</p>
{% for tag in bookmark.tags %}
<b>{{ tag.name }}</b>
{% endfor %}
{% endfor %}
{%用于书签中的书签%}
{{bookmark.title}
{bookmark.tags%中标记的%s}
{{tag.name}
{%endfor%}
{%endfor%}
如果您想获得每个条目的所有标签,您可以使用。例如,您有带有字段标记的书签实体
/**
* @ORM\OneToMany(targetEntity="Tag", mappedBy="bookmark", cascade={"persist"})
*/
private $tags;
和对书签的引用
/**
* @ORM\ManyToOne(targetEntity="Bookmark",inversedBy="tags")
* @ORM\JoinColumn(name="bookmark_id", referencedColumnName="id")
*/
private $bookmark;
最后一步是创建数组集合
public function __construct()
{
$this->tags = new ArrayCollection();
}
就是这样。现在您可以访问每个书签的所有标记
{% for bookmark in bookmarks %}
<p>{{ bookmark.title }}</p>
{% for tag in bookmark.tags %}
<b>{{ tag.name }}</b>
{% endfor %}
{% endfor %}
{%用于书签中的书签%}
{{bookmark.title}
{bookmark.tags%中标记的%s}
{{tag.name}
{%endfor%}
{%endfor%}
如果您想获得每个条目的所有标签,您可以使用。例如,您有带有字段标记的书签实体
/**
* @ORM\OneToMany(targetEntity="Tag", mappedBy="bookmark", cascade={"persist"})
*/
private $tags;
和对书签的引用
/**
* @ORM\ManyToOne(targetEntity="Bookmark",inversedBy="tags")
* @ORM\JoinColumn(name="bookmark_id", referencedColumnName="id")
*/
private $bookmark;
最后一步是创建数组集合
public function __construct()
{
$this->tags = new ArrayCollection();
}
就是这样。现在您可以访问每个书签的所有标记
{% for bookmark in bookmarks %}
<p>{{ bookmark.title }}</p>
{% for tag in bookmark.tags %}
<b>{{ tag.name }}</b>
{% endfor %}
{% endfor %}
{%用于书签中的书签%}
{{bookmark.title}
{bookmark.tags%中标记的%s}
{{tag.name}
{%endfor%}
{%endfor%}
一个书签中只有一个标记(而不是所有标记)是因为数据库供应商只会给你一个(因为WHERE子句中的t.slug=:slug
部分)。尝试在数据库上生成实际的SQL查询,您将看到相同的结果。教条不能使不存在的东西水合
一种可能的解决方案是使用子查询:
$qbOuter
->select(array('ob', 'ot'))
->from('Bookmark', 'ob')
->leftJoin('ob.tags', 'ot')
->where(
$qbOuter->expr()->in(
'ob.id',
$qbInner
->select('ib.id')
->from('Bookmark', 'ib')
->join('ib.tags', 'it')
->where(
$qbInner->expr()->andX(
$qbInner->expr()->eq('it.slug', ':slug'),
$qbInner->expr()->orX(
$qbInner->expr()->eq('ib.public', ':public')
$qbInner->expr()->eq('ib.user', ':user')
)
)
)
->getDql()
)
)
->setParameters(array(
'slug' => $tagSlug,
'public' => true,
'user' => $userId
));
这里有几点需要注意:
- 有两个QueryBuilder在起作用:一个是内部的,一个是外部的
可以接受DQL形式的子查询,这就是为什么在内部QueryBuilder的末尾有一个expr()->in()
调用getDql()
- 在内部查询和外部查询中使用的别名必须彼此不同。这就是为什么我在内部查询中将书签别名为
,在外部查询中将书签别名为ib
。Tag也是如此ob
- 内部QueryBuilder中使用的参数应绑定在外部QueryBuilder上。内部QueryBuilder仅用于为表达式中的
生成DQL
PS:我还对您的查询进行了一些改进(内部查询),并充分利用了表达式库。一个书签中只有一个标记(而不是所有标记)是因为您的数据库供应商只会给您一个(因为WHERE子句中的
t.slug=:slug
部分)。尝试在数据库上生成实际的SQL查询,您将看到相同的结果。教条不能使不存在的东西水合
一种可能的解决方案是使用子查询:
$qbOuter
->select(array('ob', 'ot'))
->from('Bookmark', 'ob')
->leftJoin('ob.tags', 'ot')
->where(
$qbOuter->expr()->in(
'ob.id',
$qbInner
->select('ib.id')
->from('Bookmark', 'ib')
->join('ib.tags', 'it')
->where(
$qbInner->expr()->andX(
$qbInner->expr()->eq('it.slug', ':slug'),
$qbInner->expr()->orX(
$qbInner->expr()->eq('ib.public', ':public')
$qbInner->expr()->eq('ib.user', ':user')
)
)
)
->getDql()
)
)
->setParameters(array(
'slug' => $tagSlug,
'public' => true,
'user' => $userId
));
这里有几点需要注意:
- 有两个QueryBuilder在起作用:一个是内部的,一个是外部的
可以接受DQL形式的子查询,这就是为什么在内部QueryBuilder的末尾有一个expr()->in()
调用getDql()
- 在内部查询和外部查询中使用的别名必须彼此不同。这就是为什么我在内部查询中将书签别名为
,在外部查询中将书签别名为ib
。Tag也是如此ob
- 内部QueryBuilder中使用的参数应绑定在外部QueryBuilder上。内部QueryBuilder仅用于为表达式中的
生成DQL
PS:我还对您的查询进行了一些改进(内部查询),并充分利用了表达式库。一个书签中只有一个标记(而不是所有标记)是因为您的数据库供应商只会给您一个(因为WHERE子句中的
t.slug=:slug
部分)。尝试在数据库上生成实际的SQL查询,您将看到相同的结果。教条不能使不存在的东西水合
一种可能的解决方案是使用子查询:
$qbOuter
->select(array('ob', 'ot'))
->from('Bookmark', 'ob')
->leftJoin('ob.tags', 'ot')
->where(
$qbOuter->expr()->in(
'ob.id',
$qbInner
->select('ib.id')
->from('Bookmark', 'ib')
->join('ib.tags', 'it')
->where(
$qbInner->expr()->andX(
$qbInner->expr()->eq('it.slug', ':slug'),
$qbInner->expr()->orX(
$qbInner->expr()->eq('ib.public', ':public')
$qbInner->expr()->eq('ib.user', ':user')
)
)
)
->getDql()
)
)
->setParameters(array(
'slug' => $tagSlug,
'public' => true,
'user' => $userId
));
这里有几点需要注意:
- 那里