我有 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
如您所见,一切都将迫不及待地获取。
我需要什么?
我想使用单个查询仅检索帖子集以及用户
现在,对于每个帖子条目,我都会得到一个额外的查询:
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();
注意:
我设法通过getResult()
电话enforcingQuery::HYDRATE_ARRAY
摆脱了额外的查询。
查询消失了,节省了三分之一的初始时间。
这里的缺点是,在将关联检索为数组时,我无法再利用Symfony'Component'Serializer'Annotation'Groups
来过滤实体属性,并且必须手动编辑结果集以删除/转换某些值。
编辑
枯萎的答案对于原始帖子是可以的。我没有以正确的方式暴露我的问题。我告诉我想检索 VIP 信息,因为我认为这是摆脱我上面讨论的额外查询的好方法。实际上我不需要 VIP 信息,但省略->leftJoin('u.vip','v')->addSelect('v')
会使教义发出收集 VIP 信息的额外查询!有没有办法阻止教义执行此查询?
Doctrine2 中有两种类型的连接查询:
1)
定期加入
2)
获取联接
查看文档第 14.2.2 章。加入以获取更多详细信息。
因此,如果要获取加入 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 将是摆脱额外查询的最佳方法
摆脱额外的查询,因为您无法延迟加载一对一关系的反面。有关更多详细信息,另请参阅此帖子:
这是预期行为。从技术上讲,一对一关联的反面不能偷懒。反向侧没有外键,因此无法决定是否代理它。我们必须查询关联的对象或联接它。请注意,这仅影响单值关联的反边,即实际上只影响双向一对一关联的反边。
一种解决方案可能是反转关系,使用户成为关系的拥有方。在这种情况下,您至少可以在
User
实体中延迟加载Vip
。延迟加载问题将转移到Vip
侧,这意味着您无法再lazy-load
Vip
User
。否则,您可以使查询返回 Partial 对象以防止加载
Vip
,但通常您应该非常小心这种方法。