如何让 API 平台加载相关(例如 Many2One)资源/实体? [英] How to get API-Platform to load related (e.g. Many2One) resources/entities?

查看:39
本文介绍了如何让 API 平台加载相关(例如 Many2One)资源/实体?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据文档,api-平台默认会预先加载相关资源.

According to the documentation, api-platform will eager-load related resources by default.

但是在默认配置下,我对具有关系的资源(主要是典型的Many2One 关系)的所有查询都使用对象 IRI 而不是序列化对象填充这些属性.

But on the default configuration, all my queries to resources with relations (mostly with typical Many2One relationships) populate these properties with the object IRI instead of the serialized object.

例如,对于这个实体:

/**
 * @ORM\Entity(repositoryClass="App\Repository\BoostLeadContactActionRepository")
 * @ORM\Table(name="BoostLeadContactActions")
 */
class BoostLeadContactAction {

    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\BoostLead", inversedBy="contacts")
     * @ORM\JoinColumn(nullable=false)
     */
    private $boostLead;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\ContactChannel", fetch="EAGER")
     * @ORM\JoinColumn(nullable=false, referencedColumnName="Id")
     */
    private $channel;

    // getters/setters/extra properties removed for brevity
}

然后我们就有了对应的ContactChannel:

Then we have the corresponding ContactChannel:

/**
 * ContactChannel
 *
 * @ORM\Table(name="ContactChannels")
 * @ORM\Entity
 */
class ContactChannel {

    /**
     * @var int
     *
     * @ORM\Column(name="Id", type="smallint", nullable=false, options={"unsigned"=true})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="Name", type="string", length=64, nullable=false)
     */
    private $name = '';
}

我已经在关系上设置了 fetch="EAGER" 即使理论上不需要.我的配置是默认的,但以防万一我真的在我的 api_platform.yaml 中写了这个:

I've set up fetch="EAGER" on the relationship even if in theory is not needed. My configuration is the default, but just in case I actually wrote this in my api_platform.yaml:

    eager_loading:
        # To enable or disable eager loading.
        enabled: true

        # Fetch only partial data according to serialization groups.
        # If enabled, Doctrine ORM entities will not work as expected if any of the other fields are used.
        fetch_partial: false

        # Max number of joined relations before EagerLoading throws a RuntimeException.
        max_joins: 30

        # Force join on every relation.
        # If disabled, it will only join relations having the EAGER fetch mode.
        force_eager: true

debug:config api_platform 的结果确认应用了正确的配置:

The result of debug:config api_platform confirms the correct configuration is applied:

Current configuration for extension with alias "api_platform"
=============================================================

api_platform:
    title: FooBar API
    description: 'FooBar API, only for authenticated use'
    version: 0.8.0
    name_converter: null
    path_segment_name_generator: api_platform.path_segment_name_generator.underscore
    eager_loading:
        enabled: true
        fetch_partial: false
        max_joins: 30
        force_eager: true

然而结果将类似于:

{
  "@context": "/api/contexts/BoostLeadContactAction",
  "@id": "/api/boost_lead_contact_actions/9",
  "@type": "BoostLeadContactAction",
  "id": 9,
  "boostLead": "/api/boost_leads/30",
  "channel": "/api/contact_channels/1",
  "direction": "outgoing",
  "successful": true,
  "type": "/api/lead_contact_attempt_reasons/1",
  "notes": "2",
  "createdAt": "2019-05-16T10:27:33+00:00",
  "updatedAt": "2019-05-16T10:27:33+00:00"
}

"boostLead", "channel" 和 "type" 应该是实际实体,急切加载,但只返回 IRI.我确认执行的 SQL 查询不包含任何类型的 join.

"boostLead", "channel" and "type" should be actual entities, eagerly loaded, but only IRIs are returned instead. I confirmed that the SQL query performed does not include any kind of join.

有趣的是,这似乎与这个其他用户遇到的问题相反.我希望我有他们的问题.

Funnily enough, it seems to be the opposite trouble than this other user is having. I wish I had their problems.

什么会阻止这些关系急切地加载?关系以其他方式工作(我可以使用 Doctrine 执行其他查询,或创建自定义序列化组并包含相关属性).

What could be preventing these relationships to be loaded eagerly? The relationships work otherwise (I can do other queries with Doctrine, or create custom serialization groups and the related properties will be included).

推荐答案

默认情况下 可取消引用的 IRI 用于显示相关的关联.查看执行的语句,您不应看到显式的 JOIN 查询,而是相关关联的附加 SELECT 语句.

By default dereferenceable IRIs are used to display the related associations. Looking at the executed statements you should not see an explicit JOIN query but rather additional SELECT statements for the related associations.

如果您想要关联对象的 JSON 表示.您需要为相关关联中的所需属性指定 Serialization @Groups.这将导致 SELECT 语句添加一个 JOIN 以检索要序列化的相关数据.

If you are wanting the JSON representation of the associated object. You need to specify the Serialization @Groups for the desired properties in the related association. This will cause the SELECT statement to add in a JOIN to retrieve the related data to be serialized.

更多详情请参见https://api-platform.com/文档/核心/序列化/#embedding-relations

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * @ApiResource(normalizationContext={ "groups": {"boost"} })
 * @ORM\Entity()
 * @ORM\Table(name="BoostLeadContactActions")
 */
class BoostLeadContactAction {

    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     * @Groups({"boost"})
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\BoostLead", inversedBy="contacts")
     * @ORM\JoinColumn(nullable=false)
     * @Groups({"boost"})
     */
    private $boostLead;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\ContactChannel", fetch="EAGER")
     * @ORM\JoinColumn(nullable=false, referencedColumnName="Id")
     * @Groups({"boost"})
     */
    private $channel;

    // getters/setters/extra properties removed for brevity
}

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * @ApiResource()
 * @ORM\Table(name="ContactChannels")
 * @ORM\Entity
 */
class ContactChannel {

    /**
     * @var int
     * @ORM\Column(name="Id", type="smallint", nullable=false, options={"unsigned"=true})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     * @Groups({"boost"})
     */
    private $id;

    /**
     * @var string
     * @ORM\Column(name="Name", type="string", length=64, nullable=false)
     * @Groups({"boost"})
     */
    private $name = '';
}

这将导致检索规范化值

{
  "@context": "/api/contexts/BoostLeadContactAction",
  "@id": "/api/boost_lead_contact_actions/9",
  "@type": "BoostLeadContactAction",
  "id": 9,
  "boostLead": "/api/boost_leads/30",
  "channel": {
      "@id": "/api/contact_channels/1",
      "@type": "ContactChannel",
      "id": "1",
      "name": "Test"
   },
  "direction": "outgoing",
  "successful": true,
  "type": "/api/lead_contact_attempt_reasons/1",
  "notes": "2",
  "createdAt": "2019-05-16T10:27:33+00:00",
  "updatedAt": "2019-05-16T10:27:33+00:00"
}

这篇关于如何让 API 平台加载相关(例如 Many2One)资源/实体?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆