Doctrine ManyToMany 自引用双向 - Parent 未更新
Doctrine ManyToMany self referencing bidirectionnal - Parent not updated
我正在尝试创建一个公司服务的多对多关系。
每个服务有 N parents 个服务和 N children 个服务。
我在这里查看了原则文档:Many-To-Many, Self-referencing 并按如下方式实现了它:
这是我的服务实体:
<?
namespace AppBundle\Entity;
class Service
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Service", mappedBy="enfants", cascade={"persist"})
*/
private $parents;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Service", inversedBy="parents")
* @ORM\JoinTable(name="app_services_hierarchy",
* joinColumns={@ORM\JoinColumn(name="parent_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="enfant_id", referencedColumnName="id")}
* )
*/
private $enfants;
public function __construct()
{
$this->enfants = new ArrayCollection();
$this->parents = new ArrayCollection();
}
public function getId(){
return $this->id;
}
//--------------------------------------------------Enfants
public function getEnfants(){
return $this->enfants;
}
public function setEnfants($enfant){
$this->enfants = $enfant;
}
public function addEnfant(Service $s){
$this->enfants[] = $s;
return $this;
}
public function removeEnfant(Service $s){
$this->enfants->removeElement($s);
}
//--------------------------------------------------Parents
public function getParents(){
return $this->parents;
}
public function setParents($parents){
$this->parents = $parents;
}
public function addParent(Service $s){
$this->parents[] = $s;
return $this;
}
public function removeParent(Service $s){
$this->parents->removeElement($s);
}
}
这是我的编辑功能(Controller.php) :
public function editAction(Request $request, $id)
{
$service = $this->getDoctrine()->getRepository(Service::class)->find($id);
$form = $this->createForm(ServiceType::class, $service);
$form ->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager ->persist($service);
dump($service);
$entityManager ->flush();
}
return $this->render('AppBundle:Service:edit.html.twig', array(
'form' => $form->createView(),
));
}
生成的表单如下所示:
问题:
我的问题是 children 已更新,但 parents 未更新。当我在我的控制器中 dump()
时,我可以在 $service
变量中看到 parents 但在我的数据库 table (app_services_hierarchie) 中唯一更新的是children.
代码中 $parents
和 $enfants
之间的区别在于,如果您的 $enfants
映射,但不是 $parents
映射的情况。
Doctrine 不会存储 $parents
除非你通过 cascade={"persist"}
告诉它这样做。
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Service", mappedBy="enfants", cascade={"persist"})
*/
这与@GregoireDucharme 链接的 post 中给出的答案基本相同。
编辑: 经过一番研究,显然这个问题不能用级联来解决。根据 Doctrine documentation:
Doctrine will only check the owning side of an association for changes.
所以您要做的就是告诉您的 $parents
也更新 $children
属性。
public function addParent(Service $s){
$this->parents[] = $s;
$s->addEnfant($this);
return $this;
}
public function removeParent(Service $s){
$this->parents->removeElement($s);
$s->removeEnfant($this);
}
在您的表单中,确保指定以下内容:
->add('parents', 'collection', array(
'by_reference' => false,
//...
))
(我没有对上面的任何代码进行拼写检查,因此请谨慎行事。)
如果'by_reference'
设置为true
,addParent
和removeParent
将不会被调用。
感谢 Anny Filina 的 blog post。
它还声明您可以从 $parents
属性 中删除 cascade
选项,但您可能应该将 cascade={"persist","remove"}
添加到 $enfants
属性.
我正在尝试创建一个公司服务的多对多关系。 每个服务有 N parents 个服务和 N children 个服务。
我在这里查看了原则文档:Many-To-Many, Self-referencing 并按如下方式实现了它:
这是我的服务实体:
<?
namespace AppBundle\Entity;
class Service
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Service", mappedBy="enfants", cascade={"persist"})
*/
private $parents;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Service", inversedBy="parents")
* @ORM\JoinTable(name="app_services_hierarchy",
* joinColumns={@ORM\JoinColumn(name="parent_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="enfant_id", referencedColumnName="id")}
* )
*/
private $enfants;
public function __construct()
{
$this->enfants = new ArrayCollection();
$this->parents = new ArrayCollection();
}
public function getId(){
return $this->id;
}
//--------------------------------------------------Enfants
public function getEnfants(){
return $this->enfants;
}
public function setEnfants($enfant){
$this->enfants = $enfant;
}
public function addEnfant(Service $s){
$this->enfants[] = $s;
return $this;
}
public function removeEnfant(Service $s){
$this->enfants->removeElement($s);
}
//--------------------------------------------------Parents
public function getParents(){
return $this->parents;
}
public function setParents($parents){
$this->parents = $parents;
}
public function addParent(Service $s){
$this->parents[] = $s;
return $this;
}
public function removeParent(Service $s){
$this->parents->removeElement($s);
}
}
这是我的编辑功能(Controller.php) :
public function editAction(Request $request, $id)
{
$service = $this->getDoctrine()->getRepository(Service::class)->find($id);
$form = $this->createForm(ServiceType::class, $service);
$form ->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager ->persist($service);
dump($service);
$entityManager ->flush();
}
return $this->render('AppBundle:Service:edit.html.twig', array(
'form' => $form->createView(),
));
}
生成的表单如下所示:
问题:
我的问题是 children 已更新,但 parents 未更新。当我在我的控制器中 dump()
时,我可以在 $service
变量中看到 parents 但在我的数据库 table (app_services_hierarchie) 中唯一更新的是children.
代码中 $parents
和 $enfants
之间的区别在于,如果您的 $enfants
映射,但不是 $parents
映射的情况。
Doctrine 不会存储 $parents
除非你通过 cascade={"persist"}
告诉它这样做。
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Service", mappedBy="enfants", cascade={"persist"})
*/
这与@GregoireDucharme 链接的 post 中给出的答案基本相同。
编辑: 经过一番研究,显然这个问题不能用级联来解决。根据 Doctrine documentation:
Doctrine will only check the owning side of an association for changes.
所以您要做的就是告诉您的 $parents
也更新 $children
属性。
public function addParent(Service $s){
$this->parents[] = $s;
$s->addEnfant($this);
return $this;
}
public function removeParent(Service $s){
$this->parents->removeElement($s);
$s->removeEnfant($this);
}
在您的表单中,确保指定以下内容:
->add('parents', 'collection', array(
'by_reference' => false,
//...
))
(我没有对上面的任何代码进行拼写检查,因此请谨慎行事。)
如果'by_reference'
设置为true
,addParent
和removeParent
将不会被调用。
感谢 Anny Filina 的 blog post。
它还声明您可以从 $parents
属性 中删除 cascade
选项,但您可能应该将 cascade={"persist","remove"}
添加到 $enfants
属性.