web-dev-qa-db-fra.com

Doctrine utilisant une jointure interne avec des conditions

J'aimerais construire le code SQL suivant à l'aide du générateur de requêtes de Doctrine:

select c.*
from customer c
join phone p
on p.customer_id = c.id
and p.phone = :phone
where c.username = :username

J'ai d'abord essayé

$qb->select('c')
    ->innerJoin('c.phones', 'p', Join::ON, $qb->expr()->andx(
        $qb->expr()->eq('p.customerId', 'c.id'),
        $qb->expr()->eq('p.phone', ':phone')
    ))
    ->where('c.username = :username');

Mais j'obtiens l'erreur suivante

Error: expected end of string, got 'ON'

Puis j'ai essayé

$qb->select('c')
    ->innerJoin('c.phones', 'p')
    ->where('c.username = :username')
    ->andWhere('p.phone = :phone');

qui semble fonctionner. Cependant, est-ce que quelqu'un sait ce qui ne va pas avec la première tentative? J'aimerais faire fonctionner le premier car il ressemble plus étroitement à la structure de SQL. Merci d'avance!

Note: Je sais que nous pouvons aussi écrire mysql ou dql en natif avec Doctrine, mais je préférerais que le constructeur de requêtes soit créé.

EDIT: Ci-dessous le code complet

namespace Cyan\CustomerBundle\Repository;

use Cyan\CustomerBundle\Entity\Customer;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join;

class CustomerRepository extends EntityRepository
{
    public function findCustomerByPhone($username, $phone)
    {
        $qb = $this->createQueryBuilder('c');

        $qb->select('c')
            ->innerJoin('c.phones', 'p', Join::ON, $qb->expr()->andx(
                $qb->expr()->eq('p.customerId', 'c.id'),
                $qb->expr()->eq('p.phone', ':phone')
            ))
            ->where('c.username = :username');

//        $qb->select('c')
//            ->innerJoin('c.phones', 'p')
//            ->where('c.username = :username')
//            ->andWhere('p.phone = :phone');

        $qb->setParameters(array(
            'username' => $username,
            'phone' => $phone->getPhone(),
        ));

        $query = $qb->getQuery();
        return $query->getResult();
    }
}
35
Mr. 14

Je vais répondre à ma propre question.

  1. innerJoin devrait utiliser le mot clé "WITH" au lieu de "ON" (la documentation de la doctrine [13.2.6. Méthodes auxiliaires] est inexacte; [13.2.5. La classe Expr] est correcte)
  2. il n'est pas nécessaire de lier les clés étrangères dans la condition de jointure car elles sont déjà spécifiées dans le mappage d'entité.

Par conséquent, ce qui suit fonctionne pour moi

$qb->select('c')
    ->innerJoin('c.phones', 'p', 'WITH', 'p.phone = :phone')
    ->where('c.username = :username');

ou

$qb->select('c')
    ->innerJoin('c.phones', 'p', Join::WITH, $qb->expr()->eq('p.phone', ':phone'))
    ->where('c.username = :username');
82
Mr. 14

Vous pouvez explicitement avoir une jointure comme ceci:

$qb->innerJoin('c.phones', 'p', Join::ON, 'c.id = p.customerId');

Mais vous devez utiliser l'espace de noms de la classe Join from doctrine:

use Doctrine\ORM\Query\Expr\Join;

Ou si vous préférez comme ça:

$qb->innerJoin('c.phones', 'p', Doctrine\ORM\Query\Expr\Join::ON, 'c.id = p.customerId');

Sinon, Join class ne sera pas détecté et votre script se bloquera ...

Voici le constructeur de la méthode innerJoin:

public function innerJoin($join, $alias, $conditionType = null, $condition = null);

Vous pouvez trouver d'autres possibilités (non seulement rejoindre "ON", mais aussi "WITH", etc ...) ici: http://docs.doctrine-project.org/fr/2.0.x/reference/ query-builder.html # la-classe-expr

[~ # ~] éditer [~ # ~]

Je pense que cela devrait être:

$qb->select('c')
    ->innerJoin('c.phones', 'p', Join::ON, 'c.id = p.customerId')
    ->where('c.username = :username')
    ->andWhere('p.phone = :phone');

    $qb->setParameters(array(
        'username' => $username,
        'phone' => $phone->getPhone(),
    ));

Sinon, je pense que vous faites un mélange de ON et de, peut-être le problème.

10
Sybio