我正在使用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,则该树已保留在数据库中
然后我用以下一个调用更新控制器(当然要遵守ID)
Doctrine将能够“看到”新结构中缺少节点5,然后自己执行$entityManager->remove($node5)
。
这不是梦吗,有什么方法可以使教义表现得像这样?还是我必须递归地走到树上进行逐节点比较,以便自己通过entityManager
进行修改?
答案 0 :(得分:0)
我得出的结论是,《主义》不是那么神奇;)
所以我必须:
merge
操作沿children
关系传播(带有cascade={"merge"}
注释)merge
根节点$em->remove
操作,而传入树上不存在这些节点$em->flush