簡體   English   中英

OneToMany不保存更改

[英]OneToMany doesn't save changes

我在兩個實體之間有一個oneToMany-ManyToOne關系。

在“部門”編輯頁面(所有者,ManyToOne)上進行編輯時,所做的更改將保存到部門表中,
但是從Utilisateur編輯頁面(反面,OneToMany)進行編輯,所做的更改將不會保存到“部門”表中。

有人可以舉例說明為什么它不起作用嗎?

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(),
    ));
}

您需要確保該實體由Doctrine管理。 您可以通過使用對象作為參數( $em->persist($utilisateur) )調用persist方法來實現。

當您通過Doctrine檢索對象時,該對象已經被管理,因此Doctrine可能沒有意識到它也應該通過OneToMany關系持久化對象。 如@Dirk所述,設置級聯操作肯定會有所作為。 您可以像這樣將其添加到Utilisateur類中:

@ORM\OneToMany(targetEntity="AppBundle\Entity\Departement", mappedBy="commercial", cascade={"persist"})

當您嘗試持久保存不是由Doctrine管理的實體時(通過關系),您應該收到一個異常。 所以很奇怪你沒有一個...

檢查表單是否確實在創建Department實例並將其添加到Utilisateur類(在將“部門”字段添加到表單時未指定類型)。

您需要使用cascade={"persist"}來定義級聯操作,如下所示:

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

在您的FormType中,您需要執行以下操作。

public function buildForm(FormBuilderInterface $builder, array $options)     {

 $builder->add('departements', CollectionType::class, array(
            'entry_type'=> DepartmentType::class,
            'allow_add' => true,
            'allow_delete' => true,
            'allow_extra_fields' => true,
            'by_reference' => false // calls addDepartement / removeDepartement on parent(Utilisateur) automatically
        ));}

有關信息,請閱讀: https : //symfony.com/doc/current/form/form_collections.html

所以...感謝TEDx在經過數小時的搜索和閱讀,大量的轉儲以及與熊的小聊天之后向我提示了一些文檔,我終於明白了以下內容。

首先,Doctrine似乎只檢查關系擁有方的數據。 這意味着如果從反面完成,它將無法處理任何事情。

其次,與第一個問題有關,當我試圖以相反的方式進行操作時,Doctrine不會在表單數組集合中設置departement.commercial 因此,與表中的數據沒有區別,它不會進行任何查詢。

最后,Doctrine將不會檢測到該格式中的任何未經檢查的條目(因此將departement.commercial設置為NULL )。

在我想出的解決方案之下。 它適用於OneToMany / ManyToOne關系的反面。 並進行一些調整也可以用於ManyToMany關系。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM