Doctrine2 OneToMany - ManyToOne returns empty collection with database ok
Asked Answered
D

2

8


I have many relations of this type, but I can't see why this one is not working.
I have a Delegation and a Promotion entities:
Delegation

Promotion

    /**
 * Company\CBundle\Entity\Promotion
 * 
 * @ORM\Entity
 * @DoctrineAssert\UniqueEntity("promotionCode")
 */
class Promotion
{
    const REGISTER_DAYS = 30;
    const REGISTER_DISCOUNT = 100;

    /**
     * @var integer $id
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(name="promotionCode", type="string", unique=true, nullable=true)
     */
    protected $promotionCode;

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

    /**
     * @ORM\Column(name="description", type="string", nullable=true)
     */
    protected $description;

    /**
     * @ORM\Column(name="days", type="integer")
     */
    protected $days;

    /**
     * @ORM\Column(name="discount", type="float")
     */
    protected $discount;

    /**
     * @ORM\ManyToOne(targetEntity="Delegation", inversedBy="promotions")
     * @ORM\JoinColumn(name="delegation_id", referencedColumnName="id")
     */
    private $delegation;

    /**
     * @ORM\ManyToOne(targetEntity="Product", inversedBy="promotions")
     */
    private $product;

    /**
     * @var date $adquiredDate
     *
     * @ORM\Column(name="adquiredDate", type="date", nullable=true)
     */
    private $adquiredDate;

When in a controller I create a promotion, the table Promotion has the new object related to the delegation one

private function createPromotion($delegation)
{
    $em = $this->getDoctrine()->getEntityManager();
    $promotion = Promotion::createPromotion($delegacion, Promotion::REGISTER_DAYS, Promotion::REGISTER_DISCOUNT);
    $em->persist($promotion);
    $em->persist($delegation);

    $em->flush();
}

Database

*************************** 15. row ***************************
           id: 32
delegation_id: 19
         days: 20
     discount: 50
 adquiredDate: 2013-01-10

*************************** 16. row ***************************
           id: 33
delegation_id: 19
         days: 25
     discount: 50
 adquiredDate: 2013-01-10
*************************** 17. row ***************************
           id: 34
delegation_id: 19
         days: 30
     discount: 50
 adquiredDate: 2013-01-10

But when I call the $delegation->getPromotions() in another controller/action there is no promotions, returns a Doctrine\ORM\PersistentCollection with no data.

Can anyone help, please?


Edit with more information. $delegation->getPromotions() is empty, but looking for a promotion of that delegation and calling $promotion->getDelegation() is returning the delegation correctly :?

Dissect answered 10/1, 2013 at 15:39 Comment(2)
Why are you using a static function to create your entities? The __construct function is there for a reason.Amandine
Dependency injection. I only use it for it, when not I use the __construct function as well :)Dissect
L
5

Have you tried defining your $delegation property like

/**
 * @ORM\ManyToOne(targetEntity="Delegation", inversedBy="promotions")
 * @ORM\JoinColumn(name="delegation_id", referencedColumnName="id")
 */
private $delegation;

See Doctrine2 Docs: Association Mapping->Many-To-One


Also there are a lot of typos in your code. For example

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

mappedBy="delegacion" should be mappedBy="delegation".

Or

public function getDeleTacion()
{
    return $this->deleTacion;
}

Should be

public function getDelegation()
{
    return $this->delegation;
}

Edit

Okay, I created a minimalistic version for you that worked for me. You can built it up from there or watch for differences with your code:

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")
     */
    public $delegation;

    /**
     * @ORM\ManyToOne(targetEntity="Product", inversedBy="promotions", cascade={"persist"})
     * @ORM\JoinColumn(name="product_id", referencedColumnName="id")
     */
    public $product;
}

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();
    }
}

Product.php

use Doctrine\ORM\Mapping as ORM;

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

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

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

If you now do something like

$delegation = new Delegation();
$product = new Product();
$promotion = new Promotion();
$promotion->delegation = $delegation;
$promotion->product = $product;

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

$products = $em->createQuery('select p from BundleName\Entity\Product p')->execute();
$delegations = $em->createQuery('select d from BundleName\Entity\Delegation d')->execute();

var_dump(count($products[0]->promotions), count($delegations[0]->promotions));

You should end up with

int(1)
int(1)

So the refrence is in fact saved and can be read. Phew. Good luck with that! :-)

Languishing answered 10/1, 2013 at 15:58 Comment(12)
Thank you for your help. I have already tried using the joincolumn annotation, and I have the same problem.About the typos, I'm sorry, I'm spanish and translate "delegacion" to "delegation" and "promocion" to "promotion" only here, but there is no typos in my code.ThanksDissect
I don't know. It may be a problem having more OneToMany relations in Delegation entity?Dissect
I only see one ;-) Please post your Delegation and Promotion classes (just the property definitions not the methods) so I can have a look at them.Languishing
Sure, sorry then about the spanish, I'm editing the original post.Dissect
I created a basic implementation of your three classes and ran a check on them. Updated my post accordingly.Languishing
Yes, as you indicate the reference is saved and can be read. I guess I'm going to use dql for this, but I don't want to. Even the reference can be read there is no way to read with the getPromotions() method, and don't know why. At any rate, thank you for your help :)Dissect
getPromotions() is no magic method. It should simply return the promotions property of the product or delegation and thus if you add it to my code you can write count($products[0]->getPromotions()). If you don't want to use DQL use a repository class instead. I just wanted to spare me the overhead of creating them too. But at some point you need to get your Product or Delegation entity out of the DB after writing the corresponding Promotion!? You have to use a repository class or DQL. I don't see where your current problem is? Help me out :)Languishing
oh yes, you are right, I didn't read that correctly. I apologize, I'm really tired because of this.Dissect
I edited my last comment. Don't know if that's promoted to you but I think your answer was to the version from before.Languishing
This one is ok. Finally I detected the real problem, but no fix it. $delegation->promotions->count() returns the number correctly, but $delegation->promotions is a PersistenCollection with no data! EDIT: In fact, if I ask for the count first then the collection is loaded, if I don't the collection is empty. It sounds to be a lazy load problem?Dissect
Yes, that's correct. Doctrine2 uses Proxy classes for lazy loading almost everywhere. But acessing $delegation->promotions should automatically invoke the corresponding fetch. But it doesn't for you?Languishing
Yes, I just see it too. I was going crazy. a var_dump($delegation->promotions) get a empty persistentCollection, but using it there is no problem. Thanks for everything.Dissect
V
5

I had a similar error where my many-to-one relationship on some freshly created entities contained entities, and an inverse one-to-many didn't, although database clearly had the corresponding rows in it.

I did persist and flush entities on the one-to-many side, but I had to also do 

$entityManager->clear();

before getting those entities from a repository again for the one-to-many relationship to be able to access those entities.

Vernonvernor answered 1/3, 2019 at 11:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.