2013-02-13 69 views
2

背景:Symfony2的分离实体

在我的应用程序有一个具有自参考ManyToOne协会(很多孩子可以指向一个单亲)的实体。而且我有一个功能,可以一次使用Doctrine ORM对许多实体进行批量更新。为了防止由于许多实体在更新后加载实体而使性能显着下降。

问题:

当我detach孩子后来尝试更新任何这些孩子主义抱怨说,它不知道了的实体。即使我试图更新之前merge父母实体。

问:

我在做什么错了,当我拆开实体?我试过在父列上执行级联=“合并”和/或“分离”,并且当我尝试坚持时,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

的问题是,孩子有一个关系特定的父对象不再由Doctr管理国家统计局。当您拨打$entityManager->merge($entity)时,您将从该功能中获得一个新的托管实体。

当你回来时,你需要手动拨打setParent()每个你的孩子与新管理的实体。

+0

你说'合并'返回一个新对象(通常我不需要重新合并实体;我只是在我的测试中这样做)。不过,我认为这是教义上的一个潜在缺陷。因为一旦我将父母分开,我不能再对任何孩子坚持任何改变。任何人都有任何见解,为什么这是预期的行为? – lifo 2013-02-13 15:15:38

+1

我不会把它称为教义上的缺陷。你要求它将一个孩子坚持到一个它不知道的父母那里。就教条而言,这样做会违反表中的外键约束(因为它不能确认实体是否有效)。我认为还有其他的优化你应该担心,而不是分离所有这些实体。例如,像显式地将要保存的实体传递给'flush()'方法,所以教义不会扫描它们。 – 2013-02-13 15:35:48

+0

那么,这是有道理的,并让我意识到,我正在关注错误的实体重新合并。我可以合并可以级联到父级的'$ t2',而不是试图合并'$ t1'。我已经证实了这个作品。感谢您的意见。我并没有真正使用很多级联,并且我尝试了其他优化的所有方式,但是分离是我发现使导入功能不起作用而不减速到每秒1次或甚至更慢的唯一方式。 – lifo 2013-02-13 15:51:47