OneToMany 不保存更改
OneToMany doesn't save changes
我在两个实体之间有一个 oneToMany - ManyToOne 关系。
在部门编辑页面(拥有方,ManyToOne)上编辑时,更改将保存到部门table,
但是从 Utilisateur 编辑页面(反面,OneToMany)进行编辑,更改不会保存到部门 table。
有人可以解释一下为什么它不起作用吗?
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
class:
@ORM\OneToMany(targetEntity="AppBundle\Entity\Departement", mappedBy="commercial", cascade={"persist"})
当你试图持久化一个不受 Doctrine 管理的实体(通过关系)时,你应该会收到一个异常。所以很奇怪你没有得到...
检查表单是否实际创建了一个 Department
实例并将其添加到 Utilisateur
class(添加 "department" 时未指定类型表单字段)。
您需要像这样使用 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
。因此,发现与table中的数据没有差异,因此不进行任何查询。
最后,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
我在两个实体之间有一个 oneToMany - ManyToOne 关系。
在部门编辑页面(拥有方,ManyToOne)上编辑时,更改将保存到部门table,
但是从 Utilisateur 编辑页面(反面,OneToMany)进行编辑,更改不会保存到部门 table。
有人可以解释一下为什么它不起作用吗?
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
class:
@ORM\OneToMany(targetEntity="AppBundle\Entity\Departement", mappedBy="commercial", cascade={"persist"})
当你试图持久化一个不受 Doctrine 管理的实体(通过关系)时,你应该会收到一个异常。所以很奇怪你没有得到...
检查表单是否实际创建了一个 Department
实例并将其添加到 Utilisateur
class(添加 "department" 时未指定类型表单字段)。
您需要像这样使用 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
。因此,发现与table中的数据没有差异,因此不进行任何查询。
最后,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