首页 > 解决方案 > Symfony 表单集合:如何防止在 EntityManager->flush() 上重复插入?

问题描述

我有以下数据模型:

MainEntity.php

<?php declare(strict_type=1);

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class MainEntity
{
  // $id, etc...

  /**
   * @ORM\OneToMany(
   *   targetEntity="App\Entity\RelationEntity",
   *   mappedBy="mainEntity",
   *   cascade={"persist", "merge", "remove"},
   *   orphanRemoval=true
   * )
   */
  protected Collection $sideRelations;

  // getSideRelations(), setSideRelations($relations), addSideRelation($sideRelation), removeSideRelation($sideRelation)...
}

RelationEntity.php

<?php declare(strict_types=1);

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(
 *   name="main_side_relation",
 *   uniqueConstraints={
 *     @ORM\UniqueConstraint(name="id_pair", columns={"main_entity_id", "side_entity_id"})
 *   }
 * )
 */
class RelationEntity
{
  // $id, etc...

  /**
   * @ORM\Column(type="integer", nullable=false)
   */
  protected ?int $relationValue;
  
  /**
   * @ORM\ManyToOne(targetEntity="App\Entity\MainEntity", inversedBy="sideRelations")
   * @ORM\JoinColumn(name="main_entity_id", referencedColumnName="id")
   */
  protected MainEntity $mainEntity;

  /**
   * @ORM\ManyToOne(targetEntity="App\Entity\SideEntity", inversedBy="mainRelations")
   * @ORM\JoinColumn(name="side_entity_id", referencedColumnName="id")
   */
  protected SideEntity $sideEntity;

  // getRelationValue(), setRelationValue($relationValue), getMainEntity(), setMainEntity($mainEntity), getSideEntity(), setSideEntity($sideEntity)...
}

SideEntity.php

<?php declare(strict_types=1);

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class SideEntity
{
   // $id, etc...
   
   /**
    * @ORM\OneToMany(
    *   targetEntity="App\Entity\RelationEntity",
    *   mappedBy="sideEntity",
    *   cascade={"persist", "merge", "remove"},
    *   orphanRemoval=true
    * )
    */
   protected Collection $mainRelations;

   // getMainRelations(), setMainRelations($mainRelations), addMainRelation($mainRelation), removeMainRelation($mainRelation)...

我已经扩展了现有的 Symfony 表单类以适应数据模型。

RelationEntityType.php

<?php declare(strict_types=1);

namespace App\Form;

class RelationEntityType extends AbstractType
{
   public function buildForm(FormBuilderInterface $builder, array $options): void
   {
      $builder
        ->add('relationValue', HiddenType::class)
        ->add('mainEntity', HiddenType::class)
        ->add('sideEntity', HiddenType::class)
      ;
      // Add Transformers to switch between Entity and database ID for input value
   }

   public function configureOptions(OptionsResolverInterface $resolver): void
   {
      $resolver->setDefaults(['data_class' => RelationEntity::class]);
   }
}

MainEntityType.php

<?php declare(strict_types=1);

namespace App\Form;

class MainEntityType extends AbstractType
{
   public function buildForm(FormBuilderInterface $builder, array $options): void
   {
      // ...
      $builder->add('sideRelations', CollectionType::class, [
        'required' => false,
        'by_reference' => false,
        'entry_type' => RelationEntity::class,
        'allow_add' => true,
        'allow_delete' => true,
        'delete_empty' => true
      ]);
   }

   public function configureOptions(OptionsResolverInterface $resolver): void
   {
      $resolver->setDefaults(['data_class' => MainEntity::class]);
   }
}

提交工作不像预期的那样,因为通过使用by_reference我明确地删除并重新添加现有的未更改的集合条目,但是当省略该选项时它会隐式发生。

在这两种情况下,UnitOfWork都填充了对现有集合条目的插入查询(并且由于唯一约束而引发错误)。我不想那样。

Symfony 的表单集合配置文档没有提供关于如何防止集合变得“脏”的有价值信息,尽管它们的条目在技术上没有改变。

我究竟如何避免覆盖未更改的现有集合条目?

(如有必要,我可以提供 MWE 的剩余代码)

标签: phpsymfonydoctrine-ormsymfony4symfony-forms

解决方案


推荐阅读