Symfony2 中的 Doctrine2 (Doctrine 2.1) 急切加载

发布于 2024-12-26 13:48:46 字数 1099 浏览 0 评论 0原文

假设我的 Symfony2 项目中有两个实体:CategoryArticle (一个包含许多文章的类别)。

在我的CategoryRepository中,我有这个方法:

findAllDummy(){
  return $this->createQueryBuilder('c')
              ->leftJoin('c.Articles a')
              ->getQuery()->getResult();
}

如果我没记错的话,在Symfony1.4(以及相应版本的Doctrine)中,返回的对象的'articles'属性将由相应的填充>Article 对象。 现在,在 Symfony2 中,返回 Proxy 对象。

因此,如果我循环浏览特定类别的文章,将执行与迭代一样多的查询。

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中强制预先加载?

Let's say I have two entities in my Symfony2 project : Category and Article (a category having many articles).

In my CategoryRepository, I have this method:

findAllDummy(){
  return $this->createQueryBuilder('c')
              ->leftJoin('c.Articles a')
              ->getQuery()->getResult();
}

If I remember well, in Symfony1.4 (and the corresponding version of Doctrine), the returned objects would have their 'articles' attribute filled by the corresponding Article objects.
Now, in Symfony2, Proxy objects are returned.

So if I loop through a specific category's articles, As many queries as iterations will be executed.

foreach($category->getArticles() as $article){
  echo $article->getDoctrine()
               ->getRepository('')getTitle();
}

I understand this is Doctrine2.1's default lazy loading behavior.

Question 1: how is this a better solution?
N queries instead of 1.

I tried to force eager loading by doing the following:

findAllDummy(){
  return $this->createQueryBuilder('c')
              ->leftJoin('c.articles a')
              ->getQuery()
              ->setFetchMode('Category', 'articles', 'EAGER')
              ->getResult();
}

But the result remains the same.

Question 2: how to force eager loading in Doctrine2?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梦在夏天 2025-01-02 13:48:46

您正在加入一个表,但没有从中选择任何内容。将 ->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 查询无关。它定义了使用 $articleRepository->find(123) 时应加载的内容。

You're joining a table but you're not selecting anything from it. Add ->addSelect('a') to your query builder. Consider two following SQL queries to understand the difference:

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;

Eager/lazy joining has nothing to do with DQL queries. It defines what should be loaded when you use $articleRepository->find(123).

惯饮孤独 2025-01-02 13:48:46

在您尝试“强制预先加载”的部分中,问题可能是您使用 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;

在 Doctrine 文档章节 14.7.6.6 中。暂时更改 DQL 中的获取模式,您可以查看有关如何使用此模式的示例:

$query->setFetchMode("MyProject\User", "address", \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER);

因此,传递对常量的引用或与您要使用的模式相对应的整数。

In the part where you try to "force eager loading" the problem might be that you use the fetchMode method with the wrong variable type for the $fetchMode argument. You pass a string 'EAGER' but the method doesn't expect a string but an integer.

The method expects constants from the ClassMetadata class:

/**
 * 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;

In the Doctrine documentation chapter 14.7.6.6. Temporarily change fetch mode in DQL you can see an example on how to use this:

$query->setFetchMode("MyProject\User", "address", \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER);

So pass either a reference to the constant or an integer that corresponds to the mode you want to use.

_蜘蛛 2025-01-02 13:48:46

正如doctrine docs,在这种情况下急切加载不会产生任何影响,因为类别和文章之间存在一对多关系。

对于一对多关系,将获取模式更改为 eager 将导致对加载的每个根实体执行一个查询。这对惰性获取模式没有任何改进,惰性获取模式也会在访问关联后一对一地初始化关联。

因此,与 @Crozin 所说的相反,您仍然可以在 DQL 中进行预先加载。
如果您有一对一或多对一的关系,急切加载将解决进行额外查询的问题。但是,要解决这种情况下的问题,您应该使用 ->addSelect('a') 正如 @Crozin 提到的。

As it says in the doctrine docs, eager loading in this case won't make any difference because you have one-to-many relationship between Category and Article.

For one-to-many relations, changing the fetch mode to eager will cause to execute one query for every root entity loaded. This gives no improvement over the lazy fetch mode which will also initialize the associations on a one-by-one basis once they are accessed.

So contrary to what @Crozin has said, you can still do eager loading in DQL.
If you have a one-to-one or many-to-one relationship, eager loading will solve the problem of making extra queries. However to solve your problem in this case you should use ->addSelect('a') as @Crozin mentioned.

云淡月浅 2025-01-02 13:48:46

这是一个更好的解决方案,因为连接是一个比简单查询昂贵得多的过程。虽然它可能看起来效率低下,但它并没有太大的浪费,并且当您不加载每个相关对象的所有部分时,它很快就会变得更加高效。

It is a better solution because joins are a much more expensive process than a simple query. While it may seem inefficient, it isn't much of a waste, and quickly becomes more efficient when you aren't loading every bit of every related object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文