10

I have this code

// ONE to many Bidir -- inverse side
    /**
     * @ORM\OneToMany(targetEntity="Item", mappedBy="Room", cascade={"persist"})
     **/
    protected $items;

The other side

// ONE to many Bidir-- own side
    /**
     * @ORM\ManyToOne(targetEntity="Room", inversedBy="items")
     * @ORM\JoinColumn(name="room_id", referencedColumnName="id")
     **/
    protected $room;

My Problem is that i go to item page and i select Room , then i can see items preselecetd in Room page

But if i go to Room page and i try to multiselect many items , then those are not persisted

EDIT: I have seen that it is only happening for OneToMany relation ship. For Manyto Many they are working fine

EDIT2:

I am talking about the backend area where i have the form and select box where i can select multiple items. This form/CRUD code / controllers are genrated by doctrine. SO i don't need to add any extra function. Any way this is my controller code

$editForm   = $this->createForm(new RoomType(), $entity);


        $request = $this->getRequest();

        $editForm->bindRequest($request);
        if ($editForm->isValid()) {
            $em->persist($entity);
            $em->flush();

When i try to walk through in controller like this

foreach($entity->getItems() as $item)
        echo $item;

Then i can see all thye items there. So it means all items are there in main object but its not persisting them. i don't know why.

If there is owing , reverse side problem. How can i chnage the relationship from owing to inverse and inverse to owning

Mirage
  • 28,544
  • 56
  • 155
  • 251

2 Answers2

10

Your code is wrong, based on your comments in annotations.

This is the owning side, because you specify the inversedBy attribute:

/**
 * ONE to many Bidir-- Inverse side
 * @ORM\ManyToOne(targetEntity="Room", inversedBy="items")
 * @ORM\JoinColumn(name="room_id", referencedColumnName="id")
 **/
protected $room;

This is the inverse side (because it has the mappedBy attribute):

/**
 * ONE to many Bidir -- owning side
 * @ORM\OneToMany(targetEntity="Item", mappedBy="Room", cascade={"persist"})
 **/
protected $items;

So your code says: Item is the owning side, Room is the inverse side.

The owning side of a bidirectional relationship must refer to its inverse side by use of the inversedBy attribute of the OneToOne, ManyToOne, or ManyToMany mapping declaration. The inversedBy attribute designates the field in the entity that is the inverse side of the relationship.

To make it more clean:

The owning side has to use the inversedBy attribute of the OneToOne, ManyToOne, or ManyToMany mapping declaration. The inversedBy attribute contains the name of the association-field on the inverse-side.

While, for the inverse side:

The inverse side of a bidirectional relationship must refer to its owning side by use of the mappedBy attribute of the OneToOne, OneToMany, or ManyToMany mapping declaration. The mappedBy attribute designates the field in the entity that is the owner of the relationship.

And, again:

The inverse side has to use the mappedBy attribute of the OneToOne, OneToMany, or ManyToMany mapping declaration. The mappedBy attribute contains the name of the association-field on the owning side.

Plus, another important consideration:

ManyToOne is always the owning side of a bidirectional assocation.

OneToMany is always the inverse side of a bidirectional assocation

Thus, for persisting items from the inverse side (room), you have to check which item has been selected/deselected and if room already contains that item or not.

gremo
  • 45,925
  • 68
  • 233
  • 380
  • 2
    I may be wrong in saying which side is owning and inverse but code should work in both directions. I treid cascade{persist} on each side and on both as well but it didn't work. even if thee is no item for that room , and i select 5 items , nothing is going in database. and this is happening for one more class. so i think i need to add something in my code for inverse to happen. Is my code alright irrespective of what is owning and inverse side – Mirage Aug 17 '12 at 10:47
3

Just use you loop to set room. Item is owing side and you editing inverse side (room). Symfony2 never updates owing sides while editing inverse one.

The simplest solution for you is use loop before persisting room:

foreach($entity->getItems() as $item){
    $item->setRoom($room);
}

and cascade on inverse side:

/**
 * @ORM\OneToMany(targetEntity="Item", mappedBy="Room", cascade={"persist"})
 **/
protected $items;

For my projects I made reusable solution based on collection events listeners. If you have time & skills I encourage you to do the same

Maciej Pyszyński
  • 8,260
  • 3
  • 21
  • 27
  • I think i also need to persist item in the loop as well. Which collection event are you talking about , can you give me reference or any link. – Mirage Aug 22 '12 at 00:37
  • If you got cascade on the inverse side, you don't have to persist them. If you got it before probably all object data was saved, but without parent - room. – Maciej Pyszyński Aug 22 '12 at 12:33
  • Read about form events: http://stackoverflow.com/questions/9651095/description-of-symfony2-form-events, collection is just form embedding items – Maciej Pyszyński Aug 22 '12 at 12:37