Symfony2条令试图插入记录两次?比赛条件?

Symfony2条令试图插入记录两次?比赛条件?,symfony,doctrine,Symfony,Doctrine,我们在Symfony2中构建了一个调查构建应用程序(想想survey Monkey或Google表单)。当一名公众访问调查时,使用Symfony的Form Builder动态生成各种问题,并使用Doctrine保存其答案。目前,我们每天平均收集1000份完成的调查,没有任何问题,但是,我们时不时会收到一个条令\DBAL例外 问题的每个答案都保存在一个表中,该表有一个唯一的键,由填写调查的人的ID和他们回答的问题的ID组成。有时,当条令试图插入他们的答案时,这个键被违反,查询失败。正如我提到的,这

我们在Symfony2中构建了一个调查构建应用程序(想想survey Monkey或Google表单)。当一名公众访问调查时,使用Symfony的Form Builder动态生成各种问题,并使用Doctrine保存其答案。目前,我们每天平均收集1000份完成的调查,没有任何问题,但是,我们时不时会收到一个
条令\DBAL
例外

问题的每个答案都保存在一个表中,该表有一个唯一的键,由填写调查的人的ID和他们回答的问题的ID组成。有时,当条令试图插入他们的答案时,这个键被违反,查询失败。正如我提到的,这种情况很少发生,我们无法在测试环境中复制它

所有Symfony表单都是动态构建的,这使得事情变得更加复杂。下面是实际执行表单数据持久化的代码

public function save(\Symfony\Component\Form\Form $form, \Our\Namspace\Entity\Participant $participant)
{
    /**
    * $surveyReponse
    *
    * @var \Our\Namespace\Entity\SurveyResponse
    */
    foreach ($form->getData() as $surveyResponseKey => $surveyResponse) {

        $subQuestionId = $this->getQuestionIdFromSurveyResponseKey($surveyResponseKey);
        $subQuestion = $this->getSubQuestionSettingsBySubQuestionId($subQuestionId);

        if ($surveyResponse) {
            $surveyResponse->setParticipant($participant)->setSubQuestion($subQuestion);
            $participant->addResponse($surveyResponse);
            $this->em->persist($surveyResponse);

        }

        $this->em->flush();

    }

    return true;
}
您可以看到,我们在表单数据中对问题(在我们的域中称为子问题)的ID进行编码,以获取(子)问题实体,然后在持久化之前在SurveyResponse对象上设置参与者和子问题
$this->em只是条令实体管理器

如果没有看到所有的代码,可能任何人都很难弄清楚发生了什么,但是如果任何人过去有过类似的问题,也许他们可以提供一些建议

我们可以而且应该将persist和flush操作包装在try/catch块中,然后处理异常,但我们真的很想知道为什么会发生这种情况

SurveyResponse实体的相关位如下所示

class SurveyResponse implements SurveyAwareInterface
{
    /**
     * id of the response.
     *
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    protected $id;

    /**
     * the subQuestion to which the response refers.
     *
     * @var SurveySubQuestion
     *
     * @ORM\ManyToOne(targetEntity="\Our\Namspace\Entity\SurveySubQuestion", inversedBy="surveyResponses")
     * @ORM\JoinColumn(name="sub_question_id", referencedColumnName="id")
     */
    protected $subQuestion;

    /**
     * the participant.
     *
     * @var AbstractParticipant
     *
     * @ORM\ManyToOne(targetEntity="Our\Namespace\Entity\Participant", inversedBy="responses")
     * @ORM\JoinColumn(name="participant_id", referencedColumnName="id", onDelete="CASCADE")
     */
    protected $participant;
实体中有这个注释

 * @ORM\Table(name="survey_response",
 *      uniqueConstraints=  @ORM\UniqueConstraint(
 *     name="participant_response", columns={"participant_id", "sub_question_id"})})
 *

注意:你不应该
flush()
在foreach里面。@PawełMikołajczuk为什么不呢?因为当他知道要插入/更新的所有资源时,这是一项消耗资源的任务,而且条令更有效。对于许多插入,您可以使用批处理:是的,我们知道我们不应该在循环中刷新,但是除非我们这样做,否则将数据插入到数据库中不会正常工作。为什么它不起作用是另一个问题!