[英]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.