I have a relationship OneToOne bidirectional, configurate how cascade persis, remove, but when i call controller eliminarPersonaFisicaAction, this show the next error:
An exception occurred while executing 'DELETE FROM entidad WHERE id = ?' with params [84]:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`xxx`.`personafisica`, CONSTRAINT `FK_D55D20169B1A19BB` FOREIGN KEY (`id_entidad`) REFERENCES `entidad` (`id`))
This is my configure in entities:
First entity:
//code
/**
* #ORM\OneToOne(targetEntity="XXX\EntidadBundle\Entity\PersonaFisica", mappedBy="entidad", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="persona_fisica_id", referencedColumnName="id")
**/
private $personaFisica;
//code
Second entity:
//code
/**
* #ORM\OneToOne(targetEntity="XXX\EntidadBundle\Entity\Entidad", inversedBy="personaFisica", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="id_entidad", referencedColumnName="id")
*/
protected $entidad;
//code
eliminarPersonaFisicaAction:
public function eliminarPersonaFisicaAction($id){
$em = $this->getDoctrine()->getManager();
$personaFisica = $em->getRepository("EntidadBundle:Entidad")->find($id);
if($personaFisica->getPresupuestosEnLosQueEsContacto()->isEmpty() && $personaFisica->getPresupuestos()->isEmpty() && $personaFisica->getDocumentos()->isEmpty() && $personaFisica->getAsignacionesExternas()->isEmpty()){
$em->remove($personaFisica);
}
$em->flush();
return $this->redirect($this->generateUrl('ver_personas_fisicas'));
}
Please note that cascade={"persist", "remove"} only affect the internal Doctrine2 persistence and removal. It has nothing to do with the database.
In order to tell DB to explicitly add 'onDelete' property to the column you should use onDelete="CASCADE"in JoinColumn config.
//code
/**
* #ORM\OneToOne(targetEntity="XXX\EntidadBundle\Entity\PersonaFisica", mappedBy="entidad", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="persona_fisica_id", referencedColumnName="id", onDelete="CASCADE")
**/
private $personaFisica;
//code
You don't need to specify JoinColumn on two tables, it is enough that only one table have extra id field. From what I see in your code you should add JoinColumn to Entidad entity. That will make Entidad entity to be deleted when PersonaFisica is deleted.
Related
An entity project can have many personnages, many chapitres, one highConcept for each project. And the user can have many projects. Then, when I want to remove a project I have this error message :
An exception occurred while executing 'DELETE FROM projets WHERE id = ?' with params [2]:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (writtle.personnages, CONSTRAINT FK_286738A6C18272 FOREIGN KEY (projet_id) REFERENCES projets (id))
this is my entities:
Personnages Entity
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Chapitre", mappedBy="personnages")
* #ORM\JoinColumn(name="projet_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $chapitres;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Projets", inversedBy="personnages")
* #ORM\JoinColumn(name="projet_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $projet;
Projet entity
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="projets")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Personnages", mappedBy="projet")
*/
private $personnages;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Chapitre", mappedBy="projet", cascade={"remove"})
* #ORM\joinColumn(onDelete="SET NULL")
*/
private $chapitres;
Chapitre entity
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Projets", inversedBy="chapitres")
*/
private $projet;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Personnages", inversedBy="chapitres")
*/
private $personnages;
HighConcept
/**
* #ORM\OneToOne(targetEntity="App\Entity\Projets", cascade={"persist", "remove"})
*/
private $projet;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="highconcepts")
*/
private $user;
User entity
/**
* #ORM\OneToMany(targetEntity="App\Entity\Projets", mappedBy="user")
*/
private $projets;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Highconcept", mappedBy="user")
*/
private $highconcepts;
I don't know how I can relate this, I tried some things like JoinColumn ondelete cascade...
I see some topics, but I think I use it correctly.
Considering that you want to remove all the entities contained in your project I suggest you to use the orphanRemoval option as explained in the Doc.
There is another concept of cascading that is relevant only when removing entities from collections. If an Entity of type A contains references to privately owned Entities B then if the reference from A to B is removed the entity B should also be removed, because it is not used anymore.
making the members of your entity look like:
/**
* #ORM\OneToMany(targetEntity="App\Entity\Personnages", mappedBy="projet", orphanRemoval=true)
*/
private $personnages;
I try to use the doctrine cascade={"remove"} but it doesn't work.
The situation :
I have announces that contains many pictures (one picture can refer to only one announce). I want that when i delete the announce from the DB it's remove the pictures too.
Here is my code :
Entity announce :
/**
* Announce
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="AppBundle\Entity\Announce\AnnounceRepository")
*/
class Announce
{
/**
* #ORM\OneToOne(targetEntity="AppBundle\Entity\Announce\PictureAnnounce", inversedBy="coverAnnounce")
* #ORM\JoinColumn(name="cover_picture_id", referencedColumnName="id", nullable=true)
*/
private $coverPicture;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Announce\PictureAnnounce", mappedBy="announce", cascade={"remove"})
*/
private $pictureAnnounces;
}
Entity pictureAnnounce :
/**
* AppBundle\Entity\Announce\PictureAnnounce
*
* #ORM\Table(name="picture_announce")
* #ORM\Entity(repositoryClass="AppBundle\Entity\Announce\PictureAnnounceRepository")
* #ORM\HasLifecycleCallbacks
*/
class PictureAnnounce
{
/**
* #ORM\OneToOne(targetEntity="AppBundle\Entity\Announce\Announce", mappedBy="coverPicture", cascade={"persist"})
*/
private $coverAnnounce;
/**
* #var Announce $announce
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Announce\Announce", inversedBy="pictureAnnounces")
* #ORM\JoinColumn(name="announce_id", referencedColumnName="id", nullable=false)
*/
private $announce;
The code for the delete (i set coverPicture to null so i don't have a foreign key error when removing)
$announce->setCoverPicture(null);
$em->flush();
$em->remove($announce);
$em->flush();
But i have an error on foreign key
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or
update a parent row: a foreign key constraint fails
PS : I can't found how to render correctly my code :s
PS : This workaround works, but isn't it the way the cascade work?
if(count($announce->getPictureAnnounces()) > 0) {
$pictureAnnounces = $announce->getPictureAnnounces();
foreach ($pictureAnnounces as $pictureAnnounce) {
$em->remove($pictureAnnounce);
}
$em->flush();
} // Then remove the announce
I ran into a problem when I'm trying to persist User entity with its relations:
class User {
/**
* #OneToMany(targetEntity="AppBundle\Entity\UserDataAttribute", mappedBy="user", cascade={"persist", "remove"})
* #var \Doctrine\Common\Collections\Collection
*/
private $customAttributes;
}
class UserDataAttribute
{
/**
* #ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="customAttributes")
* #JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
}
When I specify #JoinColumn as name="user_id" in database goes this query:
INSERT INTO user_data_attr (user_id) VALUES (null);
And when I specify #JoinColumn as name="userId" in database goes this query:
INSERT INTO user_data_attr (userId) VALUES (2323 (the actual value)));
But what I need is:
INSERT INTO user_data_attr (user_id) VALUES (2323);
What do I do wrong?
/**
* #OneToMany(targetEntity="AppBundle\Entity\UserDataAttribute", mappedBy="user", cascade={"persist", "remove"})
*/
private $customAttributes;
/**
* #ManyToOne(targetEntity="AppBundle\Entity\User", inversedBy="customAttributes")
*/
private $user;
And check it before:
app/console doctrine:schema:validate for Symfony 2
`app/console doctrine:schema:valid` for Symfony 3
I've got these entities (relevant part for the problem) :
/**
* Criterion
*
* #ORM\Table(name="innova_stepcondition_criterion")
* #ORM\Entity(repositoryClass="Innova\PathBundle\Repository\CriterionRepository")
*/
class Criterion implements \JsonSerializable
{
/**
* Criteriagroup
* #var \Innova\PathBundle\Entity\Criteriagroup
*
* #ORM\ManyToOne(targetEntity="Innova\PathBundle\Entity\Criteriagroup", inversedBy="criteria", cascade={"all"})
* #ORM\JoinColumns({
* #ORM\JoinColumn(onDelete="SET NULL")
* })
*/
protected $criteriagroup;
}
and
/**
* Criteriagroup
*
* #ORM\Table(name="innova_stepcondition_criteriagroup")
* #ORM\Entity(repositoryClass="Innova\PathBundle\Repository\CriteriagroupRepository")
*/
class Criteriagroup implements \JsonSerializable
{
/**
* Criteria linked to the criteriagroup
* #var \Doctrine\Common\Collections\ArrayCollection
*
* #ORM\OneToMany(targetEntity="Innova\PathBundle\Entity\Criterion", mappedBy="criteriagroup", indexBy="id", cascade={"persist", "remove"})
*/
protected $criteria;
}
When i try to delete a criteriagroup, i want to delete the attached criterion. I've got this error :
An exception occurred while executing 'DELETE FROM innova_stepcondition_criteriagroup WHERE id = ?' with params [1]: SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`claroline_path`.`innova_stepcondition_criteriagroup`, CONSTRAINT `FK_F33A94EA727ACA70` FOREIGN KEY (`parent_id`) REFERENCES `innova_stepcondition_criteriagroup` (`id`))
So i've read some post like this our this one and the suggested solution is the solution is to use a onDelete="SET NULL" on the joinColumn in the ManyToOne side, which i did. But i still get this error.
What could be wrong ?
Thank you
EDIT :
#RaulFerriz : Thank you for the answer. If i try your modifications : with cascade={"persist"} instead of cascade={"all"} in Criterion, i still have the same error.
But if i remove entirely the cascade in Criterion, i have :
A new entity was found through the relationship \u0027Innova\\PathBundle\\Entity\\Criterion#criteriagroup\u0027 that was not configured to cascade persist operations for entity: Innova\\PathBundle\\Entity\\Criteriagroup#0000000034dfa7b200000000f76198d8. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example #ManyToOne(..,cascade={\u0022persist\u0022}). If you cannot find out which entity causes the problem implement \u0027Innova\\PathBundle\\Entity\\Criteriagroup#__toString()\u0027 to get a clue`
that seems to mean the cascade={"persist"} is needed.
I don't knwon what to try next.
I do a doctrine:schema:update after each modification.
Your problem is not in your relation Criteriagroup and Criteria.
If you check the SQL error, the constraint that failed is for the field parent_id. Which is part of your Criteriagroup / Criteriagroup relation.
I put here the definition of your buggy relation, if someone else need this :
/**
* Parent criteriagroup
* #var \Innova\PathBundle\Entity\Criteriagroup
*
* #ORM\ManyToOne(targetEntity="Criteriagroup", inversedBy="children", cascade={"all"})
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
protected $parent;
/**
* Children criteriagroup
* #var \Doctrine\Common\Collections\ArrayCollection
*
* #ORM\OneToMany(targetEntity="Criteriagroup", mappedBy="parent", indexBy="id", cascade={"persist", "remove"})
* #ORM\OrderBy({"order" = "ASC"})
*/
protected $children;
In order to make this work, you need to replace :
#ORM\JoinColumn(name="parent_id", referencedColumnName="id")
by
#ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE")
By adding this, when you will delete a CriteriaGroup, all children CriteriaGroup will be deleted. If you don't want to delete children, just add onDelete="SET NULL".
Hope it helps.
As you have defined the entities, when you try to remove a "Criterion" the entity Criteriongroup will also be deleted. That is not what you are attempting to achieve.
Try with this
/**
* Criterion
*
* #ORM\Table(name="innova_stepcondition_criterion")
* #ORM\Entity(repositoryClass="Innova\PathBundle\Repository\CriterionRepository")
*/
class Criterion implements \JsonSerializable
{
/**
* Criteriagroup
* #var \Innova\PathBundle\Entity\Criteriagroup
*
* #ORM\ManyToOne(targetEntity="Innova\PathBundle\Entity\Criteriagroup", inversedBy="criteria")
* #ORM\JoinColum(referencedColumnName="id")
*/
protected $criteriagroup;
}
And this
/**
* Criteriagroup
*
* #ORM\Table(name="innova_stepcondition_criteriagroup")
* #ORM\Entity(repositoryClass="Innova\PathBundle\Repository\CriteriagroupRepository")
*/
class Criteriagroup implements \JsonSerializable
{
/**
* Criteria linked to the criteriagroup
* #var \Doctrine\Common\Collections\ArrayCollection
*
* #ORM\OneToMany(targetEntity="Innova\PathBundle\Entity\Criterion", mappedBy="criteriagroup", indexBy="id", cascade={"persist", "remove"})
*/
protected $criteria;
}
Basically, clean up Criterion entity from cascading all, at most I suppose you will need {cascade="persist"} at this entity that means: when Criterion is persisted, persist also Criteriagroup linked with it.
i am building a cart that can take items with specified versions.
I am using Symfony 2.4.3 and Doctrine 2
I have following code for three entities, Cart, CartItem and CartItemVersion.
Cart.php
// ----
/**
* #ORM\OneToMany(targetEntity="CartItem", mappedBy="cart")
*/
private $cartItems;
// ----
CartItem.php
// ----
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Cart")
*/
private $cart;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Item")
*/
private $item;
/**
* #ORM\OneToMany(targetEntity="CartItemVersion", mappedBy="cartItem")
*/
private $cartItemVersions;
// ----
CartItemVersion.php
// ----
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="CartItem")
*/
private $cartItem;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="ItemVersion")
*/
private $itemVersion;
// ----
While updating schema, i got this error.
[Doctrine\ORM\ORMException]
Column name `id` referenced for relation from CartItemVersion towards CartItem does not exist.
Then i gave name to the fields like cartItem_id in CartItemVersion.php and others.
Then updating schema returns,
[Doctrine\DBAL\DBALException]
An exception occurred while executing 'ALTER TABLE cart_item_version ADD CONSTRAINT FK_4D3EA2E02EA80FC1 FOREIGN KEY (cartItem_id) REFERENCES cart_item (cartItemVersion_id)':
SQLSTATE[HY000]: General error: 1005 Can't create table 'symfony.#sql-3d8_12a' (errno: 150)
I have referred Doctrine 2's documentation and followed Use Cases for OrderItem but it seems that this is something because of composite primary keys, but still giving proper names couldn't solve this issue.
Can anyone help?
In your mapping you have a bunch of issues which are corrected as below. You need define the referenced Column name and its own column name; furthermore, for those field which has mappedBy you need to define inversedBy, too.
Cart.php
/**
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="CartItem", mappedBy="cart")
*/
private $cartItems;
CartItem.php
/**
* #ORM\ManyToOne(targetEntity="Cart", inversedBy="cartItems")
* #ORM\JoinColumn(name="cart_id", referencedColumnName="id")
*/
private $cart;
/**
* #ORM\ManyToOne(targetEntity="Item")
* #ORM\JoinColumn(name="item_id", referencedColumnName="id")
*/
private $item;
/**
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="CartItemVersion", mappedBy="cartItem")
*/
private $cartItemVersions;
CartItemVersion.php
/**
* #ORM\ManyToOne(targetEntity="CartItem", inversedBy="cartItemVersions")
* #ORM\JoinColumn(name="cart_item_id", referencedColumnName="id")
*/
private $cartItem;
/**
* #ORM\ManyToOne(targetEntity="ItemVersion")
* #ORM\JoinColumn(name="item_version_id", referencedColumnName="id")
*/
private $itemVersion;
To get more info check Relationship Mapping Metadata Documentation
I think you have to make your entities slowly, step by step.
Begin with unidirectional and then add bidirectional when it is necessary...
By using association mapping documentation.
This answer could be a comment but can't post a comment because of my reputation...