Krleza
Krleza

Reputation: 107

Doctrine launching too many querys witn an innerJoin

Given this code, Doctrine launchs as many querys as rows I have in table2

$qb = $this->getModelManager()->createQuery($er->getClassName(), 't1')->getQueryBuilder();

$qb->select('t1, t2, t3')
   ->innerJoin('table1.table2', 't2');
   ->innerJoin('table2.table3', 't3')
   ->where('t3.id = :foo')
   ->setParameter('foo', $foo);

each query is like this one:

SELECT t0.id AS id_1,
       t0.name AS name_2, 
       t0.slug AS slug_3,
       t0.description AS description_4, 
       t0.visible AS visible_5 
FROM table2 t0 
WHERE t0.id = ?

and those are the entities:

TABLE1: The main entity, witch is related to table 2 by manyToOne if I make the innerJoin with table 2, Doctrine act as expected (1 query)

/**
 * @ORM\Entity(repositoryClass = "Table1Repo")
 * @ORM\Table(name="table1")
 */
class table1 extends BaseTable1 implements table1Interface
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\Column(type="string", length=255)
     * @Gedmo\Versioned
     */
    protected $name;

    /**
     * @ORM\ManyToOne(targetEntity="table2", inversedBy="tables1")
     * @ORM\JoinColumn(name="table2_id", referencedColumnName="id", onDelete="CASCADE")
     */
     protected $table2;
}

TABLE2, related with table one by OneToMany, and with table 3 by ManyToMany.

/**
 * @ORM\Entity(repositoryClass="table2Repository")
 * @ORM\Table(name="table2")
 */
class table2 extends Basetable2
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\ManyToMany(targetEntity="table3", inversedBy="table2s")
     * @ORM\JoinTable(name="table3_table2")
     */
    protected $table3;

    /**
     * @ORM\OneToMany(targetEntity="table1", mappedBy="table2")
     * @Accessor(getter="getTables1")
     */
    protected $tables1;
}

TABLE3: oly related with table 2 by a ManyToMany relation. When I make the innerJoin with table 2, Doctrine still acts as expected, making only one query

/**
 * @ORM\Entity(repositoryClass = "table3Repo")
 * @ORM\Table(name="table3")
 * @Gedmo\Loggable
 */
class table3 extends Basetable3
{
    /**
     * @ORM\Id 
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\ManyToMany(targetEntity="table2", mappedBy="tables3")
     * @ORM\JoinTable(name="table3_table2")
     */
    protected $tables2;
}

So, as I add both innerJoins to the query Builder, Doctrine makes only one query, but is when I add the WHERE clause, when Doctrine makes the 279 querys, one per row in table2, witch is related with table1 by oneToMany and with table3 by ManyToMany.

Other relevant point is that the querybuilder is beeing executed under SonataAdmin query_builder fiel option.

I can't find why I'm getting this behaviour, any clue?

Upvotes: 0

Views: 70

Answers (1)

Jovan Perovic
Jovan Perovic

Reputation: 20201

When you run a query, you always need to have a root entity which joins to others. In your case, that is table1. After fetching, based on query and entity metadata, Doctrine will attempt to create an object for each instance of root, but unless told otherwise, it will stop there. In fact, for each sub-objects (e.g. table2), it will create dummy "proxy" objects which are barely shallow representations, and are to be resolved from DB whenever to try to dereference them. The process of converting DB results to objects is known as object hydration.

In order to do perform hydration of sub-objects, you need to "select" sub-entity as well:

$qb->select('t1', 't2', 't3')
    ->innerJoin('t1.table2', 't2');
    ->innerJoin('t2.table3', 't3')
    ->where('t3.id = :foo')
    ->setParameter('foo', $foo);

Pay attention not to go crazy with fetching everything, as it takes longer and consumes reasonably more RAM. Fine-tune your query, until you reach what you want (logic and performance-wise).

Hope this helps...

Upvotes: 2

Related Questions