无法在 API POST 调用中包含实体集合

Posted

技术标签:

【中文标题】无法在 API POST 调用中包含实体集合【英文标题】:Unable to include Collection of Entities inside API POST-call 【发布时间】:2021-02-12 01:32:58 【问题描述】:

有问题的错误:

Entity of type App\Entity\Nutt is missing an assigned ID for field  'squirrel'.
The identifier generation strategy for this entity requires the ID field to be populated before EntityManager#persist() is called.
If you want automatically generated identifiers instead you need to adjust the metadata mapping accordingly.

我完全能够调用 api POST 将 Squirrel 实体添加到数据库中。 并且使用这个 Squirrel 的 id,我可以对 Nutt 实体执行 POST 调用,结果是 Nutt 表中正确相关的记录。

我似乎无法开始工作的是,允许 Squirrel api 调用包含我想在同一个 api 调用中插入的相关 Nutts 集合。

我做错了什么?

JSON 调用:


    "name": "Jake",
    "nutts": [
        
            "size": 10,
            "color": "blue"
        
    ]

实体松鼠

/**
 * @ORM\Entity
 * @ORM\Table(name="squirrel")
 */
class Squirrel 
  /**
   * @ORM\Column(type="integer")
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="AUTO")
   */
  private $id;
  /**
   * @ORM\Column(type="string", length=100)
   * @Assert\NotBlank()
   *
   */
  private $name;
  /**
   * @ORM\OneToMany(targetEntity="App\Entity\Nutt", mappedBy="squirrel", cascade="persist", "remove")
   */
  private $nutts;
  public function __construct()
  
    $this->nutts = new \Doctrine\Common\Collections\ArrayCollection();
  
  public function getId()
  
    return $this->id;
  
  public function setId($id)
  
    $this->id = $id;
  
  public function getName()
  
    return $this->name;
  
  public function setName($name)
  
    $this->name = $name;
  
  public function getNutts(): ?Collection
  
    return $this->nutts;
  
  public function setNutts(Collection $nutts)
  
    foreach ($nutts as $nutt)
    
      $this->nutts->add($nutt);
    
  
  public function addNutt(Nutt $nutt): Squirrel
  
    $this->nutts->add($nutt);
    return $this;
  

实体松鼠已更新。 setNutts 已更改为:

public function setNutts(Collection $nutts)

  foreach ($nutts as $nutt)
  
    $nutt->setSquirrel($this);
    $this->nutts->add($nutt);
  

实体坚果

/**
 * @ORM\Entity
 * @ORM\Table(name="nutt")
 */
class Nutt 
  /**
   * @ORM\ManyToOne(targetEntity="App\Entity\Squirrel", inversedBy="nutts")
   * @ORM\Id
   */
  private $squirrel;
  /**
   * @ORM\Column(type="integer")
   * @ORM\Id
   */
  private $size;
  /**
   * @ORM\Column(type="text")
   * @Assert\NotBlank()
   */
  private $color;
  /**
   * @return Squirrel|null
   */
  public function getSquirrel(): ?Squirrel
  
    return $this->squirrel;
  
  /**
   * @param Squirrel|null $squirrel
   * @return $this
   */
  public function setSquirrel(?Squirrel $squirrel): self
  
    $this->squirrel = $squirrel;
    return $this;
  
  //getters and setters for the rest

Entity Nutt 已更新。 属性 $squirrel 已删除其 id 符号,因为它是一个关系:

/**
 * @ORM\ManyToOne(targetEntity="App\Entity\Squirrel", inversedBy="nutts")
 */
private $squirrel;

松鼠控制器

/**
 * Squirrel controller.
 * @Route("/api", name="api_")
 */
class SquirrelController extends AbstractFOSRestController

  /**
   * Lists all Squirrels.
   * @Rest\Get("/squirrels")
   * @return Response
   */
  public function getSquirrelAction()
  
    $repository = $this->getDoctrine()->getRepository(Squirrel::class);
    $squirrels = $repository->findall();
    return $this->handleView($this->view($squirrels));
  
  /**
   * Create Squirrel.
   * @Rest\Post("/squirrel")
   *
   * @return Response
   */
  public function postSquirrelAction(Request $request)
  
    $squirrel = new Squirrel();
    $form = $this->createForm(SquirrelType::class, $squirrel);
    $data = json_decode($request->getContent(), true);
    $form->submit($data);
    if ($form->isSubmitted() && $form->isValid()) 
      $em = $this->getDoctrine()->getManager();
      $em->persist($squirrel);
      $em->flush();
      return $this->handleView($this->view(['status' => 'ok'], Response::HTTP_CREATED));
    
    return $this->handleView($this->view($form->getErrors()));
  

还有我目前的重点 松鼠形态

class SquirrelType extends AbstractType

  public function buildForm(FormBuilderInterface $builder, array $options)
  
    $builder
      ->add('name')
      ->add(
        'nutts',
        CollectionType::class, [
          'entry_type' => NuttType::class,
          'allow_add' => true,
          'by_reference' => false
        ])
      ->add('save', SubmitType::class);
  
  public function configureOptions(OptionsResolver $resolver)
  
    $resolver->setDefaults(array(
      'data_class' => Squirrel::class,
      'csrf_protection' => false
    ));
  

有一个疯狂的形式,但它工作正常。

@mel 在评论中解决了问题

【问题讨论】:

@msg 谢谢,帮了大忙。 Squirrel 和 Nutt 都被添加了,但现在不相关了。您对此也有建议吗?如果您将建议与您的评论一起添加到单独的答案中,我可以在该问题上签字。 @msg 我想你现在只需要添加你的评论作为答案。我发现我没有将松鼠添加到 Squirrel::setNutts() 的 foreach 中。 foreach ($nutts as $nutt) $nutt->setSquirrel($this); $this->nutts->add($nutt); 【参考方案1】:

Id annotation 将该列声明为主键,因此它成为强制性的。但在这种情况下不需要它,因为squirrel 是一个关系。

错误本身也暗示保存实体时该字段为空,因此没有调用setSquirrel

您也可以从size 中删除注释。

【讨论】:

如果 Nutt 与松鼠没有关系就无法存在怎么办? @vernes 您可以通过注释控制关系是否为nullable

以上是关于无法在 API POST 调用中包含实体集合的主要内容,如果未能解决你的问题,请参考以下文章

如何在实体框架中包含排序的导航属性[重复]

在实体框架查询中包含多个

是否可以在约束中包含 Core Data 实体类型?

Hibernate - 是不是需要在父实体中包含 Set 和 OneToMany 注释?

JSON API实体是否应包含其父级的关系?

Android Room Persistence Library - 如何查找 ID 列表中包含 ID 的实体?