首页 文章

在使用doctrine2删除级联时

提问于
浏览
207

我试图做一个简单的例子,以学习如何从父表中删除行,并使用Doctrine2自动删除子表中的匹配行 .

这是我正在使用的两个实体:

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;
}

这些表是在数据库上正确创建的,但是没有创建On Delete Cascade选项 . 我究竟做错了什么?

2 回答

  • 41

    学说中有两种级联:

    1)ORM级别 - 在关联中使用 cascade={"remove"} - 这是在UnitOfWork中完成的计算,不会影响数据库结构 . 删除对象时,UnitOfWork将遍历关联中的所有对象并将其删除 .

    2)数据库级别 - 在关联的joinColumn上使用 onDelete="CASCADE" - 这会将On Delete Cascade添加到数据库中的外键列:

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

    我还想指出你现在拥有cascade = {“remove”}的方式,如果你删除了一个Child对象,这个级联将删除Parent对象 . 显然不是你想要的 .

  • 365

    这是一个简单的例子 . 联系人具有一对多的关联电话号码 . 删除联系人时,我希望删除所有关联的电话号码,因此我使用ON DELETE CASCADE . 通过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;
    

    通过向外键约束添加“ON DELETE CASCADE”,将在删除相关联系人时自动删除phone_numbers .

    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);
    

    现在,当删除联系人表中的一行时,将自动删除其所有关联的phone_numbers行 .

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

    要在Doctrine中实现相同的功能,要获得相同的DB级别"ON DELETE CASCADE" behavoir,请使用 onDelete="CASCADE" 选项配置@JoinColumn .

    <?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;
        }
    } 
    ?>
    
    <?php
    
    $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 . "
    \n"; }

    如果你现在这样做

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

    您将看到将在第一个原始SQL示例中生成相同的SQL

相关问题