Reputation: 89
I'll be specific. I have entities quest, city and organizer. When i try to remove organizer, that has relationship with quest error appears
An exception occurred while executing 'DELETE FROM Organizer WHERE id = ?' with params [522]:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (
test
.Quest
, CONSTRAINTFK_82D6D713876C4DDA
FOREIGN KEY (organizer_id
) REFERENCESOrganizer
(id
))
I am absolutely confused with right way of configuring relationships. The logic is:
I am sorry for my very dumb description, but i trying to exclude misunderstandings.
Well, what is right entity relationship should i use for my situation?
class Quest {
...
/**
* @ORM\JoinColumn(name="organizer_id", referencedColumnName="id")
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Organizer")
*/
protected $organizer;
}
class Organizer {
...
/**
* @ORM\Column(type="string", length=140)
*/
protected $name;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\City", inversedBy="organizers")
* @ORM\JoinTable(name="organizers_cities")
*/
protected $cities;
public function __construct() {
$this->quests = new ArrayCollection(); // i don't remember why this is here
}
}
class City {
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Organizer", mappedBy="cities")
*/
protected $organizers;
/**
* Constructor
*/
public function __construct() {
$this->quests = new \Doctrine\Common\Collections\ArrayCollection();
$this->organizers = new \Doctrine\Common\Collections\ArrayCollection();
}
}
Upvotes: 1
Views: 95
Reputation: 3135
You have to configure Doctrine OR your DB to set the relation to null.
With doctrine, just remove your entity so :
$em=$this->getDoctrine()->getEntityManager(); // or getManager() in current Doctrine versions.
$em->remove($organizer);
$em->flush();
With your DB:
Change your JoinColumn annotation :
class Quest {
...
/**
* @ORM\JoinColumn(nullable=false, onDelete="SET NULL",name="organizer_id", referencedColumnName="id")
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Organizer")
*/
protected $organizer;
}
With this second method you will be able to use your DQL query. This method bypass doctrine, and the first is preferred.
Upvotes: 1
Reputation: 89
I forgot about 2 important things.
So, solution is simple, but... see below.
class Quest {
...
/**
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Organizer", inversedBy="quests")
* @ORM\JoinColumn(name="organizer_id", referencedColumnName="id")
*/
protected $organizer;
...
public function removeOrganizer()
{
$this->organizer = null;
return $this;
}
public function removeCity()
{
$this->city = null;
return $this;
}
}
class Organizer {
...
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\City", inversedBy="organizers")
*/
protected $cities;
/**
* @ORM\OneToMany(targetEntity="AppBundle\Entity\Quest", mappedBy="organizer"))
*/
protected $quests;
public function __construct() {
$this->quests = new ArrayCollection();
}
...
/**
* @ORM\PreRemove()
*/
public function removeRelationWithQuests() {
foreach($this->getQuests() as $quest) {
$quest->removeOrganizer()
->setStatus(0);
}
}
}
class City {
...
/**
* @OneToMany(targetEntity="AppBundle\Entity\Quest", mappedBy="city"))
*/
protected $quests;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Organizer", mappedBy="cities")
*/
protected $organizers;
...
/**
* @ORM\PreRemove()
*/
public function removeRelationWithQuests() {
foreach($this->getQuests() as $quest) {
$quest->removeCity()
->setStatus(0);
}
}
}
As you can see I added new functions removeOrganizer and removeCity for Quest Entity and use it with event preRemove in City and Organizer Entity.
PS I have confidence that there is a better practice of solving task like this. So, i am open for criticism for you.
Upvotes: 1
Reputation: 2106
The problem is simple, you can't remove the organizer because is referenced by an existing Quest. In your case you must first remove the relations. I don't know a way of automatically do it with doctrine, but you can configure an event listener in the preRemove event, and make the Quest organizer field to null. I'm not sure if event listeners were implemented in symfony 2.1, but I hope. Also you have the option of doing the relation null directly in the controller before the remove call. The same case apply with cities. Check this documentations links:
How to Register Event Listeners and Subscribers
Hope this help you.
Upvotes: 2