使用相关/嵌入式实体
Posted
技术标签:
【中文标题】使用相关/嵌入式实体【英文标题】:Working with related/embedded entities 【发布时间】:2015-07-19 14:53:10 【问题描述】:Github 原版:https://github.com/zfcampus/zf-apigility-doctrine/issues/215
在代码连接 API 中,三个实体及其各自的服务:地点、产品和位置。
Venue 与 Location 具有 ManyToOne 关系
/**
* @ORM\ManyToOne(targetEntity="Db\Entity\Location", cascade="persist")
* @ORM\JoinColumn(name="location_id", referencedColumnName="id")
*
* @var Db\Entity\Location $location
*/
protected $location;
public function getLocation() ...
public function setLocation($location) ...
Venue 与 Product 有 ManyToMany 关系
/**
* @ORM\ManyToMany(targetEntity="Db\Entity\Product", inversedBy="venues", cascade="persist")
* @ORM\JoinTable(name="products_venues")
**/
protected $products;
public function getProducts() ...
public function setProducts($products) ...
public function addProduct(Product $product)
$product->addVenue($this);
$this->products[] = $product;
return $this;
并且 Product 与 Venue 具有多对多关系
/**
* @ORM\ManyToMany(targetEntity="Db\Entity\Venue", mappedBy="products", cascade="persist")
**/
protected $venues;
public function getVenues() ...
public function setVenues($venues) ...
public function addVenues($venue)
$this->venues[] = $venue;
return $this;
现在,我有两个问题: 1)我可以创建一个新的场地和这样的位置信息:
POST /venues
.
.
.
"location":
"address":"123 Fake Street",
"city":"cityTest",
"country":"CountryTest",
"postalCode":"12345"
并且使用新的位置注册表创建了一个新的场地,当我获取刚刚创建的场地时,可以看到两者正确链接。 当我获得刚刚创建的 Venue Id 时,我在 _embedded 对象中看到了具有其 id 的位置对象,但是如果我需要编辑该地址并将 Venue 1 与位置 2 而不是最初创建的位置 1 链接怎么办?
其次,我无法在创建最后一个的同一 POST 调用中通过产品创建并将产品与场所链接来重现此过程。 Nether 想出了如何将现有产品添加到特定 Venue 的 Products 集合中。 那么,哪种方式更合适呢? (“1 个调用创建并将它们全部链接”与“多个创建调用 + 补丁调用将它们链接在一起”)我需要什么才能让它们在 Apigility + Doctrine 中发生?
7 月 20 日更新:
哇!!这是一个有趣的发现。为了更新特定场地的位置,我必须在场地服务中添加一个新的“位置”字段。
有了这个,我可以将位置对象作为额外属性与 /Venues 所需的属性一起发布。或者通过添加 location: "id" : 123
来指定 id(这也适用于 PATCH,这是我一直在寻找的。太棒了!)。但是我意识到没有实际的验证来检查具有指定 ID 的位置是否确实存在。如果没有找到,则新场地将链接到“空”位置。 :皱眉:
因此,在那之后,我看到了其中包含的 Apigility Doctrine 验证器。 :smile: ZF\Apigility\Doctrine\Server\Validator\ObjectExists
验证我发送的对象确实存在于数据库中。耶耶耶!!我所要做的就是将其添加为“位置”字段的验证器,并根据https://github.com/doctrine/DoctrineModule/blob/master/docs/validator.md 指定两个选项
entity_class = Db\Entity\Location
所以验证器知道我要验证的实体是什么,fields = id
就像一个验证标准。
现在,当我尝试发布场地时,我需要使用"location": "id":123
指定位置。这也适用于 PATCH。当找不到具有指定 ID 的位置时,我会收到一条很好的错误消息,这很好。如果没有提供 ID,则为 500(我猜有时会出现一个问题......)。
现在,我一直在尝试寻找如何将对象添加到实体集合中。 (例如,将产品添加到特定场所)。我尝试将“产品”字段添加到场地服务,但没有奏效。我一直在没有任何产品的情况下获得场地。 这就是我试图修补的方式:
PATCH /venues/1
...
"products":[
"id": 5
]
...
对此有什么想法吗?
【问题讨论】:
【参考方案1】:在 RESTful API 中进行原子 CRUD 操作通常是一个好主意。
在您的情况下,这意味着最好通过名为 POST|GET|DELETE|PUT /location
的单独 API 资源对您的 Location 实体进行 CRUD。
然后 API 客户端必须首先检索或创建一个位置,然后才发布地点。
示例:
第 1 步。 创建或检索位置。
POST /location
"address":"123 Fake Street",
"city":"cityTest",
"country":"CountryTest",
"postalCode":"12345"
或
GET /location/somefilter
第 2 步。 创建场地
POST /venues
...
"location": 2 //the location id
...
【讨论】:
是的,REST API 像这样工作很有意义,但在这种情况下,我在我的项目中使用 Apigility 和 Doctrine 模块 (zf-apigility-doctrine),我可以找不到像那样实现它的方法。我可以同时创建地点和地址,还可以通过使用地点字段 + 位置执行 POST /venues 来链接它们。我只是找不到执行 PATCH /venues/2 "location":123 的方法有道理吗? 您的PATCH /venues/id
端点是否有location
字段?
在我看来,一旦你在服务中创建了一个/location
端点,然后将一个location
字段添加到你的/venues
端点,一切都应该工作。 注意:不要忘记删除旧的 location
字段,因为它需要 array
而不是整数,
我找到了如何使它适用于location
(一对一关系)并更新了原始问题。现在我正在处理特定场地的products
集合。 @TomHAnderson 在我创建的回购问题中评论:github.com/zfcampus/zf-apigility-doctrine/issues/215以上是关于使用相关/嵌入式实体的主要内容,如果未能解决你的问题,请参考以下文章