我有3个以这种方式关联的实体:
别担心,我已经使用注释设置了关联,但我认为以下混合会更轻/更清楚地暴露我的问题
Post
@ORM\ManyToOne(targetEntity="User", fetch="EAGER")
- author
User
@ORM\OneToOne(targetEntity="Vip", mappedBy="user", fetch="EAGER")
- vip
Vip
# Notice that the primary key of vip is a foreign key on User primary
@ORM\id
@ORM\OneToOne(targetEntity="User", inversedBy="peliqan", fetch="EAGER")
@ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
- user
正如你所看到的,一切都准备好了。
我想检索帖子集以及两者 Users & Vip 仅使用 单一查询 信息。 (参见编辑)
现在,对于每个帖子条目,我都会得到一个额外的查询:
SELECT t0.valid AS valid_1, ...
FROM vip t0
INNER JOIN user t10 ON t0.user_id = t10.id WHERE t0.user_id = ?
何时:
我执行此
$results = $qb
->select('ps')
->leftJoin('ps.author','u')->addSelect('u')
->add('where', $qb->expr()->in('ps.id', $ids))
->getQuery()->getResult();
甚至我尝试强制执行FETCH_EAGER模式就像这样
->getQuery()
->setFetchMode('AppBundle\Entity\User', 'vip', ClassMetadata::FETCH_EAGER)
->getResult();
注意:
我设法在enforcingQuery::HYDRATE_ARRAY
来电时getResult()
删除额外查询
查询消失了,节省了初始时间的三分之一
这里的缺点是,在将关联检索为数组时,我无法再利用Symfony\Component\Serializer\Annotation\Groups
来过滤实体属性,并且必须手动编辑结果集才能删除/转换某些值。
对于原帖,Wilt的回答是可以的。我没有以正确的方式揭露我的问题。我告诉我想要检索Vip信息因为我认为这是摆脱我上面谈到的额外查询的好方法。实际上我不需要 Vip信息,但省略->leftJoin('u.vip','v')->addSelect('v')
会使教条发出收集Vip信息的额外查询!有没有办法阻止学说执行这个查询?
答案 0 :(得分:4)
Doctrine2中有两种连接查询:
1) 常规加入
2) 获取联接
查看the documentation chapter 14.2.2. Joins了解详情。
因此,如果您想要获取加入视频,请在查询中addSelect
和leftJoin
,如下所示:
$results = $qb
->select('ps')
->addSelect('u')->leftJoin('ps.author','u')
->addSelect('v')->leftJoin('u.vip','v')
->add('where', $qb->expr()->in('ps.id', $ids))
->getQuery()->getResult();
评论后更新:
我认为在结果集中包含vip将是摆脱额外查询的最佳方法
您无法摆脱额外的查询,因为您无法延迟加载一对一关系的反面。另请参阅 this post 了解更多详情:
这是预期的行为。从技术上讲,一对一关联的反面不可能是懒惰的。反面没有外键,因此不可能决定是否代理它。我们必须查询关联的对象或加入它。请注意,这只会影响单值关联的反面,即实际上只是双向一对一关联的反面。
解决方案可能是反转关系,以便用户成为关系的拥有方。在这种情况下,您至少可以在Vip
实体中加载User
。延迟加载问题将转移到Vip
方,这意味着您再也无法lazy-load
User
Vip
。{/ p>
否则,您可以让查询返回Partial object以阻止加载Vip
,但一般情况下您应该非常小心这种方法。