Doctrine2 (Doctrine 2.1) chargement rapide en Symfony2

disons que j'ai deux entités dans mon projet Symfony2 : Category et Article (une catégorie comportant de nombreux articles).

Dans mon CategoryRepository, j'ai cette méthode:

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

si je me souviens bien, en Symfony1.4 (et la version correspondante de la Doctrine), les objets retournés auraient leur attribut "articles" rempli par leArticle objets. Maintenant, dans Symfony2, les objets Proxy sont retournés.

donc si je boucle à travers une catégorie spécifique articles, autant de requêtes que d'itérations sera exécuté.

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

je comprends que c'est Doctrine2.1 par défaut de chargement paresseux comportement.

Question 1: comment est-ce une meilleure solution? N requêtes au lieu de 1.

j'ai essayé de forcer le chargement impatient de la façon suivante:

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

Mais le résultat reste le même.

Question 2: comment forcer un chargement empressé en Doctrine2?

18
demandé sur j0k 2012-01-12 18:07:41

4 réponses

vous rejoignez une table mais vous n'en sélectionnez rien. Ajouter ->addSelect('a') pour votre générateur de requêtes. Considérez deux requêtes SQL suivantes pour comprendre la différence:

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;

l'adhésion impatiente/paresseuse n'a rien à voir avec les requêtes DQL. Il définit ce qui doit être chargé lorsque vous utilisez $articleRepository->find(123).

18
répondu Crozin 2012-01-12 15:56:17

Dans la partie où vous essayez d' "la force désireux de chargement" le problème pourrait être que vous utilisez le fetchMode méthode avec le mauvais type de variable pour l' $fetchMode argument. Vous passez une chaîne de caractères 'EAGER' mais la méthode n'attend pas une chaîne mais un entier.

La méthode attend des constantes de la ClassMetadata catégorie:

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

Dans la Doctrine de la documentation chapitre 14.7.6.6. Changez temporairement le mode fetch en DQL vous pouvez voir un exemple sur la façon pour utiliser ceci:

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

passez donc soit une référence à la constante soit un entier qui correspond au mode que vous voulez utiliser.

2
répondu Wilt 2015-08-27 14:25:54

Comme il est dit dans le doctrine docs, chargement impatient dans ce cas ne fera pas de différence parce que vous avez une-à-plusieurs relation entre la catégorie et L'Article.

pour les relations un-à-plusieurs, changer le mode fetch en eager provoquera l'exécution d'une requête pour chaque entité racine chargée. Cela ne donne aucune amélioration par rapport au mode fetch paresseux qui initialisera également les associations sur une base individuelle une fois qu'elles seront accéder.

donc contrairement à ce que @Crozin a dit, Vous pouvez toujours faire des chargements rapides en DQL. Si vous avez une relation un-à-un ou plusieurs-à-un, chargement impatient va résoudre le problème de faire des requêtes supplémentaires. Toutefois, afin de résoudre votre problème dans ce cas, vous devez utiliser ->addSelect('a') comme @Crozin l'a mentionné.

0
répondu mufmuf 2017-07-06 10:48:00

c'est une meilleure solution car les jointures sont un processus beaucoup plus coûteux qu'une simple requête. Bien qu'il puisse sembler inefficace, il n'est pas beaucoup d'un gaspillage, et devient rapidement plus efficace lorsque vous ne chargez pas chaque peu de chaque objet connexe.

-2
répondu MrGlass 2012-01-12 15:38:56