16

I'm trying to understand the cascade option in Doctrine in Symfony2.

I would like to be able to delete a child entity (and not trigger the foreign key constraint error.)

I have 3 entities:

Report

/**
* @ORM\OneToMany(targetEntity="Response", mappedBy="report")
*/
protected $responses;

/**
* @ORM\OneToMany(targetEntity="Response", mappedBy="report")
*/
protected $sms;

Response

/**
 * @ORM\ManyToOne(targetEntity="Report", inversedBy="responses")
 */
protected $report;

SMS

/**
 * @ORM\ManyToOne(targetEntity="Report")
 */
protected $report;

Now I would like to delete a Response entity but I get

SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row:
a foreign key constraint fails (mybundle.sms, CONSTRAINT FK_B0A93A77BB333E0D FOREIGN KEY (reportId) REFERENCES report (id))

Where do I use the cascade option and which option should I use (detach or remove)?

I can do a lot of trial and error to figure this out, but I was hoping for an expert explanation, so I don't overlook something.

Peyman Mohamadpour
  • 17,954
  • 24
  • 89
  • 100
user1383418
  • 664
  • 3
  • 8
  • 20

3 Answers3

27

Try using

/**
 * @ORM\ManyToOne(targetEntity="Report", inversedBy="responses")
 * @ORM\JoinColumn(name="reportId", referencedColumnName="id", onDelete="CASCADE")
 */
protected $report;

And then update yor schema. It will add database level Cascading

Ziumin
  • 4,800
  • 1
  • 27
  • 34
  • Yo.. That worked! Thanks. I think I'm going to need to revisit this question shortly, though. I will also want to delete reports.. I'll get to that in a minute.. – user1383418 Nov 14 '12 at 18:34
  • Easy answer Ziumin, thumbs up, but I imagine this deletes all children from the parent? Is there an option to keep those children? For example: I want to delete a user(parent), but keep his blogposts(children). Then make the author of the blogpost null or unknown or something... – nclsvh Dec 08 '15 at 16:34
  • 3
    Try `onDelete="SET NULL"`. – Ziumin Dec 09 '15 at 09:19
12

Ziumin's answer

using the onDelete option for the ORM JoinColumn

method worked when you want to delete a child item (Owning Side).

But if you want to delete a Response which is a parent item (Inverse Side), this is when cascade comes in handy. In the Report entity I added the following for each of its collections (OneToMany relationships):

Report

/**
* @ORM\OneToMany(targetEntity="Response", mappedBy="report", cascade={"remove"})
*/
protected $responses;

/**
* @ORM\OneToMany(targetEntity="SMS", mappedBy="report", cascade={"remove"})
*/
protected $sms;

Now, when I delete a Report, it removes all of its associated entries in the Response and SMS tables.

Peyman Mohamadpour
  • 17,954
  • 24
  • 89
  • 100
user1383418
  • 664
  • 3
  • 8
  • 20
1

You may also use cascade=all for update all actions.

Report

 /**
 * @ORM\OneToMany(targetEntity="Response", mappedBy="report", cascade={"all"})
 */
protected $responses;

 /**
 * @ORM\OneToMany(targetEntity="SMS", mappedBy="report", cascade={"all"})
 */
protected $sms;
Peyman Mohamadpour
  • 17,954
  • 24
  • 89
  • 100
virtustilus
  • 644
  • 6
  • 6
  • 4
    " Do not blindly apply cascade=all to all associations as it will unnecessarily degrade the performance of your application. For each cascade operation that gets activated Doctrine also applies that operation to the association, be it single or collection valued." -> http://doctrine-orm.readthedocs.org/en/latest/reference/working-with-associations.html#transitive-persistence-cascade-operations – Herr Nentu' Sep 05 '15 at 08:18