4

I have a self-referencing One-to-Many association on an entity (User) mapped by 'parent' and inversed by 'children'. I want to be able to remove users that are not parents. My entity is declared as follows.

class User implements UserInterface
{
   /**
    * @ORM\Column(name="id", type="smallint")
    * @ORM\Id
    * @ORM\GeneratedValue(strategy="AUTO")
    */
   protected $id;

   (...)

   /**
    * @ORM\OneToMany(targetEntity="User", mappedBy="parent")
    */
   protected $children;

   /**
    * @ORM\ManyToOne(targetEntity="User", inversedBy="children")
    * @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
    */
   protected $parent;

   public function __construct()
   {
       $this->parentId = null; // Default value for column parent_id
       $this->children = new ArrayCollection();
   }
}

When I try to remove a child user that is not a parent, I am getting the following error.

exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails

I have tried doing a cascade delete, as follows.

/**
 * @ORM\OneToMany(targetEntity="User", mappedBy="parent", cascade={"persist", "remove"})
 */
protected $children;

Getting the same error either way. Any help?

Elnur Abdurrakhimov
  • 44,533
  • 10
  • 148
  • 133
Gopi Kalyan
  • 129
  • 2
  • 13

3 Answers3

9

Use this:

/**
* @ORM\ManyToOne(
*     targetEntity="User", 
*     inversedBy="children", 
*     cascade={"persist", "remove"}
* )
*
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="SET NULL")
*/

What onDelete="SET NULL" does is that when you delete a parent, its child element will get NULL value in parent_id column. This happens on DB level so you must doctrine:schema:update.

Zeljko
  • 5,048
  • 5
  • 36
  • 46
  • I made the change and db shows the delete rule as "SET NULL" for the FK constraint on running doctrine:schema:update. I also took off cascade={'remove'}. However, deleting a child user also deletes the parent user and if I am logged in as that parent user I get _InvalidArgumentException: You cannot refresh a user from the EntityUserProvider that does not contain an identifier_ Right now, I am trying to delete a child, user not a parent user. Thanks. – Gopi Kalyan Oct 24 '12 at 14:28
  • Also tried doing this in the action. `$parentUser->removeChild($childUser); $em->persist($childUser); $em->persist($parentUser); $em->remove($childUser); $em->flush();` That is not working either. CASCADE and SET NULL both remove the parent user when removing the child user. – Gopi Kalyan Oct 24 '12 at 14:40
  • Delete `cascade={"persist", "remove"}`. This is kinda weird as I have similar relation and everything works fine. To be able to remove children from parent, you must put: `@ORM\OneToMany(targetEntity="User", mappedBy="parent", cascade={"all"})` . If that works, try cascade={"persist"} (instead of "all") if that would work too (it would be better to cut it down). If everything fails, then you have to do this with unit tests. – Zeljko Oct 24 '12 at 15:01
  • Tried that and it is still removing the parent user when I delete the child. I now have `cascade={"persist"}` for the children and `onDelete="SET NULL"` for the parent properties. Does anyone want anymore information from me to help me resolve this? Thanks. – Gopi Kalyan Oct 24 '12 at 15:19
  • I don't see any other way than you to make unit tests to solve it. It is way quicker that way than manually refreshing the page, change DB etc. – Zeljko Oct 25 '12 at 13:00
  • What if you only need to unset the parent and not delete it. For me setting null for the parent id did not work. Addionaly im using api platform.Not sure if the issue is with doctrine or Api platform. – lk404 May 24 '23 at 04:24
0

At last, I managed to remove a child Category while keeping the parent Category:

$parent = $em->getRepository('Category\Entity\Category')->find(1);//parent id
$child = $em->getRepository('Category\Entity\Category')->find(5);// child id
$parent->removeChild($child);
    $em->persist($child);
    $em->remove($child);
    $em->persist($parent);      
    $em->flush(); 
Oskar
  • 2,522
  • 32
  • 37
-1

cascade has to be on the owning side:

/**
 * @ORM\ManyToOne(
 *     targetEntity="User", 
 *     inversedBy="children", 
 *     cascade={"persist", "remove"}
 * )
 */
protected $parent;
Elnur Abdurrakhimov
  • 44,533
  • 10
  • 148
  • 133
  • I tried that and I am getting the same error when trying to remove a child user. Also, I don't want the child users removed when a parent user is removed, they can continue as orphan elements. Adding 'cascade' to the owning side and updating my schema with the console command has no effect on the actual db schema when I checked. Could that be a problem? – Gopi Kalyan Oct 24 '12 at 11:22