[php] doctrine2로 계단식 삭제시

부모 테이블에서 행을 삭제하고 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;
}

테이블은 데이터베이스에서 올바르게 작성되지만 캐스케이드 삭제시 옵션은 작성되지 않습니다. 내가 뭘 잘못하고 있죠?



답변

교리에는 두 종류의 계단식이 있습니다.

1) ORM 레벨- cascade={"remove"}연관에서 사용 -이것은 UnitOfWork에서 수행되며 데이터베이스 구조에 영향을 미치지 않는 계산입니다. 개체를 제거하면 UnitOfWork는 연결의 모든 개체를 반복하여 제거합니다.

2) 데이터베이스 수준- onDelete="CASCADE"연결의 joinColumn에서 사용-데이터베이스 의 외래 키 열에 삭제시 캐스케이드가 추가됩니다.

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

또한 캐스케이드 = { “remove”}가있는 방식을 지적하고 싶습니다. Child 객체를 삭제하면이 캐스케이드가 Parent 객체를 제거합니다. 분명히 당신이 원하는 것이 아닙니다.


답변

다음은 간단한 예입니다. 연락처에는 일대 다 관련 전화 번호가 있습니다. 연락처가 삭제되면 관련된 모든 전화 번호도 삭제되기를 원하므로 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”동작을 얻으려면 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";
}

지금하면

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

첫 번째 원시 SQL 예제에서와 동일한 SQL이 생성됨을 알 수 있습니다.


답변