1

I have a series of classes with a slightly complicated set of references between the properties of those classes. I am trying to remove an entity and have that remove be cascaded to its children, but I'm running into foreign key constraint errors. Here is an example of my class structure:

<?php /** * @ORM\Entity * @ORM\Table(name="student_tests") */ class StudentTest implements IEntityAccess { /** * * @var int * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @var StudentTestItem[] * @ORM\OneToMany(targetEntity="StudentTestItem", mappedBy="studentTest", cascade{"remove","persist"}) */ protected $studentTestItems; /** * @var Test * @ORM\ManyToOne(targetEntity="Test", inversedBy="studentTests") */ protected $test; /** * @var \DateTime * @ORM\Column(type="datetime", nullable=true) */ protected $created; /** * @var User * @ORM\ManyToOne(targetEntity="User", inversedBy="studentTests") */ protected $student; } //... <?php /** * @ORM\Entity * @ORM\Table(name="student_test_items") */ class StudentTestItem { /** * * @var int * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @var StudentTest * @ORM\ManyToOne(targetEntity="StudentTest", inversedBy="studentTestItems") */ protected $studentTest; /** * @var User * @ORM\ManyToOne(targetEntity="User", inversedBy="studentTestItems", cascade={"persist"}) */ protected $student; /** * @var TestItem * @ORM\ManyToOne(targetEntity="TestItem", inversedBy="studentTestItems", cascade{"persist"}) */ protected $testItem; } //... /** * * @ORM\Table(name="tests") * @ORM\Entity * * @ORM\HasLifecycleCallbacks */ class Test implements IEntityAccess { /** * * @var int * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @var \DateTime * @ORM\Column(type="datetime", nullable=true) */ protected $startDate; /** * @var StudentTest[] * @ORM\OneToMany(targetEntity="StudentTest", mappedBy="test" ) */ protected $studentTests; /** * @var TestItem[] * @ORM\OneToMany(targetEntity="TestItem", mappedBy="test", cascade={"all"}) */ protected $items; } //... /** * * @ORM\Table(name="test_items") * @ORM\Entity */ abstract class TestItem { /** * * @var int * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @var Test * @ORM\ManyToOne(targetEntity="Test", inversedBy="items") */ /** * @var StudentTestItem[] * @ORM\OneToMany(targetEntity="StudentTestItem", mappedBy="testItem") */ protected $studentTestItems; } /** * This is the primary user object. Used for login and all the other * good stuff. * * @ORM\Table(name="users") * @ORM\HasLifecycleCallbacks class User implements AdvancedUserInterface, \Serializable, IEntityAccess { /** * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") * @var int */ private $id; /** * @var StudentTest[] * @ORM\OneToMany(targetEntity="StudentTest", mappedBy="student", cascade={"persist", "remove"}) */ protected $studentTests; /** * @var StudentTestItem[] * @ORM\OneToMany(targetEntity="StudentTestItem", mappedBy="student", cascade={"persist", "remove"}) */ protected $studentTestItems; } 

Let's say I want to delete a student test, and have that delete cascaded to its StudentTestItem children. To do so, I run the following code inside of a controller.

//... blah blah class definition /** * Delete a student test * * @return \Symfony\Component\HttpFoundation\Response * @Route("/studenttest/delete", name="student_test_delete") */ public function DeleteStudentTestAction(Request $request) { $em = $this->getDoctrine()->getManager(); $studentTest = $em->getRepository("MyAcmeBundle:StudentTest")->findOneBy(array("id" => 3)); $em->remove($studentTest); $em->flush(); return $this->redirect($this->generateUrl('student_delete_success')); } 

When I try to run that code, I get the following error message:

An exception occurred while executing 'DELETE FROM student_tests WHERE id = ?' with params [3]: SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`my_acme_bundle/student_test_items`, CONSTRAINT `FK_71FA2A7F36BB1A1` FOREIGN KEY (`student_test_id`) REFERENCES `student_tests` (`id`)) 500 Internal Server Error - DBALException 

NOW, if I remove all references to studentTestItems from the classes, i.e. I comment out $studentTestItems from the TestItem and User classes, it deletes fine without that issue. Why is this happening? Does Doctrine keep track of the parent references through associations or something?

1 Answer 1

3

Looks like you forgot to add ON DELETE CASCADE to the foreign key constraint. Try changing the following association in class StudentTestItem:

/** * @var StudentTest * @ORM\ManyToOne(targetEntity="StudentTest", inversedBy="studentTestItems") */ protected $studentTest; 

To this:

/** * @var StudentTest * @ORM\ManyToOne(targetEntity="StudentTest", inversedBy="studentTestItems") * @ORM\JoinColumn(name="student_test_id", referencedColumnName="id", onDelete="CASCADE") */ protected $studentTest; 
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, we realized this was the issue. Seems strange that it's necessary though given the cascade={"remove"} -- in my opinion Doctrine really needs to step up their documentation game.
I know how you feel. I get more frustrated with Symfony's documentation of its various component configurations and the fact that it reads like a "text book" rather than a reference document. The latter is better suited for development.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.