[英]How to load all associations for a result set in a single query in Doctrine2
I have some pretty basic entities, containing stories and tags, which I'm trying to load as efficiently as possible. 我有一些漂亮的基本实体,其中包含故事和标签,我试图尽可能高效地加载它们。
When I query for stories like this: 当我查询这样的故事时:
SELECT a FROM Foo\Article a WHERE a.id IN (1,2,3,4,5)
I see see the following SQL queries being run: 我看到正在运行以下SQL查询:
SELECT f0_.id AS id_0, f0_.title AS title_1 FROM foo_article f0_ WHERE f0_.id IN (1, 2, 3)
SELECT t0.name AS name_1, t0.article_id AS article_id_2 FROM foo_tag t0 WHERE t0.article_id = 1
SELECT t0.name AS name_1, t0.article_id AS article_id_2 FROM foo_tag t0 WHERE t0.article_id = 2
SELECT t0.name AS name_1, t0.article_id AS article_id_2 FROM foo_tag t0 WHERE t0.article_id = 3
Where I would like to see this: 我想看到的地方:
SELECT f0_.id AS id_0, f0_.title AS title_1 FROM foo_article f0_ WHERE f0_.id IN (1, 2, 3)
SELECT t0.name AS name_1, t0.article_id AS article_id_2 FROM foo_tag t0 WHERE t0.article_id IN (1, 2, 3);
Source code looks like this. 源代码看起来像这样。 Abbreviated from the actual code. 实际代码的缩写。
<?php
namespace Foo;
use Doctrine\ORM\Mapping as ORM;
/**
* Class Tag
*
* @ORM\Entity()
* @ORM\Table(name="foo_tag")
*
* @package Foo
*/
class Tag {
/**
* @ORM\Column(type="string")
* @ORM\Id()
*/
protected $name;
/**
* @ORM\ManyToOne(targetEntity="\Foo\Article",cascade={"persist"},fetch="LAZY",inversedBy="tags")
* @ORM\Id()
*/
protected $article;
}
/**
* Class Article
*
* @ORM\Entity()
* @ORM\Table(name="foo_article")
*
* @package Foo
*/
class Article {
/**
* @ORM\Id @ORM\Column(type="integer", name="id") @ORM\GeneratedValue
*/
protected $id;
/**
* @ORM\Column(type="string")
*/
protected $title;
/**
* @ORM\OneToMany(targetEntity="\Foo\Tag",mappedBy="article",cascade={"persist"},fetch="EAGER")
*/
protected $tags;
}
One possible approach I was thinking about myself would be adding something like this to my repository class. 我在想自己的一种可能方法是在存储库类中添加类似的内容。 But it just doesn't feel quite right just yet. 但这还不是很正确。 I want something that's more portable to other associations, works every time the Entity is queried, and also works with Paginated queries. 我想要一种对其他关联更可移植的东西,在每次查询实体时都可以使用,并且还可以用于分页查询。
Perhaps something in a postLoad-like event, that covers an entire result set (instead of the per-entity postLoad). 可能是类似postLoad的事件中的某个事件,它覆盖了整个结果集(而不是每个实体的postLoad)。
$qb = $entityManager->getRepository('Foo\Article')->createQueryBuilder('a')
->where('a.id IN (1,2,3)');
$list = $qb->getQuery()->execute();
/** @var Foo\Article[] $indexed */
$indexed = array_reduce($list, function($result, \Foo\Article $article) {
$result[$article->getId()] = $article;
return $result;
}, Array());
$tags = $entityManager->getRepository('Foo\Tag')->createQueryBuilder('t')
->where('t.article IN (:ids)')
->setParameter('ids', $indexed)
->getQuery()->execute();
array_map(function(\Foo\Tag $tag) use ($indexed) {
/** @var \Doctrine\ORM\PersistentCollection $collection */
$collection = $tag->getArticle()->getTags();
$collection->add($tag);
$collection->setInitialized(true);
}, $tags);
foreach($indexed as $article) {
$article->getTags()->takeSnapshot();
$article->getTags()->setInitialized(true);
}
/** @var Foo\Article $article */
// and now use the Articles and Tags, to make sure that everything is loaded
foreach($list as $article) {
$tags = $article->getTags();
print " - ".$article->getTitle()."\n";
foreach($tags as $tag) {
print " - ".$tag."\n";
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.