Tout d'abord, désolé pour mon pauvre anglais ...
J'ai quatre entités: utilisateur, application, bundle et entité. Voici leurs relations (avec cascading persist & remove, voir le code ci-dessous):
Ça fonctionne bien. Mais un utilisateur peut avoir deux de ses entités par défaut et je dois y accéder directement.
J'ajoute donc à l'utilisateur deux champs, entity1 et entity2, avec un 1-1 relation. Et maintenant, mon application se bloque:
An exception occurred while executing 'DELETE FROM bundle WHERE id = ?' with params {"1":13}:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`misc`.`entity`, CONSTRAINT `FK_E284468F1FAD9D3` FOREIGN KEY (`bundle_id`) REFERENCES `bundle` (`id`))
J'ai essayé plusieurs choses, y compris celles fondées dans ce post , mais je n'ai pas pu le réparer.
Toute aide sera la bienvenue, merci d'avance.
EDIT: Je dois préciser que les relations Utilisateur-> Entité sont optionnelles: Entité1 et entité2 peuvent être nulles. L'erreur se produit même si les deux sont nuls.
Voici mes définitions d'entités:
# User :
/**
* @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Application", mappedBy="user", cascade={"remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $applications;
/**
* @ORM\OneToOne(targetEntity="\sfCommands\ContentBundle\Entity\Entity")
* @ORM\JoinColumn(name="entity1_id", referencedColumnName="id")
*/
private $entity1;
/**
* @ORM\OneToOne(targetEntity="\sfCommands\ContentBundle\Entity\Entity")
* @ORM\JoinColumn(name="entity2_id", referencedColumnName="id")
*/
private $entity2;
#Application :
/**
* @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Bundle", mappedBy="application", cascade={"remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $bundles;
/**
* @ORM\ManyToOne(targetEntity="\sfCommands\UserBundle\Entity\User", inversedBy="applications", cascade={"persist"})
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
#Bundle :
/**
* @ORM\ManyToOne(targetEntity="\sfCommands\ContentBundle\Entity\Application", inversedBy="bundles", cascade={"persist"})
* @ORM\JoinColumn(name="application_id", referencedColumnName="id")
*/
protected $application;
/**
* @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Entity", mappedBy="bundle", cascade={"remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $entitys;
#Entity :
/**
* @ORM\ManyToOne(targetEntity="\sfCommands\ContentBundle\Entity\Bundle", inversedBy="entitys", cascade={"persist"})
* @ORM\JoinColumn(name="bundle_id", referencedColumnName="id")
*/
protected $bundle;
Donc, grâce à ce forum français , j'ai corrigé le problème.
J'avais besoin d'ajouter nullable = true & onDelete = "SET NULL" dans @ORM\JoinColumn
Voici la configuration réalisable, cela aidera peut-être quelqu'un:
#User.
/**
* @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Application", mappedBy="user", cascade={"remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $applications;
/**
* @ORM\OneToOne(targetEntity="\sfCommands\ContentBundle\Entity\Entity")
* @ORM\JoinColumn(name="entity1_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
*/
private $entity1;
/**
* @ORM\OneToOne(targetEntity="\sfCommands\ContentBundle\Entity\Entity")
* @ORM\JoinColumn(name="entity2_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
*/
private $entity2;
#Application.
/**
* @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Bundle", mappedBy="application", cascade={"remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $bundles;
/**
* @ORM\ManyToOne(targetEntity="\sfCommands\UserBundle\Entity\User", inversedBy="applications", cascade={"persist"})
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
*/
protected $user;
#Bundle.
/**
* @ORM\ManyToOne(targetEntity="\sfCommands\ContentBundle\Entity\Application", inversedBy="bundles", cascade={"persist"})
* @ORM\JoinColumn(name="application_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
*/
protected $application;
/**
* @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Entity", mappedBy="bundle", cascade={"remove"}, orphanRemoval=true)
* @ORM\OrderBy({"name" = "ASC"})
*/
protected $entitys;
#Entity.
/**
* @ORM\ManyToOne(targetEntity="\sfCommands\ContentBundle\Entity\Bundle", inversedBy="entitys", cascade={"persist"})
* @ORM\JoinColumn(name="bundle_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
*/
protected $bundle;
Utilisez onDelete = "CASCADE" si vous utilisez une annotation
/**
* @ORM\ManyToOne(targetEntity="Report", inversedBy="responses")
* @ORM\JoinColumn(name="reportId", referencedColumnName="id",onDelete="CASCADE")
*/
Utilisez onDelete: CASCADE si vous utilisez yml
joinColumn:
name: pid
referencedColumnName: id
onDelete: CASCADE
onDelete = "CASCADE" fonctionne aussi très bien. Mais n'oubliez pas d'exécuter app/console doctrine: schema: update --force avant que les modifications apportées au niveau de la base de données ne prennent effet.
orphanRemoval parfois ne fonctionne pas parce que cela dépend de (est programmé dans) PersistencCollection
. Et nous pourrions appeler ArrayCollection#removeElement()
.
Voici un extrait de la PersistencCollection#remove()
if ($this->association !== null &&
$this->association['type'] & ClassMetadata::TO_MANY &&
$this->owner &&
$this->association['orphanRemoval']) {
$this->em->getUnitOfWork()->scheduleOrphanRemoval($removed);
}
et ArrayCollection ne fait pas cela.