user1684343
user1684343

Reputation: 115

Symfony2: Left Join producing wrong query

I'm trying to build a query with doctrine query builder like this:

$q = $this
        ->createQueryBuilder('u')
        ->select('u, r')
        ->leftJoin('u.roles', 'r')
        ->where('u.username = :username OR u.email = :email')
        ->setParameter('username', $username)
        ->setParameter('email', $username)
        ->getQuery();`

This code produces 2 queries:

Query 1 is correct

SELECT t0.user_id AS user_id1, t0.username AS username2, t0.salt AS salt3, t0.password AS password4, t0.email AS email5, t0.is_active AS is_active6, t0.created AS created7, t0.updated AS updated8, t0.last_login AS last_login9 
FROM users t0 
WHERE t0.username = ? 
LIMIT 1 

Query 2 is not correct:

SELECT t0.role_id AS role_id1, t0.role AS role2 
FROM roles t0 
INNER JOIN user_role ON t0.id = user_role.role_id 
WHERE user_role.user_fk = ?

Query 2 should be:

SELECT t0.role_id AS role_id1, t0.role AS role2 
FROM roles t0 
INNER JOIN user_role ON t0.role_id = user_role.role_fk 
WHERE user_role.user_fk = ?

Entity\Role looks like this:

/**
 * @ORM\Table(name="roles")
 * @ORM\Entity(repositoryClass="XXX\XXXBundle\Entity\Repository\RoleRepository")
 */
class Role implements RoleInterface
{
    /**
     * @ORM\Id
     * @ORM\Column(name="role_id", type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $_roleId;
    /**
     * @ORM\Column(name="role", type="string", length=20, unique=true)
     */
    protected $_role;
    /**
     * @ORM\ManyToMany(targetEntity="User", mappedBy="roles")
     * @ORM\JoinTable(name="user_role",
     *     joinColumns={@ORM\JoinColumn(name="role_fk", referencedColumnName="role_id")})
     */
    private $_users;
...

Entity\User looks like this:

class User implements UserInterface, \Serializable  
    {
        /**
         * @ORM\Column(name="user_id", type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $_userId;
        ...
        /**
         * @ORM\ManyToMany(targetEntity="Role", inversedBy="users")
         * @ORM\JoinTable(name="user_role",
         *     joinColumns={@ORM\JoinColumn(name="user_fk", referencedColumnName="user_id")})
         */
        protected $_roles;
    ...

The annotation in the Entity\Role code states the column names to use and the SELECT portion of the statement is using the correct names. The WHERE portion of the statement is using the correct column user_role.user_fk, this is defined in the Entity\User code.

How do I stop doctrine using column names that do not exist and use the defined column names for the INNER JOIN part of the statement?

Upvotes: 0

Views: 417

Answers (1)

user1684343
user1684343

Reputation: 115

I found a solution which works.

Entity\User needs to be altered to include the inverseJoinColumns on the annotation like this:

/**
 * @ORM\ManyToMany(targetEntity="Role", inversedBy="_users")
 * @ORM\JoinTable(name="user_role",
 *     joinColumns={@ORM\JoinColumn(name="user_fk", referencedColumnName="user_id")},
 *     inverseJoinColumns={@ORM\JoinColumn(name="role_fk", referencedColumnName="role_id")})
 */
protected $_roles;

Entity\Role needs to be altered to include the inverseJoinColumns like this:

/**
 * @ORM\ManyToMany(targetEntity="User", mappedBy="_roles")
 * @ORM\JoinTable(name="user_role",
 *     joinColumns={@ORM\JoinColumn(name="role_fk", referencedColumnName="role_id")},
 *     inverseJoinColumns={@ORM\JoinColumn(name="user_fk", referencedColumnName="user_id")})
 */
private $_users;

and the createQueryBuilder code needs to look like this:

$q = $this
        ->createQueryBuilder('u')
        ->select('u, r')
        ->from('XXXXXXBundle:User', 'u')
        ->leftJoin('u.roles', 'r', \Doctrine\ORM\Query\Expr\Join::ON, 'user_role.role_kf = r.role_id')
        ->where('u.username = :username OR u.email = :email')
        ->setParameter('username', $username)
        ->setParameter('email', $username)
        ->getQuery();

Upvotes: 1

Related Questions