无法在Symfony2/Doctrine2中持久化复杂的实体图


Unable to persist complex entity graph in Symfony2/Doctrine2

由于保密协议,我能提供的细节有点有限,所以请耐心等待。

我有一个复杂的实体图。它包括:

  • ParentChild之间的1对1关系。
  • Child包含FooChild实体中的ArrayCollection。级联。
  • FooChild表示FooChild之间的多对多连接表,但也包含Child需要跟踪的一些元数据。级联在每侧(FooChild)持续
  • Parent s不需要有Child .

关于FooChild,要100%清楚,关系是多对多的,但由于元数据,它包含多对一的关系定义:

/**
 * @ORM'Entity
 * @ORM'Table(name="foo_children", indexes={
 *      @ORM'Index(name="fooid_idx", columns={"foo_id"}),
 *      @ORM'Index(name="childid_idx", columns={"child_id"}),
 * })
 */
class FooChild
{
    /**
     * @ORM'Id()
     * @ORM'ManyToOne(targetEntity="Foo", cascade={"persist"})
     * @ORM'JoinColumn(name="foo_id", referencedColumnName="id", nullable=false)
     */
    protected $foo;
    /**
     * @ORM'Id()
     * @ORM'ManyToOne(targetEntity="Child", inversedBy="fooChildren", cascade={"persist"})
     * @ORM'JoinColumn(name="child_id", referencedColumnName="id", nullable=false)
     */
    protected $child;
    /**
     * @ORM'Column(type="smallint")
     */
    private $count;
    // methods
}

好的,所以有了这个结构,在Parent编辑页面上,我创建了一个选项,让某人添加Child到它,并使用这里看到的Symfony原型机制填充FooChild。当我尝试提交相当大的表单时,得到以下异常:

MyBundle'Entity'FooChild类型的实体通过一个外部实体MyBundle'Entity'Child具有身份,但是这个实体本身没有身份。你必须在相关实体上调用EntityManager#persist(),并确保在尝试持久化"MyBundle' entity 'FooChild"之前生成一个标识符。在Post Insert ID生成的情况下(比如MySQL的Auto-Increment或PostgreSQL的SERIAL),这意味着你必须在两个持久化操作之间调用EntityManager#flush()。

问题是,我试图以不同的顺序持久化这个图的各个部分,但异常仍然存在。我当前的尝试是:

$form = $this->createForm(new ParentType(), $parent);
if ($request->getMethod() == 'POST') {
    $form->handleRequest($request);
    if ($form->has('child')) {
        $data = $form->getData();
        $child = $data->getChild();
        $fooChildren = $child->getFooChildren();
        foreach ($fooChildren as $fc) {
            $em->persist($fc);
            $em->flush();
        }
        $em->persist($child);
        $em->flush();
    }
    $em->persist($parent);
    $em->flush();
}

在foreach中第一次尝试持久化时抛出异常。就像我之前说的,我已经交换了几次持久化的顺序,但是没有什么不同。我不知道还能尝试什么

我有一个最初的解决方案,删除Child的表单类型,并让Parent的表单类型处理未映射的(非常重要的)FooChild条目。然后,在控制器中,我有:

$em->persist($parent);
$em->flush();
if ($form->has('fooChildren')) {
    $child = new Child();
    $child->setParent($parent);
    $em->persist($child);
    $em->flush();
    // run through the FooChild entites and add them to the child
}

它工作了,但我遇到了一些其他不相关的问题,所以我目前正在重新组织我的模式