【发布时间】:2013-02-13 17:04:24
【问题描述】:
我花了很长时间试图弄清楚如何与 Doctrine 2 建立 ManyToOne -> OneToMany 关系,但它仍然无法正常工作......
这是应用程序的行为:
- 一个网站有
Pages -
User可以在Page上写Comment
这是我的实体(简化版):
评论实体:
**
* @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())获取Comments 的集合。
我的问题是,当我尝试保存新的 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());
}
【问题讨论】:
-
您的
Comment实体中是否缺少page_id属性? -
我不应该在
Comment实体中定义page_id属性,因为已经定义了ManyToOne关系(假设可以处理此问题)。在我的数据库架构中,Comment表中有正确的字段:user_id和page_id -
但是你需要在你的
@ORM\ManyToOne下添加@ORM\JoinColumn(name="page_id", referencedColumnName="id")。还是我错过了什么? -
好吧,我错了!
-
是的,它已经默认了 ;)
标签: symfony doctrine-orm one-to-many many-to-one