我正在尝试通过主实体更新相关实体。例如,我有产品和优惠。我做一个
POST
到/products
{
"name": "sample product",
"offers": [
{
"description": "sample offer"
}
]
}
我得到了这个回应
{
"@context": "/contexts/Product",
"@id": "/products/1",
"@type": "Product",
"name": "sample product",
"offers": [
{
"@id": "/offers/1",
"@type": "https://schema.org/Offer",
"description": "sample offer"
}
]
}
到目前为止,一切都很好。现在,我想在
PUT
执行
/products/1
操作
{
"name": "product updated",
"offers": [
{
"@id": "/offers/1",
"description": "offer updated"
}
]
}
并收到此错误
执行查询时发生异常:SQLSTATE[23000]: 违反完整性约束:1048 列“product_id”不能 空
如果我从 Offer.php 中删除
#[ORM\JoinColumn(nullable:false)]
,它可以工作,但是 product_id
设置为 null
(行的其余部分保留)并插入新行。
我想要的是更新行(只需更新描述字段)。这可能吗?
我正在使用 https://api-platform.com/docs/core/getting-started/#mapping-the-entities 给出的示例,并进行一些小的修改(请参阅评论)
我的代码是:
产品.php
<?php
// api/src/Entity/Product.php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Serializer\Annotation\Groups; //ADDED THIS
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity]
#[ApiResource(
normalizationContext: ["groups" => ["products"]],
denormalizationContext: ["groups" => ["products"]],
)]
class Product // The class name will be used to name exposed resources
{
#[ORM\Id, ORM\Column, ORM\GeneratedValue]
private ?int $id = null;
/**
* A name property - this description will be available in the API documentation too.
*
*/
#[ORM\Column]
#[Assert\NotBlank]
#[Groups(["products"])] //ADDED THIS
public string $name = '';
// Notice the "cascade" option below, this is mandatory if you want Doctrine to automatically persist the related entity
/**
* @var Offer[]|ArrayCollection
*
*/
#[ORM\OneToMany(targetEntity: Offer::class, mappedBy: 'product', cascade: ['persist'])]
#[Groups(["products"])] //ADDED THIS
public iterable $offers;
public function __construct()
{
$this->offers = new ArrayCollection(); // Initialize $offers as a Doctrine collection
}
public function getId(): ?int
{
return $this->id;
}
// Adding both an adder and a remover as well as updating the reverse relation is mandatory
// if you want Doctrine to automatically update and persist (thanks to the "cascade" option) the related entity
public function addOffer(Offer $offer): void
{
$offer->product = $this;
$this->offers->add($offer);
}
public function removeOffer(Offer $offer): void
{
$offer->product = null;
$this->offers->removeElement($offer);
}
// ...
//ADDED THIS SET AND GET
public function setName($name)
{
$this->name = $name;
return $this;
}
public function getName()
{
return $this->name;
}
}
Offer.php
<?php
// api/src/Entity/Offer.php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups; //ADDED THIS
use Symfony\Component\Validator\Constraints as Assert;
/**
* An offer from my shop - this description will be automatically extracted from the PHPDoc to document the API.
*
*/
#[ORM\Entity]
#[ApiResource(types: ['https://schema.org/Offer'])]
class Offer
{
#[ORM\Id, ORM\Column, ORM\GeneratedValue]
private ?int $id = null;
#[ORM\Column(type: 'text')]
#[Groups(["products"])] //ADDED THIS
public string $description = '';
#[ORM\Column]
#[Assert\Range(minMessage: 'The price must be superior to 0.', min: 0)]
public float $price = 1.0; //MODIFIED THIS
#[ORM\ManyToOne(targetEntity: Product::class, inversedBy: 'offers')]
#[ORM\JoinColumn(nullable:false)] //ADDED THIS
public ?Product $product = null;
public function getId(): ?int
{
return $this->id;
}
//ADDED THIS SET AND GET
public function setDescription($description)
{
$this->description = $description;
return $this;
}
public function getDescription()
{
return $this->description;
}
}
尝试使用
PATCH
方法而不是 PUT
并将 Content-Type 标头设置为 application/merge-patch+json
PUT
方法要求填写每个已知属性,否则会认为它已被删除,因此将其设置为null
。这就是为什么您的 id
设置为 null
。
PATCH
方法仅编辑您的json
内的属性。
不要忘记这样做:https://api-platform.com/docs/core/content-negotiation/#configuring-patch-formats
您可以阅读:https://rapidapi.com/blog/put-vs-patch/ 以获得正确的解释。这是我们都犯过的错误哈哈
嗯,显然这就像做一样简单
{
"name": "product updated",
"offers": [
{
"id": "/offers/1",
"description": "offer updated"
}
]
}
注意
id
没有 @
!!!
更新 2024:在版本 3.2.10 中,这不起作用