Doctrine 2.5 意外的关联获取行为 [Symfony 3]
Posted
技术标签:
【中文标题】Doctrine 2.5 意外的关联获取行为 [Symfony 3]【英文标题】:Doctrine 2.5 Unexpected association fetch behavior [Symfony 3] 【发布时间】:2016-11-10 03:36:41 【问题描述】:我有 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
如您所见,一切都已准备就绪。
我需要什么?
我想仅使用 单个查询检索帖子集以及 both 用户 & 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
来过滤实体属性,并且必须手动编辑结果集才能删除/转换某些值。
编辑
原始帖子的威尔特答案是可以的。我没有以正确的方式揭露我的问题。我告诉我要检索 Vip 信息,因为我认为这是摆脱我上面所说的额外查询的好方法。其实我不需要 Vip 信息,但省略->leftJoin('u.vip','v')->addSelect('v')
使学说发出额外的查询来收集Vip 信息!有没有办法阻止学说执行这个查询?
【问题讨论】:
【参考方案1】:Doctrine2 中有两种连接查询:
1) 常规连接 2) 获取连接
查看the documentation chapter 14.2.2. Joins了解更多详情。
因此,如果您想获取加入 vip,您应该在查询中 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 了解更多详情:
这是预期行为。从技术上讲,一对一关联的反面不能偷懒。反面没有外键,因此无法决定是否代理它。我们必须查询关联的对象或加入它。请注意,这只影响单值关联的反面,即实际上只影响双向一对一关联的反面。
一种解决方案可能是反转关系,使用户成为关系的拥有方。在这种情况下,您至少可以在 User
实体中延迟加载 Vip
。延迟加载问题将转移到Vip
方面,这意味着您不能再将lazy-load
User
放在Vip
中。
否则,您可以让查询返回 Partial object 以防止加载 Vip
,但通常您应该非常小心这种方法。
【讨论】:
感谢您的宝贵时间。其实这是我知道的。我没有以正确的方式暴露我的问题。我认为在结果集中包含 vip 将是获得 额外查询 的最佳方式。我希望我不会在这里弄得一团糟。一次又一次地为你点赞,谢谢。 我或许应该再提出一个问题…… 事情对我来说越来越清楚了,我需要发现一个cannot lazy load the inverse side of a one-to-one relationship
。我已阅读拥有方必须是持有外键的实体。这就是我将 Vip 设为拥有方的原因(它的 PK 是指向 User id PK 的外键)。最后,获取我需要的信息的最轻松/最快的方法是强制执行 Query::HYDRATE_ARRAY。我猜想防止对象水合,然后没有额外的查询来解决关系的反面。我仍然必须处理 mysql 延迟行查找问题现象。以上是关于Doctrine 2.5 意外的关联获取行为 [Symfony 3]的主要内容,如果未能解决你的问题,请参考以下文章
Doctrine em 在 Codeigniter 中获取关联数据
Doctrine 2.1.6 逆向工程 1-n(一对多)关联被误解为 1-1(一对一)
教义:在 OneToMany 关联中忽略了 mappedBy 的值