2013-02-13 70 views
0

我有一個大的時間試圖找出如何設置一個ManyToOne - 使用Doctrine 2>OneToMany關係,它仍然沒有工作...Symfony的2 - 多對一雙向關係的行爲

這裏是應用程序的行爲:

  1. 一個站點有Page小號
  2. 一個User可以在Page

這裏是我的實體(簡化):

評論實體:

** 
* @ORM\Entity 
* @ORM\Table(name="comment") 
*/ 
class Comment { 
    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

    /** 
    * Many Comments have One User 
    * 
    * @ORM\ManyToOne(targetEntity="\Acme\UserBundle\Entity\User", inversedBy="comments") 
    */ 
    protected $user; 

    /** 
    * Many Comments have One Page 
    * 
    * @ORM\ManyToOne(targetEntity="\Acme\PageBundle\Entity\Page", inversedBy="comments") 
    */ 
    protected $page; 

    ... 

    /** 
    * Set user 
    * 
    * @param \Acme\UserBundle\Entity\User $user 
    * @return Comment 
    */ 
    public function setUser(\Acme\UserBundle\Entity\User $user) 
    { 
     $this->user = $user; 
     return $this; 
    } 

    /** 
    * Set page 
    * 
    * @param \Acme\PageBundle\Entity\Page $page 
    * @return Comment 
    */ 
    public function setPage(\Acme\PageBundle\Entity\Page $page) 
    { 
     $this->page = $page; 
     return $this; 
    } 

用戶實體:

/** 
* @ORM\Entity 
* @ORM\Table(name="fos_user") 
*/ 
class User extends BaseUser 
{ 
    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

    /** 
    * The User create the Comment so he's supposed to be the owner of this relationship 
    * However, Doctrine doc says: "The many side of OneToMany/ManyToOne bidirectional relationships must be the owning 
    * side", so Comment is the owner 
    * 
    * One User can write Many Comments 
    * 
    * @ORM\OneToMany(targetEntity="Acme\CommentBundle\Entity\Comment", mappedBy="user") 
    */ 
    protected $comments; 

    ... 

    /** 
    * Get Comments 
    * 
    * @return \Doctrine\Common\Collections\Collection 
    */ 
    public function getComments() { 
     return $this->comments ?: $this->comments = new ArrayCollection(); 
    } 

頁實體:

/** 
* @ORM\Entity 
* @ORM\Table(name="page") 
*/ 
class Page 
{ 
    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

    /** 
    * One Page can have Many Comments 
    * Owner is Comment 
    * 
    * @ORM\OneToMany(targetEntity="\Acme\CommentBundle\Entity\Comment", mappedBy="page") 
    */ 
    protected $comments; 

    ... 

    /** 
    * @return \Doctrine\Common\Collections\Collection 
    */ 
    public function getComments(){ 
     return $this->comments ?: $this->comments = new ArrayCollection(); 
    } 

我希望有一個雙向關係能夠獲得的收藏來自Page或來自User的個(使用getComments())。

我的問題是,當我嘗試保存新Comment,我得到一個錯誤,說教義是無法創建一個Page實體。我想這是因爲它沒有找到Page(但它應該),所以它試圖創建一個新的Page實體,以便稍後將其鏈接到我嘗試創建的Comment實體。

這裏是我的控制器方法來創建一個Comment

public function createAction() 
    { 
     $user = $this->getUser(); 
     $page = $this->getPage(); 

     $comment = new EntityComment(); 
     $form = $this->createForm(new CommentType(), $comment); 

     if ($this->getRequest()->getMethod() === 'POST') { 
      $form->bind($this->getRequest()); 
      if ($form->isValid()) { 
       $em = $this->getDoctrine()->getManager(); 

       $comment->setPage($page); 
       $comment->setUser($user); 

       $em->persist($comment); 
       $em->flush(); 

       return $this->redirect($this->generateUrl('acme_comment_listing')); 
      } 
     } 

     return $this->render('AcmeCommentBundle:Default:create.html.twig', array(
      'form' => $form->createView() 
     )); 
    } 

我不明白爲什麼會這樣。我已經在此控制器中檢查了我的Page對象(由$this->getPage()返回 - 返回存儲在會話中的對象),並且它是存在的有效Page實體(我也在數據庫中檢查過)。

我不知道現在該做什麼,我無法找到有同樣的問題:(

這是確切的錯誤消息我的人:

一個新的實體被發現通過沒有配置爲 級聯關係 「的Acme \ CommentBundle \實體\評論#頁」堅持實體操作: 的Acme \ PageBundle \實體\頁@ 000000005d8a1f2000000000753399d4爲了解決 這個問題:無論是顯式調用的EntityManager#堅持()在這個 unkno wn實體或配置級聯在 映射中堅持這個關聯,例如@ManyToOne(..,cascade = {「persist」})。如果您不能 找出哪個實體導致問題實現 'Acme \ PageBundle \ Entity \ Page #__ toString()'以獲得線索。

但我不想添加cascade={"persist"},因爲我不想在級聯上創建頁面,而只是鏈接現有的頁面。

UPDATE1:

如果我取前設置它的頁面,它的工作。但我仍然不知道爲什麼我應該。

public function createAction() 
     { 
      $user = $this->getUser(); 
      $page = $this->getPage(); 

      // Fetch the page from the repository 
      $page = $this->getDoctrine()->getRepository('AcmePageBundle:page')->findOneBy(array(
       'id' => $page->getId() 
      )); 

      $comment = new EntityComment(); 

      // Set the relation ManyToOne 
      $comment->setPage($page); 
      $comment->setUser($user); 

      $form = $this->createForm(new CommentType(), $comment); 

      if ($this->getRequest()->getMethod() === 'POST') { 
       $form->bind($this->getRequest()); 
       if ($form->isValid()) { 
        $em = $this->getDoctrine()->getManager(); 

        $em->persist($comment); 
        $em->flush(); 

        return $this->redirect($this->generateUrl('acme_comment_listing')); 
       } 
      } 

      return $this->render('AcmeCommentBundle:Default:create.html.twig', array(
       'form' => $form->createView() 
      )); 
     } 

UPDATE2:

我已經結束了存儲在會話(而不是完整的對象),我認爲這是考慮到一個事實,我不會有一個更好的主意了PAGE_ID使用會話來存儲,但只是ID。我也期待Doctrine在檢索Page實體時緩存查詢。

但有人能解釋爲什麼我不能使用會話中的Page實體嗎?這是我是如何設置會話:

$pages = $site->getPages(); // return doctrine collection 
if (!$pages->isEmpty()) {   
    // Set the first page of the collection in session 
    $session = $request->getSession(); 
    $session->set('page', $pages->first()); 
} 
+0

更多信息,你是不是缺少在'Comment'實體'page_id'屬性? – cheesemacfly 2013-02-13 01:33:22

+0

我不應該在'Comment'實體中定義一個'page_id'屬性,因爲已經定義了關係'ManyToOne'(這是爲了解決這個問題)。在我的數據庫模式中,我在'Comment'表中包含了正確的字段:'user_id'和'page_id' – maxwell2022 2013-02-13 02:12:49

+0

但是你需要添加'@ORM \ JoinColumn(name =「page_id」,referencedColumnName =「id」)''你的@ORM \ ManyToOne'。或者我錯過了什麼? – cheesemacfly 2013-02-13 02:33:38

回答

0

其實,你Page對象不是由實體管理器已知的,對象來自會話。 (正確的術語與實體經理「分離」。) 這就是爲什麼它會嘗試創建一個新的。

當您從不同來源獲得對象時,必須使用merge函數。 (從會話,從反序列化功能,等...)

而不是

// Fetch the page from the repository 
      $page = $this->getDoctrine()->getRepository('AcmePageBundle:page')->findOneBy(array(
       'id' => $page->getId() 
      )); 

您可以簡單地使用:

$page = $em->merge($page); 

,如果你要使用它會幫助你在你的會話中的對象。關於企業合併的here

+0

謝謝,明天我會看看。但我不確定我想在會話中存儲完整的「Page」實體。沒關係,我想我也可以使用註釋了嗎?我見過'cascade = {「merge」}',那是一樣的嗎? – maxwell2022 2013-02-13 12:57:16

+0

我想,從來沒有嘗試過註釋,讓我知道! – Pierrickouw 2013-02-13 13:25:03

+1

因此,您的解決方案正在工作,註釋不是!這不是很方便:( – maxwell2022 2013-02-13 22:26:02