0

我花了很长时间试图弄清楚如何与 Doctrine 2 建立ManyToOne->OneToMany关系,但它仍然无法正常工作......

这是应用程序的行为:

  1. Page一个网站有
  2. AUser可以写CommentPage

这是我的实体(简化):

评论实体:

**
 * @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();
    }

我想要一个双向关系,以便能够从(使用)或从(使用)获取Comments的集合。PageUsergetComments()

我的问题是,当我尝试保存新的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\Entity\Comment#page”找到了一个新实体,该关系未配置为对实体进行级联持久操作:Acme\PageBundle\Entity\Page@000000005d8a1f2000000000753399d4。要解决此问题:在此未知实体上显式调用 EntityManager#persist() 或配置级联在映射中保持此关联,例如 @ManyToOne(..,cascade={"persist"})。如果您无法找出导致问题的实体,请执行“Acme\PageBundle\Entity\Page#__toString()”以获取线索。

但我不想添加cascade={"persist"},因为我不想在级联上创建页面,而只是链接现有的页面。

更新1:

如果我在设置之前获取页面,它就可以工作。但我仍然不知道为什么我应该这样做。

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

更新2:

我最终将 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());
}
4

1 回答 1

0

实际上,Page实体管理器不知道您的对象,该对象来自会话。(正确的术语是与实体管理器“分离”。)这就是为什么它试图创建一个新的。

当您从不同来源获取对象时,您必须使用merge函数。(来自会话,来自反序列化函数等......)

代替

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

您可以简单地使用:

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

如果您想在会话中使用对象,它将对您有所帮助。

有关合并实体的更多信息在这里

于 2013-02-13T09:04:24.820 回答