247 votes

Sur delete cascade avec doctrine2

Je suis en train de faire un exemple simple pour apprendre comment faire pour supprimer une ligne dans une table parente et de supprimer automatiquement les lignes correspondantes dans la table enfant en utilisant Doctrine2.

Voici les deux entités que j’utilise :

Child.php :

Father.php

Les tableaux sont correctement créés sur la base de données, mais l’option sur Delete Cascade qu'il n’est pas créé. Ce que je fais mal ?

442voto

Michael Ridgway Points 1796

Il y a deux sortes de cascades dans la Doctrine:

1) ORM niveau utilise cascade={"remove"} dans l'association - c'est un calcul qui est fait dans le UnitOfWork et n'affecte pas la structure de base de données. Lorsque vous supprimez un objet, le UnitOfWork va se répéter sur tous les objets de l'association et de les supprimer.

2) niveau de Base de données - les utilisations onDelete="CASCADE" sur l'association joinColumn - cela va ajouter Sur Delete Cascade de la colonne de clé étrangère dans la base de données:

@ORM\JoinColumn(name="father_id", referencedColumnName="id", onDelete="CASCADE")

Je tiens aussi à souligner que la manière que vous avez de votre cascade={"remove"} maintenant, si vous supprimez un objet Enfant, cette cascade va supprimer l'objet Parent. Clairement pas ce que vous voulez.

52voto

Kurt Krueckeberg Points 617

Voici simplement un exemple. Un contact a plusieurs numéros de téléphone associés. Lorsqu'un contact est supprimé, je veux que tous ses numéros de téléphone associés également être supprimée, de sorte que j'utilise SUR DELETE CASCADE. L'un-à-plusieurs ou plusieurs-à-une relation est mise en œuvre par la clé étrangère dans la phone_numbers.

CREATE TABLE contacts
 (contact_id BIGINT AUTO_INCREMENT NOT NULL,
 name VARCHAR(75) NOT NULL,
 PRIMARY KEY(contact_id)) ENGINE = InnoDB;

CREATE TABLE phone_numbers
 (phone_id BIGINT AUTO_INCREMENT NOT NULL,
  phone_number CHAR(10) NOT NULL,
 contact_id BIGINT NOT NULL,
 PRIMARY KEY(phone_id),
 UNIQUE(phone_number)) ENGINE = InnoDB;

ALTER TABLE phone_numbers ADD FOREIGN KEY (contact_id) REFERENCES \
contacts(contact_id) ) ON DELETE CASCADE;

En ajoutant "on DELETE CASCADE" de la contrainte de clé étrangère, phone_numbers seront automatiquement supprimés lorsque leur contact associé est supprimé.

INSERT INTO table contacts(name) VALUES('Robert Smith');
INSERT INTO table phone_numbers(phone_number, contact_id) VALUES('8963333333', 1);
INSERT INTO table phone_numbers(phone_number, contact_id) VALUES('8964444444', 1);

Maintenant, quand une ligne dans la table contacts est supprimé, l'ensemble de ses associés phone_numbers lignes seront automatiquement supprimés.

DELETE TABLE contacts as c WHERE c.id=1; /* delete cascades to phone_numbers */

Pour réaliser la même chose dans la Doctrine, pour obtenir la même DB-niveau "on DELETE CASCADE" de comportement, vous devez configurer les annotations @JoinColumn avec le onDelete="CASCADE" option.

<?php
namespace Entities;

use Doctrine\Common\Collections\ArrayCollection;

/**
  @Entity
  @Table(name="contacts")
*/
class Contact {

/**
*  @Id
*  @Column(type="integer", name="contact_id") 
*  @GeneratedValue
*/
   protected $id;  

/** 
 * @Column(type="string", length="75", unique="true") 
*/ 
   protected $name; 

/** 
* @OneToMany(targetEntity="Phonenumber", mappedBy="contact")
*/ 
   protected $phonenumbers; 

    public function __construct($name=null)
    {
    $this->phonenumbers = new ArrayCollection();

        if (!is_null($name)) {

            $this->name = $name;
        }
    }

    public function getId()
    {
       return $this->id;
    }

    public function setName($name)
    {
    $this->name = $name;
    }

    public function addPhonenumber(Phonenumber $p)
    {
         if (!$this->phonenumbers->contains($p)) {

             $this->phonenumbers[] = $p;
             $p->setContact($this);
         }
    }

    public function removePhonenumber(Phonenumber $p)
    {
         $this->phonenumbers->remove($p);
    }
}

<?php
namespace Entities;

/**
@Entity
@Table(name="phonenumbers")
*/
class Phonenumber {

/**
*  @Id
*  @Column(type="integer", name="phone_id") 
*  @GeneratedValue
*/
    protected $id;  
 /**
*  @Column(type="string", length="10", unique="true") 
*/  
    protected $number;

/** 
* @ManyToOne(targetEntity="Contact", inversedBy="phonenumbers")
* @JoinColumn(name="contact_id", referencedColumnName="contact_id", onDelete="CASCADE")
*/ 
     protected $contact; 

     public function __construct($number=null)
     {
        if (!is_null($number)) {

            $this->number = $number;
        }
     }

     public function setPhonenumber($number)
     {
    $this->number = $number;
     }

     public function setContact(Contact $c)
     {
    $this->contact = $c;
     }
 } 
?>
$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config);

$contact = new Contact("John Doe"); 

$phone1 = new Phonenumber("8173333333");
$phone2 = new Phonenumber("8174444444");
$em->persist($phone1);
$em->persist($phone2);
$contact->addPhonenumber($phone1); 
$contact->addPhonenumber($phone2); 

$em->persist($contact);
try {

    $em->flush();
} catch(Exception $e) {

    $m = $e->getMessage();
    echo $m . "<br />\n";
}

Maintenant, si vous ne

# doctrine orm:schema-tool:create --dump-sql

vous verrez que les mêmes SQL généré comme dans le premier, raw-SQL exemple

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X