0

Doctrine2 是否支持从反向更改关联时更新关联的能力?如果不是开箱即用,是否有一个插件/扩展可以用来覆盖这种行为?

这是我所拥有的一个例子:

Organization
/**
 * @Id
 * @Column(type="integer")
 */
    protected $id

/**
 * @ManyToOne(targetEntity="Organization", inversedBy="children", cascade={"persist"})
 * @JoinColumn(name="parent_org_id", referencedColumnName="id")
 */
protected $parent;

/**
* @OneToMany(targetEntity="Organization", mappedBy="parent", cascade={"persist"})
*/
protected $children;    
4

1 回答 1

1

不。 Doctrine 2 通过拥有方跟踪关联,并且由于它试图对您的实体的行为产生最小的影响,它不想添加这种功能。

跟踪反向更改的标准方法是通过向您的实体添加逻辑来确保它们保持同步,这些逻辑在反向进行更改时会更新拥有端。

在您的示例中,您可以使用 addChild、removeChild 和 setParent 函数来执行以下操作:

public function addChild(Organization $child) 
{
    $this->children[] = $child;
    $child->setParent($this); // < update the owning side
}

public function removeChild(Organization $child) 
{
    $this->children->removeElement($child);
    $child->setParent(null); // < update the owning side
}

public function setParent(Organization $parent = null) 
{
    $this->parent = $parent;
}

您可以看到现在出现了一个新问题,您必须始终使用 addChild/removeChild 函数(即在反面进行更改)以使拥有方保持同步(或自己同步,作为调用方)。这导致您必须创建一个策略,调用者必须始终在拥有方或反方更新。

也可以使setParent函数更新反面,但您必须非常小心,因为这很容易导致无限递归:

public function addChild(Organization $child) 
{
    $this->children[] = $child;
    // safely update the owning side
    if ($child->getParent() != $this) {
       $child->setParent($this);
    }
}

public function removeChild(Organization $child) 
{
    $this->children->removeElement($child);
    // safely update the owning side
    if ($child->getParent() == $this) {
        $child->setParent(null); 
    }
}

public function setParent(Organization $parent = null) 
{
    $oldParent = $this->parent;
    $this->parent = $parent;
    // update the inverse side
    if ($oldParent) {
        $oldParent->removeChild($this); // will not call setParent
    }
    if ($this->parent) {
        $this->parent->addChild($this); // will not call setParent
    }
}

除了增加的复杂性之外,这种方案在例如将许多孩子从一个父母移动到另一个父母时并不理想,因为 removeChild 需要线性时间,从而为移动创建 O(n^2) 运行时间。

于 2013-07-02T06:42:46.923 回答