Reputation: 23
I'm getting a foreign constraint violation when trying to cascade delete entities having one-to-one and one-to-many bidirectional relations. Here are my four entities related this way : the "User" object may have zero or one "Contact". Contact may have zero or one "Address" and zero or many "Telephone". But "Contact" must be related to a "User" entity, as well as "Address" and "Telephon"e with a "Contact" entity.
My aim is, when I delete a "User" all the child objects are cascade deleted too ("Contact", "Address" and "Telephone"). However, when I delete a child object, I just want its reference id in the parent entity to be set to NULL.
I've tried several ways including the options onDelete="CASCADE" and onDelete=NULL but I still get the foreign constraint violation error.
User entity
class User
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* Contact
*
* @ORM\OneToOne(targetEntity="Contact", mappedBy="user", cascade={"persist", "remove"})
* @ORM\JoinColumn(nullable=true)
*/
private $contact;
...
}
Contact entity
class Contact
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* Address
*
* @ORM\OneToOne(targetEntity="Address", mappedBy="contact", cascade={"persist", "remove"})
* @ORM\JoinColumn(nullable=true)
*/
private $address;
/**
* Telephones
*
* @ORM\OneToMany(targetEntity="Telephone", mappedBy="contact", cascade={"persist", "remove"})
* @ORM\JoinColumn(nullable=true)
*/
private $telephones;
/**
* User
*
* @ORM\OneToOne(targetEntity="User", inversedBy="contact", cascade={"persist"})
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
*/
private $user;
/**
* Constructeur
*/
public function __construct()
{
$this->telephones = new ArrayCollection();
}
...
}
Address entity
class Address
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\OneToOne(targetEntity="Contact", inversedBy="address", cascade={"persist"})
* @ORM\JoinColumn(name="contact_id", referencedColumnName="id", nullable=false)
*/
private $contact;
...
}
Telephone entity
class Telephone
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="Contact", inversedBy="telephones", cascade={"persist"})
* @ORM\JoinColumn(name="contact_id", referencedColumnName="id", nullable=false)
*/
private $contact;
...
}
Upvotes: 2
Views: 3084
Reputation: 394
Try this configuration. I have only made changes to the @ORM\JoinColumn
annotations by adding onDelete="CASCADE"
. This uses the built in database cascading so you will need to update your schema.
I have also removed some extraneous @ORM\JoinColumn(nullable=true)
annotations on non owning sides of relations. These had no effect and were only misleading.
User entity
class User
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* Contact
*
* @ORM\OneToOne(targetEntity="Contact", mappedBy="user", cascade={"persist", "remove"})
*/
private $contact;
...
}
Contact entity
class Contact
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* Address
*
* @ORM\OneToOne(targetEntity="Address", mappedBy="contact", cascade={"persist", "remove"})
*/
private $address;
/**
* Telephones
*
* @ORM\OneToMany(targetEntity="Telephone", mappedBy="contact", cascade={"persist", "remove"})
*/
private $telephones;
/**
* User
*
* @ORM\OneToOne(targetEntity="User", inversedBy="contact", cascade={"persist"})
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
*/
private $user;
/**
* Constructeur
*/
public function __construct()
{
$this->telephones = new ArrayCollection();
}
...
}
Address entity
class Address
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\OneToOne(targetEntity="Contact", inversedBy="address", cascade={"persist"})
* @ORM\JoinColumn(name="contact_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
*/
private $contact;
...
}
Telephone entity
class Telephone
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="Contact", inversedBy="telephones", cascade={"persist"})
* @ORM\JoinColumn(name="contact_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
*/
private $contact;
...
}
Upvotes: 1
Reputation: 1986
$user->setContact(null);
$contact->setUser(null);
$em->remove($user);
$em->remove($contact);
Upvotes: 0