Doctrine / Symfony / CollectionType:如何使用双向一对多关系将新项目保留在集合中?

时间:2017-11-02 19:32:13

标签: forms symfony doctrine

我有两个具有双向一对多关系的实体:

class EntityA {
  /**
   * @ORM\ManyToOne(targetEntity="EntityB", inversedBy="entitiesA")
   * @ORM\JoinColumn(nullable=false)
   */
  protected $entityB;

  //...

  public function setEntityB(EntityB $entity = null)
  {
    $entity->addEntityA($this);

    $this->entityB = $entity;
  }

  //...
}

class EntityB {
  /**
   * @ORM\OneToMany(targetEntity="EntityA", mappedBy="entityB")
   */
  protected $entitiesA;

  //...

  public function addEntityA(EntityA $entity)
  {
    if(!$this->entitiesA->contains($entity)){
      $this->entitiesA[] = $entity;

      //Make link
      $entity->setEntityB($this);
    }
  }
  //...
}

对于表单类型,我使用CollectionType:

->add('entitiesA', CollectionType::class, array(
    'entry_type'   => EntityBType::class,
    'allow_add'    => true,
    'allow_delete' => true
  ))

所有事情都可以运作,除了1:我认为集合中的新项目没有链接到EntityA。也许我忘记了一个过程...我有以下错误:

  

通过“EntityB#entitiesA”关系找到了一个新实体,该关系未配置为对实体进行级联持久化操作:EntityA @ 000000006cf0842c000000004d5dcfd9。要解决此问题:在此未知实体上显式调用EntityManager#persist()或在映射中配置级联持久保存此关联,例如@ManyToOne(..,cascade = {“persist”})。如果你无法找出哪个实体导致问题,请实现'EntityA #__ toString()'以获得线索。

当我像这样添加cascade={"persist"}时:

class EntityB {
  /**
   * @ORM\ManyToOne(targetEntity="EntityA", mappedBy="entityB", cascade={"persist"})
   */
  protected $entitiesA;

我有以下错误:

  

SQLSTATE [23000]:违反完整性约束:1048 Le champ'entityB_id'nepeutêtrevide(null)

您有什么想法解决我的问题吗?

非常感谢你。

3 个答案:

答案 0 :(得分:0)

在我的应用程序中,我有双向关系,如下所示:

业主方:

/**
 * Many users can have many types
 * @var \AppBundle\Entity\TypeOfUser
 *
 * @ORM\ManyToOne(targetEntity="AppBundle\Entity\TypeOfUser", inversedBy="type")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="type_user_id", referencedColumnName="id")
 * })
 */
protected $typeOfUser;

反面

/**
 * A type of user can belong to Many Users
 * @var \Doctrine\Common\Collections\ArrayCollection
 *
 * @ORM\OneToMany(targetEntity="User", mappedBy="typeOfUser")
 */
protected $type;

答案 1 :(得分:0)

感谢@jjoselon的帮助。我尝试添加referencedColumnName="id",但我再次SQLSTATE[23000]: Integrity constraint violation

然而,我找到了一个解决方案但不干净。

  

我在EntityB中添加了一个新字段,但没有存储在DB中。

class EntityB {
  /**
   * @ORM\ManyToOne(targetEntity="EntityA", mappedBy="entityB")
   */
  protected $entitiesA;
  protected $entitiesA_new;

$entitiesA_new将用于新对象,$entitiesA用于现有对象

  

在表单类型中,我添加非映射字段:

->add('entitiesA_new', CollectionType::class, array(
    'entry_type'   => EntityBType::class,
    'allow_add'    => true,
    'allow_delete' => true,
    'entry_options'  => array(
      "mapped" => false
    )))
  ))
  

在控制器中,在表单验证之后,我从请求中解析entitiesA_new的所有字段并添加新对象。

$forms_raw = $request->request->get('block_prefix');
if($forms_raw  && isset($forms_raw["entitiesA_new"]))
{
  foreach ($forms_raw["entitiesA_new"] as $entityA_raw)
  {
    $entityA = new EntityA();

    $entityA->setName($entityA_raw["name"]);
    $entityA->setOption($entityA_raw["option"]);
    $entityA->setCategory($entityA_raw["category"]);
    $entityA->setEntityB($entityB);

    $em->persist($entityA);
  }
}

所以我认为有一个更好的解决方案,但就目前而言,我只有那个。

答案 2 :(得分:0)

  

SQLSTATE [23000]:违反完整性约束:1048 Le champ'entityB_id'ne peutêtrevide(null)

为避免这种情况,您必须先持久化并刷新entryB,然后再持久化并刷新entryA