我有一段时间试图找出如何设置ManyToOne
- > OneToMany
与Doctrine 2的关系,但仍无法正常工作......
以下是应用程序行为:
Page
s 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
或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
实体(我已经在DB也是。)
我现在不知道该怎么做,我找不到有同样问题的人:(
这是我的确切错误消息:
通过这种关系找到了一个新的实体 'Acme \ CommentBundle \ Entity \ Comment#page'未配置为 实体的级联持久化操作: ACME \ PageBundle \实体\页@ 000000005d8a1f2000000000753399d4。要解决 此问题:在此显式调用EntityManager#persist() 未知实体或配置级联持久化此关联 映射例如@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 :(得分:0)
实际上,实体管理器不知道您的Page
对象,该对象来自会话。 (正确的术语与实体经理“分离”。)
这就是为什么它试图创建一个新的。
当您从不同来源获取对象时,您必须使用merge
函数。 (来自会话,来自unserialize函数等...)
而不是
// Fetch the page from the repository
$page = $this->getDoctrine()->getRepository('AcmePageBundle:page')->findOneBy(array(
'id' => $page->getId()
));
您可以简单地使用:
$page = $em->merge($page);
如果您想在会话中使用对象,它会对您有所帮助。
有关合并实体here
的更多信息