Search code examples
phpmysqlsymfonydoctrinedql

Joining Relationships On Entity SubClasses in Doctrine


I have two entities that share an abstract class creating class table inheritance. I can query for the entities by using the abstract class' repository and get all the entities that extend the abstract class as the result.

$qb = $this->createQueryBuilder('c')
    ->where('c.featured = true')
    ->orderBy('c.sticky', 'DESC')
    ->addOrderBy('c.weight', 'ASC')
    ->setFirstResult($offset)
    ->setMaxResults($limit);

// Returns 8 results, results in 34 queries

The sub classes contain ManyToMany relationships to other entities so if I query in this manner, those relationships result in additional queries since they are not being joined. How can you query for entities extending an abstract class and join their columns? I tried adding multiple from statements with left joins but the query returned fewer than the expected 8 results. That query builder looks something like this:

$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select(array(
    'a', 'artist', 'country', 
    't', 'artwork', 'user'))
   ->from('AcmeArtworkBundle:Artwork', 'a')
   ->from('AcmeTourBundle:Tour', 't')
   ->leftJoin('a.artist', 'artist')
   ->leftJoin('a.country', 'country')
   ->leftJoin('t.artwork', 'artwork')
   ->leftJoin('t.user', 'user')
   ->where('a.featured = true')
   ->andWhere('t.featured = true')
   ->orderBy('a.sticky', 'DESC')
   ->addOrderBy('t.sticky', 'DESC')
   ->addOrderBy('a.weight', 'ASC')
   ->addOrderBy('t.weight', 'ASC')
   ->setFirstResult($offset)
   ->setMaxResults($limit);

// 5 results :-(

Solution

  • From the information provided by the link provided by @Ocramius, By default Doctrine loads entities using lazy loading. Associations are fetched only when they need to be. You can tell Doctrine to automatically fetch an association by setting the fetch mode to EAGER.

    /**
     * @var string $date
     *
     * @ORM\ManyToOne(targetEntity="Date", inversedBy="artwork", cascade={"persist"}, fetch="EAGER")
     * @ORM\JoinColumn(name="date", referencedColumnName="id")
     */
    private $date;
    

    It's important to note that you can actually cause more queries to be run by doing this if you aren't careful.