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.
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;
This is my ERD
I need help with how to associate the foreign keys with my entities
from what i know is that it has to something with this kind of code:
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
TL;DR I made entities but now i need to associate the foreign keys (image) but i don't know how.
/**
* #ORM\ManyToOne(targetEntity="klant", mappedBy="Bestellingorder")
*/
private $klanten;
/**
* #ORM\OneToMany(targetEntity="Bestellingorder", inversedBy="klanten")
* #ORM\JoinColumn(name="Bestellingorder_id", referencedColumnName="id")
*/
private $Bestellingorder;
[Creation Error] The annotation #ORM\ManyToOne declared on property TuinBundle\
Entity\Bestellingorder::$klanten does not have a property named "mappedBy". Ava
ilable properties: targetEntity, cascade, fetch, inversedBy
stuck here.
Try with that :
/**
* #ORM\ManyToOne(targetEntity="klant", inversedBy="Bestellingorder")
* #ORM\JoinColumn(name="klant_id", referencedColumnName="id")
*/
private $klanten;
/**
* #ORM\OneToMany(targetEntity="Bestellingorder", mappedBy="klanten")
*/
private $Bestellingorder;
But i don't understand why you have sometimes "klant" or "klanten", didn't make sense for me. What is the name of your entity ? klant or klanten ?
I'm using JMSSerializer - along with the Doctrine constructor - in order to deserialize an object sent.
My (simplified) entities are the following. I omit the code I think is useless:
Widget
{
protected $id;
/**
* #ORM\OneToMany(
* targetEntity="Belka\Iso50k1Bundle\Entity\VarSelection",
* mappedBy="widget",
* cascade={"persist", "remove", "detach", "merge"})
* #Serializer\Groups({"o-all-getCWidget", "i-p2-create", "o-all-getWidget", "i-p3-create", "i-p2-editWidget"})
* #Type("ArrayCollection<Belka\Iso50k1Bundle\Entity\VarSelection>")
*/
protected $varsSelection;
}
/**
* #ORM\Entity()
*
* #ORM\InheritanceType("SINGLE_TABLE")
*
* #ORM\DiscriminatorColumn(
* name="vartype",
* type="string")
*
* #ORM\DiscriminatorMap({
* "PHY" = "PhyVarSelection"
* })
*
* #ORM\HasLifecycleCallbacks()
*/
abstract class VarSelection
{
/**
* #Id
* #Column(type="integer")
* #GeneratedValue("SEQUENCE")
* #Serializer\groups({"o-all-getCWidget", "o-all-getWidget", "i-p2-editWidget"})
*/
protected $id;
}
class PhyVarSelection extends VarSelection
{
/**
* #var PhyVar
*
* #ORM\ManyToOne(
* targetEntity="Belka\Iso50k1Bundle\Entity\PhyVar",
* cascade={"persist", "merge", "detach"})
*
* #ORM\JoinColumn(
* name="phy_var_sel",
* referencedColumnName="id",
* nullable=false)
*/
protected $phyVar;
}
class PhyVar extends Variable
{
/**
* #ORM\Column(type="string")
* #ORM\Id
*
* #Serializer\Groups({"o-p2-getCMeters", "o-all-getWidget"})
* #Assert\Regex("/(PHY)_\d+_\d+_\w+/")
*/
protected $id;
/**
* #ORM\Column(type="text", name="varname")
* #Serializer\Groups({"o-p2-getCMeters", "o-all-getWidget", "o-all-getCWidget"})
*/
protected $varName;
...
}
I try to deserialize an object that represents a Widget entity already persisted, along with which an array of varselection with their own id specified - if already persisted - and without their own id if they are new and to be persisted.
Deserialization works:
$context = new DeserializationContext();
$context->setGroups('i-p2-editWidget');
$data = $this->serializer->deserialize($content, $FQCN, 'json', $context);
but $data has always Widget::$varsSelection[]::$phyVar as a proxy class initialized, with only the id properly set. What I have to do so as to have it all is:
foreach ($data->getVarsSelection() as $varSel) {
$varSel->getVar();
}
why is that? How can have it initialized already? I don't want to spend time cycling and fetching data from DB again.
edit
I've added a domain of the entities so as to get the idea of what I'm deserializing
I figured out myself the hows and whys of this behavior:
since I'm sending a JSON like the following:
{
"id": <widgetID>,
"vars_selection": {
"id": <varSelectionID>,
"vartype": "PHY"
}
}
JMSSerializer's Doctrine ObjectConstructor simply tries to finds just two Entities: Widget and VarSelection by executing the following line:
$object = $objectManager->find($metadata->name, $identifierList);
in other words: Doctrine's EntityManager tries to find the Entity identified by its ID. Hence, well'get the unitialized proxy classes.
As far as I know, find cannot specify an hydration mode. Hence, two are the ways to handle this:
Specify fetch="EAGER" on PhyVarSelection::$phyVar. Quite costly, when we do not need it though;
Replace the ObjectConstructor by calling the repository and make a DQL, which will have the EAGER option properly set. Something like $query->setFetchMode("PhyVarSelection", "phyVar", \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER);
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 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...