Michaël Gallego

This is my blog. What can you expect here? Well... Zend Framework 2, Amazon AWS...

Twitter

Google+

LinkedIn

Github

Last.fm

Doctrine 2, "unknown column in ON clause"

Dans l’application que je suis en train de réaliser, j’ai eu besoin d’effectuer la jointure suivante avec Doctrine 2 :

$dql = 'SELECT a, s FROM Model_Application a, Model_Mission m
        JOIN a.student s WHERE a.mission = m.id AND m.company = :company';

$result = $this->getEntityManager()->createQuery($dql)
                                   ->setParameter('company', $company)
                                   ->getResult();

Mais rien à faire, j’obtenais sans cesse cette erreur : “Unknown column a0.student_id in ON clause”_, alors que la colonne student_id existe bel est bien dans ma table. En affichant le SQL généré par Doctrine, voici ce que j’obtenais:

SELECT a0_.coverLetter AS coverLetter0, [beaucoup de choses inutiles], a0_.student_id AS student_id5,
a0_.mission_id AS mission_id6 FROM Applications a0_, Missions m2_ INNER JOIN Students s3_ ON a0_.student_id = s3_.id
LEFT JOIN Users u1_ ON s3_.id = u1_.id WHERE a0_.mission_id = m2_.id AND m2_.company_id = ?

Le problème vient simplement de la clause FROM : en effet, depuis MySQL 5.0, la précédence des opérateurs a été modifiée, et la jointure prend la précédence sur le FROM. De ce fait, dans le SQL généré, Missions m2_ est considéré comme l’opérande de gauche du ON et s3_.id est considéré comme l’opérande de droite du ON, a0_.student_id n’étant une opérande pour aucun opérateur, l’erreur est générée.

La solution, en SQL, consiste entourer le contenu du FROM par des parenthèses :

SELECT a0_.coverLetter AS coverLetter0, [beaucoup de choses inutiles], a0_.student_id AS student_id5,
a0_.mission_id AS mission_id6 FROM (Applications a0_, Missions m2_)
INNER JOIN Students s3_ ON a0_.student_id = s3_.id LEFT JOIN Users u1_ ON s3_.id = u1_.id
WHERE a0_.mission_id = m2_.id AND m2_.company_id = ?

Sauf qu’évidemment, ajouter ces mêmes parenthèses dans le DQL ne fonctionne pas, ce serait trop simple. En fait, la solution consiste tout simplement à réorganiser le DQL afin de mettre le JOIN après la première clause du FROM :

$dql = 'SELECT a, s FROM Model_Application a JOIN a.student s, Model_Mission m
        WHERE a.mission = m.id AND m.company = :company';

Et voilà, ça fonctionne ! A noter que la blague m’a coûté une après-midi à me demander pourquoi ça marchait pas :D !