我一直关注How to Embed a Collection of Forms Symfony 网站上的示例。
我的情况有点不同。我有 2 个 Doctrine 实体 Experiment
和 Goal
,其 composite primary key关系(参见下面的代码)。
基本上,一个实验
可以有多个目标
,但目标ID仅在与实验
ID和用户组合时才是唯一的
ID。
class Goal
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer", options={"default": 1})
* @ORM\Id
*/
protected $id = 1;
/**
* @var integer
*
* @ORM\Column(name="experiment_id", type="integer", nullable=true, options={"default": null})
* @ORM\Id
*/
protected $experimentId;
/**
* @ORM\ManyToOne(targetEntity="Experiment", inversedBy="goals")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="experiment_id", referencedColumnName="id"),
* @ORM\JoinColumn(name="user_id", referencedColumnName="user_id")
* })
*/
protected $experiment;
/**
* @var integer
*
* @ORM\Column(name="user_id", type="integer", nullable=true, options={"default": null})
* @ORM\Id
*/
protected $userId;
/**
* @ORM\ManyToOne(targetEntity="Optimcore\UserBundle\Entity\User", inversedBy="goals", cascade={"persist"})
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
// ...
}
我有一个 ExperimentType
表单,其中嵌入 GoalType
表单的 'collection'
。
在我的 Controller 中,我有以下代码:
$originalGoals = new ArrayCollection();
foreach ($experiment->getGoals() as $goal) {
$originalGoals->add($goal);
}
$form = $this->createForm(new ExperimentType(), $experiment, array(
'action' => $this->generateUrl('experiment_goals', array('id' => $experiment->getId())),
'method' => 'PUT',
));
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
// remove the relationship between the Goal and the Experiment
foreach ($originalGoals as $goal) {
if (false === $experiment->getGoals()->contains($goal)) {
$goal->setExperiment(null);
$em->persist($goal);
$em->remove($goal);
}
}
foreach ($experiment->getGoals() as $goal) {
if (is_null($goal->getUserId())) {
$this->getUser()->addGoal($goal);
$goal->setUserId($this->getUser()->getId());
$goal->setUser($this->getUser());
$em->persist($goal);
}
}
$em->flush();
}
我有 javascript 来添加和删除页面上的目标表单。新目标将分配下一个可用 ID,因此,如果页面上最后一个目标的 ID 为 2,则下一个目标的 ID 为 3。
添加新目标并保存到数据库工作正常,删除目标并保存也工作正常。
但是,当通过页面上的 javascript 删除目标,然后通过 javascript 添加新目标时,该目标将被分配与已删除目标相同的 ID。现在,当提交表单并且 Doctrine 尝试保存目标时,会引发 SQL 错误,因为 Doctrine 尝试插入一个与 Javascript 删除的目标具有相同 ID 但仍在数据库中的目标。
如何让 Doctrine 在插入新目标之前删除第一个目标?我之前尝试过冲洗,但这没有帮助。如何强制 Doctrine 在添加保存新目标之前仅删除旧目标?还是我的做法完全错了?
错误消息如下:
An exception occurred while executing 'INSERT INTO goal (id, experiment_id, user_id, name) VALUES (?, ?, ?, ?)' with params ["2", 183, 6, "Goal 2"]:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2-183-6' for key 'PRIMARY'
最佳答案
在 Doctrine documentation 中找到了一个很长问题的非常简单的答案。 .
10.2. How Doctrine Detects Changes
- Flush only a single entity with
$entityManager->flush($entity)
.
为了让 Doctrine 在保存新目标之前删除原始目标,我必须在 $em->remove($goal) 之后添加
。这将仅刷新该单个实体,并从数据库中删除该记录。$em->flush($goal);
;
foreach ($originalGoals as $goal) {
if (false === $experiment->getGoals()->contains($goal)) {
$goal->setExperiment(null);
$em->persist($goal);
$em->remove($goal);
// commit this change to the database
$em->flush($goal);
}
}
关于javascript - 使用嵌入的表单集合保存相关 Doctrine 实体时出现 Symfony SQL 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37076593/