如何在多个级别上更新实体及其关系?

时间:2018-09-19 16:11:37

标签: symfony doctrine

我正在使用Symfony 3和Doctrine开发一个Web应用程序,该应用程序允许绘制树结构并将其持久化。

一个节点包含一个OneToMany关系的子节点,称为children,树的根是唯一一个不是其他任何节点的子节点的节点。

这是实体:

/**
 * @ORM\Entity(repositoryClass="App\Repository\NodeRepository")
 */
class Node
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    public $id;

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

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Node", mappedBy="parent")
     */
    public $children;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Node", inversedBy="children")
     * @ORM\JoinColumn(name="id_parent", referencedColumnName="id")
     */
    public $parent;

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

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }

    /**
     * @return Collection|Node[]
     */
    public function getChildren(): Collection
    {
        return $this->children;
    }

    public function addChild(Node $child): self
    {
        if (!$this->children->contains($child)) {
            $this->children[] = $child;
            $child->setParent($this);
        }

        return $this;
    }

    public function removeChild(Node $child): self
    {
        if ($this->children->contains($child)) {
            $this->children->removeElement($child);
            // set the owning side to null (unless already changed)
            if ($child->getParent() === $this) {
                $child->setParent(null);
            }
        }

        return $this;
    }

    public function getParent(): ?self
    {
        return $this->parent;
    }

    public function setParent(?self $parent): self
    {
        $this->parent = $parent;

        return $this;
    }
}

创建树没有特殊问题。但是当涉及到更新时,我不确定什么是最好的方法。 主要示例是删除节点(但该问题也适用于移动节点),我将进一步说明该问题。

我有一个updateNodeAction控制器,它将整个新树作为参数(在结构中始终设置了学说ID)。我想用已经持久化的树来merge,以便在执行flush时删除被删除的节点。

在我的梦中,我想像(参数$node是设置了ID的根节点)之类的东西

public function updateNodeAction(Node $node, EntityManagerInterface $entityManager) {
    $entityManager->merge($node);
    $entityManager->flush();
    return new Response('OK');
}

其中,Doctrine处理数据库中节点本身及其所有后代的所有修改(添加,删除,移动)。例如,如果以下根目录为ID的树为1,则该树已保留在数据库中

initial state

然后我用以下一个调用更新控制器(当然要遵守ID)

modified state

Doctrine将能够“看到”新结构中缺少节点5,然后自己执行$entityManager->remove($node5)

这不是梦吗,有什么方法可以使教义表现得像这样?还是我必须递归地走到树上进行逐节点比较,以便自己通过entityManager进行修改?

1 个答案:

答案 0 :(得分:0)

我得出的结论是,《主义》不是那么神奇;)

所以我必须:

  • 声明“教义” merge操作沿children关系传播(带有cascade={"merge"}注释)
  • merge根节点
  • 在合并之前在树上存在的节点上调用$em->remove操作,而传入树上不存在这些节点
  • 最后,致电$em->flush