Doctrine 2.5意外关联获取行为[Symfony 3]

时间:2016-07-07 17:37:38

标签: php doctrine-orm symfony query-builder doctrine-query

我有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信息的额外查询!有没有办法阻止学说执行这个查询?

1 个答案:

答案 0 :(得分:4)

Doctrine2中有两种连接查询:

1) 常规加入
2) 获取联接

查看the documentation chapter 14.2.2. Joins了解详情。

因此,如果您想要获取加入视频,请在查询中addSelectleftJoin,如下所示:

$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,但一般情况下您应该非常小心这种方法。