Doctrine ManyToMany 自引用双向 - 父级未更新

Posted

技术标签:

【中文标题】Doctrine ManyToMany 自引用双向 - 父级未更新【英文标题】:Doctrine ManyToMany self referencing bidirectionnal - Parent not updated 【发布时间】:2018-03-27 13:07:37 【问题描述】:

我正在尝试创建公司的多对多关系 beetwin 服务。 每个服务都有 N 个父母 服务和 N 个孩子 服务。

我在这里查看了教义文档: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(),
    ));

生成的表单如下所示:

问题:

我的问题是 孩子更新了,但父母没有更新。当我在控制器中 dump() 时,我可以在 $service 变量中看到父级,但在我的数据库表 (app_services_hierarchie) 中更新的唯一是子级。

【问题讨论】:

看看***.com/questions/5033825/… 可能是这样,但它仍然无法正常工作......奇怪的是,当我更新时,表单被重新加载,我之前选择的父母被选中(所以我的实体充满了父母)但数据库中没有任何内容,所以一旦我重新加载页面它们就会消失...... 【参考方案1】:

您的代码中$parents$enfants 之间的区别在于,在您的$enfants 映射的情况下,您正在查看的服务是拥有方,但在你的$parents 映射。

Doctrine 不会存储 $parents,除非您通过 cascade="persist" 告诉它这样做。

/**
 * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Service", mappedBy="enfants", cascade="persist")
 */

这与@GregoireDucharme 链接的帖子中给出的答案基本相同。

编辑:经过一番研究,显然这个问题不能使用级联解决。根据Doctrine documentation:

Doctrine 只会检查关联的拥有方是否有更改。

所以你要做的就是告诉你的$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' 设置为trueaddParentremoveParent 将不会被调用。

感谢 Anny Filina 的 blog post。

它还指出您可以从您的$parents 属性中删除cascade 选项,但您可能应该将cascade="persist","remove" 添加到您的$enfants 属性中。

【讨论】:

我之前尝试过这个解决方案,但它仍然无法正常工作,实体已更新但数据库未更新。数据库刚刚为儿童(儿童)更新/我编辑了我的问题以添加级联持久性(即使它不起作用,你们都告诉我添加它,我可能是解决方案的一部分,这很有意义) 您是否也尝试过添加refreshcascade="persist", "refresh"。真的不确定这是否与“更新”实体有关,但值得一试。 @Gauthier 编辑了我的回复。看起来该位置的 cascade 选项不是您正在寻找的解决方案。 我想我已经很接近了,当我尝试更新时收到错误“Expected argument of type "AppBundle\Entity\Service", "string" given",并且没有显示表单不再作为选择列表。我觉得我更近了。无论如何感谢您查看此内容,我认为您找到了问题@micha

以上是关于Doctrine ManyToMany 自引用双向 - 父级未更新的主要内容,如果未能解决你的问题,请参考以下文章

为啥这个 Doctrine OneToOne 自引用双向关联不起作用?

学说:在自引用中删除实体(多对多)

用于 ManyToMany 的 Symfony Doctrine 重命名表

Symfony2-Doctrine:ManyToMany 关系未保存到数据库

php Doctrine Tabel Realtion Annotations(ManyToOne,OneToMany,ManyToMany)

Doctrine Symfony ManyToMany 将表作为 OneToMany 连接到其他表