我花了很长时间试图弄清楚如何与 Doctrine 2 建立ManyToOne
->OneToMany
关系,但它仍然无法正常工作......
这是应用程序的行为:
Page
一个网站有- A
User
可以写Comment
在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();
}
我想要一个双向关系,以便能够从(使用)或从(使用)获取Comment
s的集合。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\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());
}