Doctrine2(Doctrine2.1)在Symfony2中快速加载
假设我的Symfony2项目中有两个实体:Doctrine2(Doctrine2.1)在Symfony2中快速加载,symfony,doctrine,doctrine-orm,lazy-loading,Symfony,Doctrine,Doctrine Orm,Lazy Loading,假设我的Symfony2项目中有两个实体:Category和Article(一个包含许多文章的类别) 在我的分类报告中,我有以下方法: findAllDummy(){ return $this->createQueryBuilder('c') ->leftJoin('c.Articles a') ->getQuery()->getResult(); } 如果我记得清楚的话,在Symfony1.4(以及相应版本的
Category
和Article
(一个包含许多文章的类别)
在我的分类报告中
,我有以下方法:
findAllDummy(){
return $this->createQueryBuilder('c')
->leftJoin('c.Articles a')
->getQuery()->getResult();
}
如果我记得清楚的话,在Symfony1.4(以及相应版本的条令)中,返回的对象的“articles”属性将由相应的Article
对象填充。
现在,在Symfony2中,将返回代理对象
因此,如果我循环浏览特定类别的文章,将执行与迭代次数一样多的查询
foreach($category->getArticles() as $article){
echo $article->getDoctrine()
->getRepository('')getTitle();
}
我知道这是Doctrine2.1默认的延迟加载行为
问题1:这是一个更好的解决方案吗?
N个查询,而不是1个查询
我尝试通过执行以下操作来强制快速加载:
findAllDummy(){
return $this->createQueryBuilder('c')
->leftJoin('c.articles a')
->getQuery()
->setFetchMode('Category', 'articles', 'EAGER')
->getResult();
}
但结果仍然是一样的
问题2:如何在Doctrine2中强制快速加载?这是一个更好的解决方案,因为连接过程比简单查询要昂贵得多。虽然它看起来效率很低,但它并不是一种浪费,当您不加载每个相关对象的每一位时,它会很快变得更高效。您正在加入一个表,但没有从中选择任何内容。将
->addSelect('a')
添加到查询生成器中。考虑以下两个SQL查询来理解差异:
SELECT a.id, a.title
FROM article a
JOIN category c ON a.category_id = c.id
WHERE a.id = 123;
SELECT a.id, a.title, c.id, c.name
FROM article a
JOIN category c ON a.category_id = c.id
WHERE a.id = 123;
渴望/惰性加入与DQL查询无关。它定义了当您在尝试“强制快速加载”的部分中使用
$articlerrepository->find(123)
时应加载的内容。问题可能是您对$fetchMode
参数使用的fetchMode
方法的变量类型错误。您传递了一个字符串'EAGER'
,但该方法不需要字符串,而需要整数
该方法需要ClassMetadata
类中的常量:
/**
* Specifies that an association is to be fetched when it is first accessed.
*/
const FETCH_LAZY = 2;
/**
* Specifies that an association is to be fetched when the owner of the
* association is fetched.
*/
const FETCH_EAGER = 3;
在条令文件章节14.7.6.6中。暂时更改DQL中的提取模式您可以看到一个关于如何使用该模式的示例:
$query->setFetchMode("MyProject\User", "address", \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER);
因此,传递一个对常量的引用或一个与您想要使用的模式对应的整数。正如在中所说的,在这种情况下,即时加载不会有任何区别,因为类别和文章之间存在一对多关系
对于一对多关系,将fetch模式更改为eager将导致为每个加载的根实体执行一个查询。这与延迟获取模式相比没有任何改进,延迟获取模式也会在访问关联后逐个初始化关联
因此,与@Crozin所说的相反,您仍然可以在DQL中进行快速加载。
如果您有一对一或多对一的关系,快速加载将解决进行额外查询的问题。然而,要解决这种情况下的问题,您应该使用@Crozin提到的
->addSelect('a')
。@Crozin我仍然有点困惑……当您说“它定义了应该加载的内容”时,您指的是什么是水合的吗?@SamSelikoff是的,如果您定义了文章关系上的fetch=EAGER
,所有文章都将被加载(和水合)当你调用categoryRepository->findOne(321)
加载和水合有什么区别?@SamSelikoff在这个上下文中没有。将这两个词视为同义词。嗯。那么,你答案中的两个查询中的任何一个都可以被急切地加载或延迟加载?