我有三个Doctrine2实体,交互如下:
书签实体与Tag实体具有ManyToMany关系,如下所示:
/**
* @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;
我需要使用特定标记检索所有带有标记的书签,并遵守以下规则:
我使用的是Doctrine QueryBuilder(下面代码中的$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()
时,返回的Bookmark
实体在$tags
下只有一个标记,即由$tagSlug
(因此,不符合规则#2)。
答案 0 :(得分:3)
您在书签中只获得1个标记(而不是所有标记)的原因是因为您的数据库供应商只会给您一个(因为WHERE子句中的t.slug = :slug
部分)。尝试Doctrine在数据库上生成的实际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
));
这里需要注意的一些事项:
expr()->in()
可以接受DQL形式的子查询,这就是为什么在内部QueryBuilder末端进行getDql()
调用的原因。ib
或外部查询中的ob
混淆的原因。 Tag也是如此。IN
表达式生成DQL。这里会发生的是内部查询将查找您想要的所有书签ID,外部查询将使用所有相关标签获取这些书签,以便Doctrine可以对它们进行水合。
PS:我还改进了你的查询(内部查询)并充分利用了表达式库。
答案 1 :(得分:0)
如果您希望获得每个条目的所有代码,可以使用aggregate field执行此操作 例如,您有带有字段标记的书签实体
/**
* @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 %}