09/27/2026
Doctrine addJoin? Use join() or leftJoin()
Doctrine ORM's QueryBuilder has no addJoin() method. Use join(), which is the same as innerJoin(), or leftJoin(). Add the joined alias with addSelect() if you want the related entities loaded in the same query:
// inside ArticleRepository
$qb = $this->createQueryBuilder('a')
->leftJoin('a.author', 'u')
->addSelect('u')
->where('a.published = :published')
->setParameter('published', true);
$articles = $qb->getQuery()->getResult();
The name addJoin() comes from Propel: Propel 1's Criteria class has addJoin($left, $right, $joinType). If you're porting Propel code, or following an answer written for it, that's where it came from. On a Doctrine QueryBuilder it fails with Call to undefined method Doctrine\ORM\QueryBuilder::addJoin().
Which join method to use
| Method | SQL | Rows with no match |
|---|---|---|
join() / innerJoin() |
INNER JOIN |
dropped |
leftJoin() |
LEFT JOIN |
kept, with the joined alias null |
In Doctrine's source, join() simply calls innerJoin(). Each call appends another join, so you can chain as many as you need. The signatures are in Doctrine's Query Builder documentation.
Joining without a mapped association
The first argument is normally an association path such as a.author. When the two entities have no association, pass the class and a condition instead:
use Doctrine\ORM\Query\Expr\Join;
$qb->leftJoin(User::class, 'u', Join::WITH, 'u.id = a.authorId');
That case, including what the query hands back, is covered in joining entities with no association.
How to verify
Print the DQL and the SQL before running the query:
dump($qb->getDQL());
dump($qb->getQuery()->getSQL());
You should see LEFT JOIN a.author u in the DQL and a LEFT JOIN on the authors' table in the SQL.
Doctrine's own docblock on leftJoin() says the joined entities are fetched with the result only when their alias is in the select. Leave out addSelect('u') and the join still runs, but each author loads separately the first time you touch it, one query per article. That's the N+1 problem in a Twig loop.
Questions this raises
Does Doctrine have an addJoin() method?
No. Doctrine ORM's QueryBuilder offers join(), innerJoin() and leftJoin(). addJoin() belongs to Propel's Criteria class.
What is the difference between join() and innerJoin()?
None. In Doctrine's source, join() passes its arguments straight to innerJoin(). Both produce an INNER JOIN.
Why is my joined entity loaded with a separate query?
The join alias isn't in the select. Add ->addSelect('u') after the join and Doctrine hydrates the related entity from the same query.