67 votes

Effectuer une sous-requête WHERE IN dans Doctrine 2

Je voudrais sélectionner des articles de commande parmi toutes les commandes comportant un article spécifique. En SQL, je le ferais comme suit :

SELECT DISTINCT i.id, i.name, order.name 
FROM items i 
JOIN orders o ON i.order_id=o.id 
WHERE o.id IN (
   SELECT o2.id FROM orders o2
   JOIN items i2 ON i2.order_id=o2.id AND i2.id=5
)
AND i.id != 5
ORDER BY o.orderdate DESC
LIMIT 10

Comment puis-je faire cette requête avec le constructeur de requêtes ?

135voto

faken Points 2489

C'est comme ça que j'essaierais :

/** @var Doctrine\ORM\EntityManager $em */
$expr = $em->getExpressionBuilder();
$em->createQueryBuilder()
   ->select(array('DISTINCT i.id', 'i.name', 'o.name'))
   ->from('Item', 'i')
   ->join('i.order', 'o')
   ->where(
       $expr->in(
           'o.id',
           $em->createQueryBuilder()
               ->select('o2.id')
               ->from('Order', 'o2')
               ->join('Item', 
                      'i2', 
                      \Doctrine\ORM\Query\Expr\Join::WITH, 
                      $expr->andX(
                          $expr->eq('i2.order', 'o2'),
                          $expr->eq('i2.id', '?1')
                      )
               )
               ->getDQL()
       )
   )
   ->andWhere($expr->neq('i.id', '?2'))
   ->orderBy('o.orderdate', 'DESC')
   ->setParameter(1, 5)
   ->setParameter(2, 5)
   ;

Je n'ai pas testé cela bien sûr, et j'ai fait quelques hypothèses sur vos modèles. Problèmes possibles :

  • Limite : cela a été un peu un problème dans Doctrine 2, il semble que le constructeur de requêtes n'est pas très bon pour accepter les limites. Jetez-y un coup d'oeil aquí , aquí y aquí .
  • La clause IN est généralement utilisée avec un tableau, mais je pense qu'elle fonctionnera avec une sous-requête.
  • Vous pouvez probablement utiliser le même paramètre ?1, au lieu de deux paramètres (car ils ont la même valeur), mais je n'en suis pas sûr.

En conclusion, cela ne fonctionnera peut-être pas du premier coup, mais vous mettra sûrement sur la bonne voie. Dites-nous ensuite la réponse finale 100% correcte.

10voto

user1370289 Points 40

Juste pour éviter la confusion du dernier commentaire posté par clang1234.

L'exemple de requête DQL fonctionne vraiment. Il est vrai que la requête The expr->in() transformera le second paramètre en un tableau, dans ce cas la chaîne DQL. Ce qu'il fait, c'est créer un tableau dont le premier élément est la chaîne de caractères de la requête DQL. C'est exactement ce que la méthode Expr\Func attend, un tableau. C'est un peu plus loin dans le code de Doctrine 2 que l'élément tableau de la chaîne de requête dql sera géré correctement. (voir DBAL/Platforms/AbstractPlatform.php méthode getInExpression pour plus de détails, le tableau est implosé en IN() )

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X