Doctrine many-to-many relations and onFlush event

核能气质少年 提交于 2019-12-24 10:56:11

问题


Little example about Books and Authors: DB structure:

Entities (they were generated form database using symfony2 console commands):

Author:

    /**
 * Author
 *
 * @ORM\Table(name="authors")
 * @ORM\Entity
 */
class Author
{

    private $_isCachable = true;


    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

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

    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\ManyToMany(targetEntity="App\CoreBundle\Entity\Books", mappedBy="author", cascade={"persist","remove","detach","merge","refresh"})
     */
    private $book;

    /**
     * Constructor
     */
    public function __construct()
    {
    $this->book = new \Doctrine\Common\Collections\ArrayCollection();
    }
}

Book:

 <?php

namespace App\CoreBundle\Entity;

use App\CoreBundle\RedisLayer\Marks\Insert;
use App\CoreBundle\RedisLayer\Marks\Update;
use Doctrine\ORM\Mapping as ORM;

/**
 * Book
 *
 * @ORM\Table(name="books")
 * @ORM\Entity
 */
class Book
{

    private $_isCachable = true;


    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

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

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

    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\ManyToMany(targetEntity="App\CoreBundle\Entity\Authors", inversedBy="book", cascade={"persist","remove","detach","merge","refresh"})
     * @ORM\JoinTable(name="author_books",
     *   joinColumns={
     *     @ORM\JoinColumn(name="book_id", referencedColumnName="id")
     *   },
     *   inverseJoinColumns={
     *     @ORM\JoinColumn(name="author_id", referencedColumnName="id")
     *   }
     * )
     */
    private $author;

    /**
     * Constructor
     */
    public function __construct()
    {
    $this->author = new \Doctrine\Common\Collections\ArrayCollection();
    }

}

So when I run this code:

    $book = new \App\CoreBundle\Entity\Book();
    $book->setTtile('book title: '.uniqid());
    $book->setIsbn('book isbn: '.uniqid());

    $author = new \App\CoreBundle\Entity\Author();
    $author->setName('author title: '.uniqid());


    $author->addBook($book);

    $entityManager->persist($author);

    $entityManager->flush();

I expect doctrine to generate these SQLs:

"START TRANSACTION"]

    # CREATE BOOK
    INSERT INTO books (ttile, isbn) VALUES (?, ?)
    array(2) {
      [1] =>
      string(25) "book title: 524ea3cf34d5f"
      [2] =>
      string(24) "book isbn: 524ea3cf34da3"
    }
    array(2) {
      [1] =>
      string(6) "string"
      [2] =>
      string(6) "string"
    }

    # CREATE AUTHOR
    INSERT INTO authors (name) VALUES (?)
    array(1) {
      [1] =>
      string(27) "author title: 524ea3cf34de9"
    }
    array(1) {
      [1] =>
      string(6) "string"
    }

    # CREATE LINKS
    INSERT INTO author_books (book_id, author_id) VALUES (?, ?)
    array(2) {
      [0] =>
      int(34)
      [1] =>
      int(23)
    }

"COMMIT"

But i get only SQLs for #CERATE AUTHOR and #CREATE BOOK. SQL for linking table was not generated.

  1. What is the problem?

  2. If I run this code:

    $book = new \App\CoreBundle\Entity\Book();
    $book->setTtile('book title: '.uniqid());
    $book->setIsbn('book isbn: '.uniqid());
    
    $author = new \App\CoreBundle\Entity\Author();
    $author->setName('author title: '.uniqid());
    
    $author->addBook($book);
    $book->addAuthor($author); // added
    
    $entityManager->persist($author);
    
    $entityManager->flush();
    

    all is OK. So I need to add book to author and author to book? Is it possible to create book and author and then and book to author and flush (without adding author to book) ?

  3. If I use doctrine onFLush event listener I can use getScheduledEntityUpdates (list of entities that should be updated), getScheduledEntityInsertions (list of entities that should be updated) and getScheduledEntityDeletions (list of entities that should be deleted) methods of the unitOfWork object. But this is only entities. How can I get info about linking table? I need to get SQL for linking table at doctrine onFlush event.


回答1:


You need to ensure that both Book:authors and Author:books have the proper values before persisting.

Specifically:

class Authors
{
    public function addBook($book)
    {
        $this->books[] = $book;
        $book->addAuthor($this);
    }

Do the same on the Book entity.

BTW, change Books and Authors to Book and Author. Otherwise it will drive you crazy. You can keep the table names plural if you want.

====================================================

Question #3:

When doctrine creates a linking table then it hides it completely. What you need to do is to make your own BookAuthor entity and then set one to many relations from it to Book/Author. At that point you will have full access to it. You can also add additional properties if you want.



来源:https://stackoverflow.com/questions/19180219/doctrine-many-to-many-relations-and-onflush-event

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!