OneToMany 不保存更改 [英] OneToMany doesn't save changes

查看:40
本文介绍了OneToMany 不保存更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个实体之间的 oneToMany - ManyToOne 关系.

I have a oneToMany - ManyToOne relation between two entities.

在部门编辑页面(拥有方,ManyToOne)进行编辑时,更改将保存到部门表中,
但是从 Utilisateur 编辑页面(反面,OneToMany)进行编辑,更改不会保存到部门表中.

When editing on the Departement edit page (owning side, ManyToOne), changes will be saved into the departement table,
but editing from the Utilisateur edit page (inverse side, OneToMany), changes won't be saved into the Departement table.

有人能解释一下为什么它不起作用吗?

Can someone exmplain me why it's not working?

src/AppBundle/Entity/Utilisateur.php

class Utilisateur implements UserInterface, \Serializable {
    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Departement", mappedBy="commercial")
     */
    private $departements;

    /**
     * Constructor
     */
    public function __construct() {
        $this->departements=new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * @param \AppBundle\Entity\Departement $departement
     * @return Utilisateur
     */
    public function addDepartement(\AppBundle\Entity\Departement $departement)
    {
        $this->departements[] = $departement;

        return $this;
    }

    /**
     * @param \AppBundle\Entity\Departement $departement
     */
    public function removeDepartement(\AppBundle\Entity\Departement $departement)
    {
        $this->departements->removeElement($departement);
    }

    /**
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getDepartements()
    {
        return $this->departements;
    }
}

src/AppBundle/Entity/Departement.php

class Departement {
    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Utilisateur", inversedBy="departements")
     */
    private $commercial;

    /**
     * @param \AppBundle\Entity\Utilisateur $commercial
     * @return Departement
     */
    public function setCommercial(\AppBundle\Entity\Utilisateur $commercial=null) {
        $this->commercial=$commercial;

        return $this;
    }

    /**
     * @return \AppBundle\Entity\Utilisateur
     */
    public function getCommercial() {
        return $this->commercial;
    }
}

src/AppBundle/Form/Utilisateur/Edit3dhType.php

public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder->add('departements', EntityType::class, array(
        'class'=>Departement::class,
        'expanded'=>true,
        'multiple'=>true
    ));
}

src/AppBundle/Controller/UtilisateurController.php

/**
 * @Route("/dashboard/utilisateurs/edit-{id}", name="security_edit_user")
 * @Method({"GET", "POST"})
 *
 * @param Request $request
 * @param Utilisateur $utilisateur
 * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
 */
public function editAction(Request $request, Utilisateur $utilisateur) {
    $logo=$utilisateur->getLogo();
    if($utilisateur->getLogo() !== null) {
        $utilisateur->setLogo(new File($this->getParameter('dir_picto').$logo));
    }

    $form=$this->createForm(Edit3dhType::class, $utilisateur, array(
        'action'=>$this->generateUrl('security_edit_user', array('id'=>$utilisateur->getId())),
        'method'=>'POST',
    ));

    $form->handleRequest($request);
    if($form->isSubmitted() && $form->isValid()) {
        if($utilisateur->getLogo() !== null) {
            $utilisateur->setLogo($this->container->get('service.upload')->uploadPicto($utilisateur->getLogo()));
        } else {
            $utilisateur->setLogo($logo);
        }

        $em=$this->getDoctrine()->getManager();
        $em->flush();
    }

    return $this->render('security/edit.html.twig', array(
        'user'=>$this->getUser(),
        'utilisateur'=>$utilisateur,
        'form'=>$form->createView(),
    ));
}

推荐答案

所以……感谢 TEDx 向我暗示了一些文档,经过数小时的搜索和阅读、大量的转储以及与熊的小聊天……我开始了解以下内容.

So... Thanks to TEDx who hinted me some docs, after hours of searchs and reading, tons of dumps and a small chat with a bear... I came to understand the following.

首先,Doctrine 似乎只检查关系拥有方的数据.这意味着如果从相反的一侧完成它就不会处理事情.

First, Doctrine seems to only check data on the owning side of the relation. Meaning that it won't handle things if done from the inverse side.

第二,关于第一个问题,当我试图做相反的事情时,Doctrine不会在表单数组集合中设置departement.commercial.因此,发现与表中的数据没有差异,它不会进行任何查询.

Second, related to the first problem, as I'm trying to do things on the inverse side, Doctrine won't set departement.commercial in the form array collection. Thus, finding no differences with the data in the table, it doesn't make any query.

最后,Doctrine 不会检测表单中任何未经检查的条目(因此将 departement.commercial 设置为 NULL).

Last, Doctrine won't detect any unchecked entry in the form (so setting departement.commercial to NULL).

在我想出的解决方案下面.它适用于 OneToMany/ManyToOne 关系的反面.并且通过一些调整也可以用于多对多关系.

Below the solution I came up with. It apply for the inverse side of OneToMany/ManyToOne relations. And with some tweak can also be used for ManyToMany relations.

src/AppBundle/Controller/UtilisateurController.php

public function editAction(Request $request, Utilisateur $utilisateur) {
    //Save pre submit data
    $preSubmitDepartement=$utilisateur->getDepartements()->toArray();

    $form=$this->createForm(UtilisateurType::class, $utilisateur, array(
        'action'=>$this->generateUrl('security_edit_user', array('id'=>$utilisateur->getId())),
        'method'=>'POST',
        'utilisateur'=>$utilisateur,
    ));

    $form->handleRequest($request);
    if($form->isSubmitted() && $form->isValid()) {
        $em=$this->getDoctrine()->getManager();

        //Get post submit data
        $postSubmitDepartement=$utilisateur->getDepartements()->toArray();

        //Keep only IDs for pre and post submit data
        /** @var Departement $v */
        foreach($preSubmitDepartement as $k=>$v) {
            $preSubmitDepartement[$k]=$v->getId();
        }
        /** @var Departement $v */
        foreach($postSubmitDepartement as $k=>$v) {
            $postSubmitDepartement[$k]=$v->getId();
        }

        //Find removed IDs
        $prePostSubmitDifference=array_map('unserialize', array_diff(array_map('serialize',$preSubmitDepartement), array_map('serialize',$postSubmitDepartement)));

        //Fetch related Departement entries
        $departements=$em->getRepository(Departement::class)->findBy(array('id'=>array_merge($postSubmitDepartement, $prePostSubmitDifference)));

        //setCommercial to $utilisateur or null
        /** @var Departement $departement */
        foreach($departements as $departement) {
            if(in_array($departement->getId(), $postSubmitDepartement)) {
                $departement->setCommercial($utilisateur);
            } else if(in_array($departement->getId(), $prePostSubmitDifference)) {
                $departement->setCommercial(null);
            }
        }

        $em->flush();
    }

    return $this->render('security/edit.html.twig', array(
        'user'=>$user,
        'utilisateur'=>$utilisateur,
        'form'=>$form->createView(),
    ));
}

现在我可以从反面设置departement.conseiller.

Now I can set departement.conseiller from the inverse side.

这篇关于OneToMany 不保存更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆