J'essaie de faire un exemple simple afin d'apprendre à supprimer une ligne d'une table parent et à supprimer automatiquement les lignes correspondantes dans la table enfant à l'aide de Doctrine2.
Voici les deux entités que j'utilise:
Child.php:
<?php
namespace Acme\CascadeBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="child")
*/
class Child {
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="Father", cascade={"remove"})
*
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="father_id", referencedColumnName="id")
* })
*
* @var father
*/
private $father;
}
Father.php
<?php
namespace Acme\CascadeBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="father")
*/
class Father
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
}
Les tables sont correctement créées dans la base de données, mais l'option Sur supprimer la cascade n'est pas créée. Qu'est-ce que je fais mal?
php
doctrine-orm
symfony
cascading-deletes
rfc1484
la source
la source
Réponses:
Il existe deux types de cascades dans Doctrine:
1) Niveau ORM - utilise
cascade={"remove"}
dans l'association - c'est un calcul qui est fait dans UnitOfWork et n'affecte pas la structure de la base de données. Lorsque vous supprimez un objet, UnitOfWork parcourt tous les objets de l'association et les supprime.2) Niveau base de données - utilise
onDelete="CASCADE"
sur la colonne joinColumn de l'association - cela ajoutera On Delete Cascade à la colonne de clé étrangère dans la base de données:Je tiens également à souligner que la façon dont vous avez votre cascade = {"supprimer"} en ce moment, si vous supprimez un objet enfant, cette cascade supprimera l'objet parent. Ce n'est clairement pas ce que vous voulez.
la source
onDelete
ainsi quecascade = {"remove"}
par exemple lorsque vous avez un objet lié à fosUser. Les deux objets ne devraient pas exister seuls@ORM\JoinColumn(onDelete="CASCADE")
et laisser la doctrine gérer automatiquement les noms de colonne.onDelete="CASCADE"
n'aura aucun effet puisque Doctrinecascade={"remove"}
supprime les entités liées avant de supprimer l'entité racine (il le doit). Ainsi, lorsque l'entité racine est supprimée, il ne reste plus de relations étrangèresonDelete="CASCADE"
à supprimer. Mais pour être sûr, je vous suggère de simplement créer un petit cas de test et de regarder les requêtes en cours d'exécution et leur ordre d'exécution.Voici un exemple simple. Un contact a un à plusieurs numéros de téléphone associés. Lorsqu'un contact est supprimé, je souhaite que tous ses numéros de téléphone associés soient également supprimés, donc j'utilise ON DELETE CASCADE. La relation un-à-plusieurs / plusieurs-à-un est implémentée par la clé étrangère dans les numéros de téléphone.
En ajoutant "ON DELETE CASCADE" à la contrainte de clé étrangère, les numéros de téléphone seront automatiquement supprimés lorsque leur contact associé sera supprimé.
Désormais, lorsqu'une ligne du tableau des contacts est supprimée, toutes les lignes associées de phone_numbers seront automatiquement supprimées.
Pour obtenir la même chose dans Doctrine, pour obtenir le même comportement "ON DELETE CASCADE" au niveau de la base de données, vous configurez @JoinColumn avec l' option onDelete = "CASCADE" .
Si vous le faites maintenant
vous verrez que le même SQL sera généré comme dans le premier exemple raw-SQL
la source
onDelete="cascade"
est placé correctement dans l'entité (sur l'enfant) car il s'agit de la cascade SQL , qui est placée sur l'enfant. Seule la Doctrine en cascade (cascade=["remove"]
, qui n'est pas utilisée ici) est placée sur le parent.