Doctrine 2 cascade={''remove"} doesn't seem to be working
Asked Answered
M

3

18

Hi I have the following class

namespace MP\User\RegistrationBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Persistence\PersistentObject;
use MP\Services\SiteAdapterBundle\Util\String;
/**
 * @ORM\Table(name="customer")
 * @ORM\Entity(repositoryClass="MP\User\RegistrationBundle\Repositories\CustomerRepository")
 * @ORM\HasLifecycleCallbacks
 */
class Customer extends PersistentObject
{
    
    /**
     * @var string $id
     * @ORM\Id
     * @ORM\Column(name="icustomer_id", type="integer")
     */
    protected $id;

    /**
     * @var string $addresses
     * @ORM\OneToMany(targetEntity="MP\User\RegistrationBundle\Entity\Address", mappedBy="customer", cascade={"remove"})
     */
    protected $addresses;

With the following relationship

/**
 * MP\User\RegistrationBundle\Entity
 */
namespace MP\User\RegistrationBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Persistence\PersistentObject;

/**
 * @ORM\Table(name="custdeladd") 
 * @ORM\Entity(repositoryClass="MP\User\RegistrationBundle\Repositories\AddressRepository")
 */
class Address extends PersistentObject
{
      /**
       * @var integer $suffix
       * @ORM\Column(name="isuffix", type="integer") 
       * @ORM\Id
       */
      protected $suffix;

      /**
       * @var object $customer
       * @ORM\ManyToOne(targetEntity="MP\User\RegistrationBundle\Entity\Customer", inversedBy="addresses", cascade={"persist"})
       * @ORM\JoinColumn(name="icustomer_id", referencedColumnName="icustomer_id")
       */
      protected $customer;
}

Does anybody know why when the customer gets deleted the addresses aren't? Many thanks

Maurice answered 15/10, 2012 at 12:30 Comment(1)
cascade={"remove"} worked for meEverest
S
45

Your relationship definition seems to be fine. What is the way the customer is deleted? I mean Doctrine doesn't set "ON DELETE CASCADE" directly in database. So, if you remove customer entity in other way than "doctrine's" one, comments won't be deleted.

You may tell doctrine to set this directly in database, by adding in annotation:

@ORM\JoinColumn(name="icustomer_id", referencedColumnName="icustomer_id", onDelete="CASCADE")

But if you're trying remove the entity in right-doctrine way ant this still doesn't work, try add "orphanRemoval" to true, it should help:

// Customer.php
/**
 * @var string $addresses
 * @ORM\OneToMany(targetEntity="MP\User\RegistrationBundle\Entity\Address", mappedBy="customer", cascade={"remove"}, orphanRemoval=true)
 */
protected $addresses;
Stubble answered 16/10, 2012 at 9:37 Comment(1)
Thanks a lot, the mappedBy="customer", cascade={"remove"}, orphanRemoval=true jig on the OneToMany did the trick, I am sure I tried this before but..Maurice
K
18

I had quite a bit of trouble getting this to work. Here's some points that might help those having similar troubles:

  1. The owning entity needs @OneToMany( ... cascade={"remove"} or cascade={"all"} )
  2. The child entity also needs @JoinColumn(... onDelete="CASCADE")
  3. Also, if you are modifying the onDelete="CASCADE" part I believe you will need to update your schema before your changes take effect.
Kerns answered 10/3, 2015 at 23:32 Comment(2)
This should effectively get you the desired result, if you still can't get it to work you might want to clear your cache, it took me several minutes to figure out cache is the culprit.Cerveny
So why does the child entity also need onDelete="CASCADE"? Why doesn't it just work with cascade={"remove"}?Iain
C
1

I tried the answers above, but got the same foreign key constraint violation.

My code was something like the following:

class FooBar
{
    /**
     * @ORM\OneToMany(
     *     targetEntity="Foo",
     *     mappedBy="foobar",
     *     cascade={"persist", "remove"},
     *     orphanRemoval=true
     * )
     * @var Collection|Foo[]
     */
    private $fooCollection;

    /**
     * @return Collection|Foo[]
     */
    public function getFooCollection()
    {
        return $this->fooCollection;
    }

    /**
     * @param Collection|Foo[] $fooCollection
     *
     * @return $this
     */
    public function setFooCollection($fooCollection): FooBar
    {
        $this->fooCollection = $fooCollection;
        return $this;
    }
}

class Foo
{
    // ... some more properties & ID here ....

    /**
     * @ORM\OneToMany(
     *     targetEntity="Bar",
     *     mappedBy="foo",
     *     cascade={"persist", "remove"},
     *     orphanRemoval=true
     * )
     * @var Collection|Bar[]
     */
    private $barCollection;

    /**
     * @ORM\ManyToOne(
     *     targetEntity="FooBar",
     *     inversedBy="fooCollection"
     * )
     * @ORM\JoinColumn(
     *     name="fooBarId",
     *     referencedColumnName="fooBarId",
     *     nullable=false
     * )
     * @var FooBar
     */
    private $fooBar;

    public function __construct()
    {
        $this->barCollection = new ArrayCollection();
    }

    /**
     * @return Bar[]|Collection
     */
    public function getBarCollection()
    {
        return $this->barCollection;
    }

    /**
     * @param Bar[]|Collection $barCollection
     *
     * @return $this
     */
    public function setBarCollection($barCollection): Foo
    {
        $this->barCollection = $barCollection;
        return $this;
    }

    /**
     * @return FooBar
     */
    public function getFooBar(): FooBar
    {
        return $this->fooBar;
    }

    /**
     * @param FooBar $fooBar
     *
     * @return $this
     */
    public function setFooBar(FooBar $fooBar): Foo
    {
        $this->fooBar = $fooBar;
        return $this;
    }

    // ... some more getters & setters here ...
}

class Bar
{
    // ... some more properties & ID here ....

    /**
     * @ORM\ManyToOne(
     *     targetEntity="Foo",
     *     inversedBy="barCollection"
     * )
     * @ORM\JoinColumn(
     *     name="fooId",
     *     referencedColumnName="fooId",
     *     nullable=false
     * )
     * @var Foo
     */
    private $foo;

    // ... some more getters & setters here ...
}

I had another part of the program, where I tried to remove all Foo's corresponding to a FooBar, with the following code.

$fooBar = new FooBar();
$fooBar->setFooCollection([]);

$entityManager->persist($foorBar);
$entityManager->flush();

This gave an foreign key exception on the relationship between Foo and Bar "Cannot delete or update a parent row: a foreign key constraint fails".

Adding the following method to FooBar:

/**
     * @param Foo[] $collection
     */
    public function removeFooCollection($collection)
    {
        /** @var Foo $entry */
        foreach ($collection as $entry)
        {
            $this->fooCollection->removeElement($entry);
            $entry->setFooBar(null);
        }
    }

And using the following code to remove all Foo's related to the FooBar:

$fooBar->removeFooCollection(
     $fooBar->getFooCollection()
);
$entityManager->persist($fooBar);
$entityManager->flush();

Fixed all foreign key constraint issues.

Croydon answered 9/5, 2019 at 12:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.