Doctrine: How to unset (SET NULL) OneToMany relati

2019-07-18 04:54发布

This is a very very simple behavior, but I can't find the way to achieve it with doctrine. I'm going to explain it reducing the complexity with only two entities.

Having two entites (Author and Book) related like "One Author owns zero or more books" and "One book is owned by zero or one author", I'm trying to unset the relation between an author and one of his books (from the author side), expecting that book.author_id field in database sets as null.

The Entities are defined as follow:

Author

/**
 * Author
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="Poc\PocBundle\Entity\AuthorRepository")
 */
class Author
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return Author
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @ORM\OneToMany(targetEntity="Book", mappedBy="author", cascade={"persist", "remove"})
     */
    private $books;

    public function __construct()
    {
        $this->products = new ArrayCollection();
    }

    /**
     * Add books
     *
     * @param \Poc\PocBundle\Entity\Book $books
     * @return Author
     */
    public function addBook(\Poc\PocBundle\Entity\Book $books)
    {
        $this->books[] = $books;

        return $this;
    }

    /**
     * Remove books
     *
     * @param \Poc\PocBundle\Entity\Book $books
     */
    public function removeBook(\Poc\PocBundle\Entity\Book $books)
    {
        $this->books->removeElement($books);
    }

    /**
     * Get books
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getBooks()
    {
        return $this->books;
    }
}

Book

/**
 * Book
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="Poc\PocBundle\Entity\BookRepository")
 */
class Book
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return Book
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @ORM\ManyToOne(targetEntity="Author", inversedBy="books")
     * @ORM\JoinColumn(name="author_id", referencedColumnName="id", onDelete="SET NULL")
     */
     protected $author;


    /**
     * Set author
     *
     * @param \Poc\PocBundle\Entity\Author $author
     * @return Book
     */
    public function setAuthor(\Poc\PocBundle\Entity\Author $author = null)
    {
        $this->author = $author;

        return $this;
    }

    /**
     * Get author
     *
     * @return \Poc\PocBundle\Entity\Author 
     */
    public function getAuthor()
    {
        return $this->author;
    }
}

In the main controller I do the following.

  • Retrieve an author

  • Retrieve a Book owned by this author

  • Remove book from author

  • Persist Author & flush

  • Retrieve Book

  • Get the author ...

And the Author remains being the same. In database the field book.author_id of this record is not set to NULL as expected, but is still related with the author.

The Controller Code:

    $Book = $this->getDoctrine()
        ->getRepository('PocPocBundle:Book')
        ->find('1');
    $Author = $this->getDoctrine()
        ->getRepository('PocPocBundle:Author')
        ->find('1');

    $Author->removeBook($Book);


    $em = $this->getDoctrine()->getManager();
    $em->persist($Author);
    $em->flush();

    echo "<pre>";
    $Book = $this->getDoctrine()
        ->getRepository('PocPocBundle:Book')
        ->find('1');
    \Doctrine\Common\Util\Debug::dump($Book);

    die;

... And the output

object(stdClass)[286]
      public '__CLASS__' => string 'Poc\PocBundle\Entity\Book' (length=25)
      public 'id' => int 1
      public 'name' => string 'El Quijote' (length=10)
      public 'author' => 
        object(stdClass)[293]
          public '__CLASS__' => string 'Poc\PocBundle\Entity\Author' (length=27)
          public '__IS_PROXY__' => boolean true
          public '__PROXY_INITIALIZED__' => boolean true
          public 'id' => int 1
          public 'name' => string 'Cervantes' (length=9)
          public 'books' => string 'Array(1)' (length=8)

In the output of entity Book (id=1) we can see this books is still related with the author.

Sure, I'm missing something but I can't find where is the gap.

1条回答
爷的心禁止访问
2楼-- · 2019-07-18 05:10

If you want to remove the association between the Author and the Book entities, you should delete the association in your Book entity and persist it too by using $em->flush(). $em->persist($entity) is not used for entity removal. Deleting the association in your PHP objects and flush them through the ORM remove the association in the database.

Just check this in the Doctrine's documentation:

http://docs.doctrine-project.org/en/latest/reference/working-with-associations.html#removing-associations

I hope it will work for you. Cheers!

查看更多
登录 后发表回答