【问题标题】:How to get API-Platform to load related (e.g. Many2One) resources/entities?如何让 API 平台加载相关(例如 Many2One)资源/实体?
【发布时间】:2023-03-06 02:40:01
【问题描述】:

根据documentation,api-platform默认会eager-load相关资源。

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

例如,对于这个实体:

/**
 * @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

/**
 * 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 中写了这个:

    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 的结果确认应用了正确的配置:

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

有趣的是,这似乎与this other user is having相反的麻烦。我希望我有他们的问题。

是什么阻止了这些关系被急切地加载?否则关系会起作用(我可以使用 Doctrine 进行其他查询,或创建自定义序列化组,相关属性将被包含在内)。

【问题讨论】:

  • 并不是每天都有开发人员要求解决其他人的问题。 (我正在寻找解决方案并回来)
  • 您是否尝试在private $channel; 上方添加@ApiProperty(attributes={"fetchEager": true})
  • 您是否真的在每个类声明上方添加* @ApiResource(attributes={"force_eager"=true})
  • 都试过了。没用。但是正如您所见,force_eager 在全局级别启用,在资源或属性级别重新启用它应该不会产生影响。试了下,没有效果。
  • 正如问题所述,默认情况下,您不必为急切加载执行任何操作。这只是一个纯粹的猜测,但请尝试在 eager_loading 下注释掉 enabled、fetch_partial 和 max_joins,以便您的配置与文档匹配。特别是 fetch_partial 可能会导致问题。也可能有助于开始一个新的项目,可能只有两个加入的实体,没有别的。

标签: php symfony doctrine api-platform.com


【解决方案1】:

默认dereferenceable IRIs 用于显示相关关联。 查看执行的语句,您应该不会看到显式的 JOIN 查询,而是相关关联的附加 SELECT 语句。

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

更多详情见https://api-platform.com/docs/core/serialization/#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"
}

【讨论】:

  • 嗯。我误读了文档。我将“默认 EAGER”解释为自动嵌入关系。文档的其他部分表明情况并非如此。我猜不可能将整个实体标记为属于序列化组?
  • 不知道,因为上下文可以改变并且这样做会导致其他影响。
猜你喜欢
  • 1970-01-01
  • 2019-10-20
  • 1970-01-01
  • 1970-01-01
  • 2020-05-14
  • 1970-01-01
  • 1970-01-01
  • 2014-10-23
  • 2019-01-11
相关资源
最近更新 更多