我正在使用Symfony 2.8/Doctrine ORM 2.5.2.
我有2个实体,Gallery
OneToManyFile
class Gallery { /** * @var File[] * * @ORM\OneToMany(targetEntity="File", mappedBy="gallery", fetch="EAGER") */ private $files; }
我在文档中看到了两件事.
首先,现在OneToMany关系确实有fetch=EAGER
选项(在此处指定).它在以前的版本中不存在.
其次,对于OneToMany,每个查询的此获取方法的手动设置似乎不可用,但我不知道文档是否是最新的,因为它指出:
在查询期间更改提取模式只能用于一对一和多对一关系.
无论如何我都试过了,这是我的查询:
public function findWithEager() { $qb = $this->createQueryBuilder('g'); $query = $qb->getQuery(); $query->setFetchMode("CommonBundle\\Entity\\Gallery", "files", ClassMetadata::FETCH_EAGER); return $query->getResult(); }
但当我这样做时:
foreach ($galleryRepository->findWithEager() as $gallery) { foreach ($gallery->getFiles() as $file) { $file->getId(); } }
然后我得到1 + n个查询.第一个是SELECT * FROM Gallery
以下n个SELECT * FROM File WHERE id = :galleryId
我希望Doctrine做1 + 1个查询,第二个是查询 SELECT * FROM File WHERE id IN (:galleryListIds)
我错过了什么?这种行为是否在Doctrine中实现?
在最新的学说的changelog状态:
当使用fetch ="EAGER"标记一对多关联时,它现在将执行少于之前的一个查询,并与indexBy结合使用.
目前尚不清楚预期的行为是什么.
欢迎任何见解,谢谢!
一番搜索和一些测试后(使用Doctrine ORM 2.5.6
的PHP 5.6
)我有一些成果。
目前,无法Gallery
通过一个查询获取您的实体,File
而通过第二个查询获取所有相关实体。
使用在一查询中获取Gallery和File实体Left Join
。
这是->find*
设置fetch="EAGER"
注释时方法的作用。
您可以使用DQL手动执行此操作: SELECT g, f FROM Gallery g LEFT JOIN g.files f
如文档中所述,您不能调用->setFetchMode('Gallery', 'files', ClassMetadata::FETCH_EAGER)
DQL查询来获得相同的结果
...对于一对多关系,将获取模式更改为渴望将导致对每个加载的根实体执行一个查询。这没有对惰性获取模式进行任何改进,后者会在访问关联后以一对一的方式初始化关联。
这将导致在您执行第一个查询以获取Gallery实体后立即运行n个其他查询。
通过一个查询获取Gallery实体,然后延迟加载File实体。
这是Doctrine的默认行为(fetch="LAZY"
),将对每个Gallery#$files
访问集产生1个查询和一个附加查询(如果全部访问,则为1 + n个查询)。
未来可能的选择
有一个PR添加了一个EAGER_BATCHED
fetch选项,它可以完全满足您的要求(Gallery
通过一个查询获取实体,然后File
通过第二个查询获取所有实体),但是不幸的是,发生的事情并不多。
如果您使用的是->find*
方法,fetch="EAGER"
则将遵守注释。学说将通过左联接来实现。根据您的数据集,这可能还可以,也可能非常昂贵。
如果您是手动编写DQL或使用查询生成器,则必须LEFT JOIN
一对多关系,并记住将要提取的所有实体添加到select子句中。
我的首选是在您希望热切地获取一对多关系时编写DQL,因为它可以使您的意图明确。