Doctrine2(Doctrine2.1)在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(以及相应版本的

假设我的Symfony2项目中有两个实体:
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在这个上下文中没有。将这两个词视为同义词。嗯。那么,你答案中的两个查询中的任何一个都可以被急切地加载或延迟加载?