具有ManyToOne关联的Symfony2分离实体

时间:2013-02-13 14:59:19

标签: php symfony doctrine-orm symfony-2.1 cascade

背景:

在我的应用程序中,我有一个实体,它具有自引用 ManyToOne关联(许多孩子可以指向单亲)。我有一个功能,使用Doctrine ORM一次对许多实体进行批量更新。为了防止性能因许多实体被加载而导致性能下降detach实体一旦更新。

问题:

当我detach一个拥有孩子的实体,然后尝试更新其中任何一个孩子时,Doctrine会抱怨它不知道父母了。在尝试更新孩子之前,即使我merge 实体。

问题:

当我分离实体时,我做错了什么?我尝试在父列上执行cascade =“merge”和/或“detach”,当我尝试保留时,Doctrine仍抱怨是一个未知实体。

我已经嘲笑了一个重现这个的简单例子。见下文。

测试代码:

实体\ Thing.php

/**
 * @ORM\Entity()
 * @ORM\Table(name="things")
 */
class Thing
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\ManyToOne(targetEntity="Thing", inversedBy="children", cascade={"detach","merge"})
     * @ORM\JoinColumn(name="parentId", referencedColumnName="id", onDelete="SET NULL")
     */
    protected $parent;

    /**
     * @ORM\OneToMany(targetEntity="Thing", mappedBy="parent")
     */
    protected $children;

    /**
     * @ORM\Column(type="string", length=64)
     */
    protected $name;

    public function __construct($name = null)
    {
        $this->children = new ArrayCollection();
        $this->name = $name;
    }

    // .. SNIP ...
}

测试操作:

public function testThingAction($_route)
{
    $em = $this->getDoctrine()->getEntityManager();
    $repo = $em->getRepository('AcmeThingBundle:Thing');

    // simple setup of a couple things in the DB
    $t1 = $repo->findByName('Thing1');
    if (!$t1) {
        $t1 = new Thing('Thing1');
        $t2 = new Thing('Thing2');
        $t2->setParent($t1);

        $em->persist($t1);
        $em->persist($t2);
        $em->flush();
        return $this->redirect($this->generateUrl($_route));
    }

    list($t1, $t2) = $repo->findAll();

    // detach and re-merge Thing1
    // This should cause Thing1 to be removed and then re-added 
    // to the doctrine's known entities; but it doesn't!?
    $em->detach($t1);
    $em->merge($t1);

    // try to update T2
    $t2->setName('Thing2 - ' . time());
    $em->persist($t2);
    // will fail with: 
    // A new entity was found through the relationship Thing#parent
    $em->flush();

    return array();
}

1 个答案:

答案 0 :(得分:1)

问题是,子节点与不再由Doctrine管理的特定父对象有关系。当您致电$entityManager->merge($entity)时,您将从该功能获得一个新的托管实体。

当您收到回复后,您需要使用新管理的实体手动呼叫每个孩子的setParent()