Doctrine2 doesn't load Collection until a method is called
Asked Answered
M

1

6

When does Doctrine2 loads the ArrayCollection?
Until I call a method, like count or getValues, I have no data
Here is my case. I have a Delegation entity with OneToMany (bidirectional) relation to a Promotion Entity, like this:

Promotion.php

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Promotion
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\ManyToOne(targetEntity="Delegation", inversedBy="promotions", cascade={"persist"})
     * @ORM\JoinColumn(name="delegation_id", referencedColumnName="id")
     */
    protected $delegation;
}

Delegation.php

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Delegation
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\OneToMany(targetEntity="Promotion", mappedBy="delegation", cascade={"all"}, orphanRemoval=true)
     */
    public $promotions;

    public function __construct() {
        $this->promotions = new \Doctrine\Common\Collections\ArrayCollection();
    }
}

Now I do something like the following (with a given delegation)

$promotion = new Promotion();
$promotion = new Promotion();
$promotion->setDelegation($delegation);
$delegation->addPromotion($promotion);

$em->persist($promotion);
$em->flush();

Looking for the relation into the database is ok. I have my promotion row with the delegation_id set correctly.
And now my problem comes: if I ask for $delegation->getPromotions() I get an empty PersistenCollection, but if I ask for a method of the collection, like $delegation->getPromotions()->count(), everything is ok from here. I get the number correctly. Asking now for $delegation->getPromotions() after that I get the PersistenCollection correctly as well.
Why is this happening? When does Doctrine2 loads the Collection?

Example:

$delegation = $em->getRepository('Bundle:Delegation')->findOneById(1);
var_dump($delegation->getPromotions()); //empty
var_dump($delegation->getPromotions()->count()); //1
var_dump($delegation->getPromotions()); //collection with 1 promotion

I could ask directly for promotions->getValues(), and get it ok, but I'd like to know what is happening and how to fix it.

As flu explains here Doctrine2 uses Proxy classes for lazy loading almost everywhere. But acessing $delegation->getPromotions() should automatically invoke the corresponding fetch.
A var_dump get an empty collection, but using it- in a foreach statement, for example- it is working ok.

Mayhew answered 11/1, 2013 at 9:59 Comment(0)
S
5

Calling $delegation->getPromotions() only retrieves the un-initialized Doctrine\ORM\PersistentCollection object. That object is not part of the proxy (if the loaded entity is a proxy).

Please refer to the API of Doctrine\ORM\PersistentCollection to see how this works.

Basically, the collection itself is again a proxy (value holder in this case) of a real wrapped ArrayCollection that remains empty until any method on the PersistentCollection is called. Also, the ORM tries to optimize cases where your collection is marked as EXTRA_LAZY so that it is not loaded even when you apply some particular operations to it (like removing or adding an item).

Shool answered 29/1, 2013 at 8:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.