web-dev-qa-db-fra.com

Faire une sous-requête WHERE .. IN dans Doctrine 2

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

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 pourrais-je faire cette requête avec le générateur de requêtes?

56
chiborg

Voici comment je l'essayerais:

/** @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 générateur de requêtes n'est pas très bon pour accepter les limites. Jetez un coup d'œil ici , ici et ici .
  • La clause IN est généralement utilisée avec un tableau, mais je pense que cela 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 ne suis pas sûr.

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

97
faken

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

l'exemple de requête dql fonctionne vraiment. Il est vrai que The expr-> in () convertira le second paramètre en un tableau, dans ce cas la chaîne dql. Ce qu'il fait, il crée simplement un tableau avec la chaîne de requête dql comme premier élément. C'est exactement ce que l'Expr\Func attend, un tableau. C'est un peu plus profond dans le code Doctrine 2 que l'élément de tableau de chaîne de requête dql sera géré correctement. (Voir la méthode getInExpression de DBAL/Platforms/AbstractPlatform.php pour plus de détails, le tableau est implosé dans DANS())

9
user1370289