概述
我们超图的基础已经完成。我们已经将 FlyBy 的模式拆分为位置数据和评论数据,并且我们已经实现子图,它们只定义自己涉及的类型。
重新审视我们的模式约定清单,我们仍然有三个字段我们还不知道如何实现:
Location.reviewsForLocation
及Location.overallRating
:这两者都是Location
类型中的 字段,不过我们决定将这两者归属于reviews
子图。Review.location
:这是Review
类型(位于reviews
子图)中的 字段,可是该 字段的返回类型为Location
,而这一类型则是在locations
子图中定义的。
要实现这些 字段,我们必须向开发人员工具包中添加一个新工具: 实体!
在这一课中,我们将
- 了解什么是 实体,以及它的用途
- 了解如何定义 实体
- 了解 路由器在 子图间传输数据时如何表示实体
什么是实体?
实体是一种分布在多个 子图中的 对象类型,包含的 字段在此类对象类型中呈现。
这意味着,我们可以定义一个类型,该类型 既存在于我们 子图中,也可以对这些子图的 字段进行独立解析。
在 FlyBy 中,我们希望我们的评论包括所评论的位置。我们的 Location
类型需要同时用于 两个子图,因此,我们将把 Location
类型转变为 实体。
一个 子图(它定义了一个 实体)能够完成以下一个或两个操作:
- 引用 实体
- 向 实体贡献 字段
引用实体
引用 实体意味着使用它作为其他 字段的返回类型(该字段在 子图内定义)。
例如,在 reviews
子图中,我们可以在 Review
类型中添加一个 location
字段,该字段会引用 Location
实体作为其返回类型。
向实体贡献字段
为实体添加字段表示一个子图谱为实体添加特定于该子图谱专有问题的字段。
例如,Location
实体将为name
、description
和photo
包含字段,它们都存在于locations
子图谱中。换句话说,locations
子图谱 将这些字段添加到Location
实体中。。
,而reviews
子图谱将为Location
实体添加两个特定于评论的字段:reviewsForLocation
和overallRating
。。
如何创建实体
为在子图谱模式中将对象转换成实体,我们需要做两件事:
- 定义主键
- 定义引用解析器
定义主键
一个实体的主键是字段(或字段),它们可以唯一标识该实体在子图中的一个实例。 路由器使用主键从多个子图收集数据,并将其与单个实体实例相关联。
例如,一个位置实体的主键是它的 ID。 路由器使用该 ID 收集有关特定位置实例的数据,例如 ID 为“loc-1”的位置。
在我们的每个子图模式中,我们可以通过添加@key
指令在类型的名称后,为一个实体定义一个主键。
@key
指令需要一个称为fields
的属性,我们将把它设置字段是我们想要用作实体的主键。
type EntityType @key(fields: "id") {id: ID!}
定义引用解析器函数
每个 子图,为 实体贡献 字段,还需要为此实体定义一个特殊 解析器函数,称为 引用解析器。 路由器使用引用 解析器直接访问 实体 字段,每个 子图都应为其做出贡献。
每个引用 解析器的名称如下: __resolveReference
。我们为每个 实体的引用 解析器定义与该类型的所有 字段解析器一起使用。
__resolveReference
函数的签名与其他 解析器函数稍微不同。 __resolveReference
它不是像往常一样使用四个 参数,而是仅使用三个参数:
reference
: 实体由 路由器传入的表示对象。它会告诉 子图正在请求哪个实体实例。我们将在下面的部分中介绍实体表示是什么。context
:共享于所有 解析器的对象。(这与普通解析器中相同,但请注意,按照惯例,我们将此__resolveReference
参数称为context
,而不是其他 解析器中的contextValue
!)info
:包含有关 操作执行状态的信息,就像普通 解析器一样。我们不会使用太多 此参数。
让我们先关注这个第一个 参数, reference
,并详细了解 实体表述。
什么是实体表述?
一个 实体表述是 路由器用来表示一个特定 实体实例的对象。一个表述总是包括该 类型名的 实体和特定实例的 @key
字段。
__typename
字段:此 字段存在于所有 GraphQL类型上,并且自动存在。它始终以字符串的形式返回其包含类型的名称。例如,Location.__typename
返回“Location”。@key
字段:一个 子图 可以用它来识别 实体 的实例的一对键值。例如,如果我们使用"id" 字段 作为 实体Location
的主键,那么我们的实体表示将包括一个"id"属性,其值类似于"loc-2"。
一个 实体 的位置表示可能如下所示:
{"__typename": "Location","id": "loc-2"}
您可以将 实体 表示视为护照,路由器 用护照来引用 子图 之间的特定对象。
typename 字段 就像护照的原籍国。它说明了该对象属于哪个 实体。并且 字段@key
就如同护照的 ID 号码,唯一标识该 实体 的实例。
练习
__resolveReference
函数应该定义在哪里?将该框中的项拖动到上方的空白部分
引用解析器
子图
@unique
字段
路由
@key
仅一个
多个
@primary
键
关键要点
- 实体是一种在其多个子图中解析其字段(s) 的类型。
- 要创建实体,我们可以使用
@key
指令指定哪个字段(s) 可以唯一标识该类型的某个对象。 - 我们可以通过两种方式使用实体
- 作为字段的返回类型(引用一个实体)。
- 为实体定义字段(从多个子图中贡献到实体)。
- 所有子图为某个实体贡献字段的子图需要为该实体定义一个引用解析器函数。此
__resolveReference
解析器在路由器需要从另一个子图访问给定实体的字段时调用。 - 一个实体表示是一个对象,路由器使用此对象来表示实体的一个具体实例。它包括实体的类型及其键字段。
接下来
我们已经针对实体介绍了很多!在下一课中,我们将回到我们子图的代码中,并定义我们的第一个实体。
分享你对本课程的问题和评论
你的反馈有助于我们改进!如果你遇到了困难或感到困惑,请告诉我们,我们会帮助你的。所有评论都是公开的,且必须遵守 Apollo 行为准则。注意,已解决或已处理的评论可能会被删除。
你需要一个 GitHub 帐户才能在下方发帖。如果没有 GitHub 帐户怎么办? 请在我们的 Odyssey 论坛中发帖。