php 使用doctrine2删除级联

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6328535/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 00:02:41  来源:igfitidea点击:

On delete cascade with doctrine2

phpdoctrine-ormsymfonycascading-deletes

提问by rfc1484

I'm trying to make a simple example in order to learn how to delete a row from a parent table and automatically delete the matching rows in the child table using Doctrine2.

我正在尝试制作一个简单的示例,以了解如何从父表中删除一行并使用 Doctrine2 自动删除子表中的匹配行。

Here are the two entities I'm using:

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

Child.php:

子.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

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

The tables are correctly created on the database, but the On Delete Cascade option it's not created. What am I doing wrong?

表已在数据库上正确创建,但未创建 On Delete Cascade 选项。我究竟做错了什么?

回答by Michael Ridgway

There are two kinds of cascades in Doctrine:

Doctrine 中有两种级联:

1) ORM level - uses cascade={"remove"}in the association - this is a calculation that is done in the UnitOfWork and does not affect the database structure. When you remove an object, the UnitOfWork will iterate over all objects in the association and remove them.

1)ORM级别——cascade={"remove"}在关联中使用——这是在UnitOfWork中完成的计算,不影响数据库结构。当您删除一个对象时,UnitOfWork 将遍历关联中的所有对象并删除它们。

2) Database level - uses onDelete="CASCADE"on the association's joinColumn - this will add On Delete Cascade to the foreign key column in the database:

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

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

I also want to point out that the way you have your cascade={"remove"} right now, if you delete a Child object, this cascade will remove the Parent object. Clearly not what you want.

我还想指出,您现在拥有级联 ={"remove"} 的方式,如果您删除子对象,此级联将删除父对象。显然不是你想要的。

回答by Kurt Krueckeberg

Here is simple example. A contact has one to many associated phone numbers. When a contact is deleted, I want all its associated phone numbers to also be deleted, so I use ON DELETE CASCADE. The one-to-many/many-to-one relationship is implemented with by the foreign key in the phone_numbers.

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

By adding "ON DELETE CASCADE" to the foreign key constraint, phone_numbers will automatically be deleted when their associated contact is deleted.

通过在外键约束中添加“ON DELETE CASCADE”,电话号码将在其关联联系人被删除时自动删除。

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

Now when a row in the contacts table is deleted, all its associated phone_numbers rows will automatically be deleted.

现在,当contacts 表中的一行被删除时,所有关联的phone_numbers 行都将被自动删除。

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

To achieve the same thing in Doctrine, to get the same DB-level "ON DELETE CASCADE" behavtheitroad, you configure the @JoinColumn with the onDelete="CASCADE"option.

为了在 Doctrine 中实现同样的事情,要获得相同的 DB 级别的“ON DELETE CASCADE”行为,您可以使用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 . "<br />\n";
}

If you now do

如果你现在做

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

you will see that the same SQL will be generated as in the first, raw-SQL example

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