7. 介绍实体
15m

概述

现在是见证联邦真正力量的时候了;我们即将把这些部分组合起来,使我们的查询比以往任何时候都更强大,更具动态性。

在本课中,我们将

  • 了解什么是 类型,它的用途,以及如何定义它
  • Listing 类型转换为一个

评论和列表

还记得我们的梦想 吗?

query GetListingAndReviews {
listing(id: "listing-1") {
title
description
numOfBeds
amenities {
name
category
}
overallRating
reviews {
id
text
}
}
}

正如这个 所示,我们希望 reviewsoverallRating 成为 Listing 类型上。

这最大的问题是什么?正如我们之前讨论过的, reviews listings 中的类型一无所知,更不用说它应该添加一个 Listing 类型了!让我们用实体来解决这个问题。

什么是实体?

一个 实体 是一个 ,它的 分布在多个 上。它是联邦图架构的基本构建块,用于在子图之间连接数据,同时仍然遵守关注点分离原则。

使用 时,每个 可以执行以下一项或两项操作:

  • 贡献 不同的
  • 引用 一个 ,这意味着在 中定义的另一个 中使用它作为返回值类型。

贡献与引用

为了区分 ,即那些 贡献 到一个 的,以及那些 引用 一个 的,可以这样理解:一个 贡献 实际上是在从 它自己的域 类型添加新的数据功能。

这与仅仅 引用 形成对比;它本质上只是“提及”实体的存在,并提供它作为 另一个字段 的返回值类型。

在联邦中,我们使用实体来创建连贯的类型,这些类型不局限于一个 或另一个;相反,它们可以跨越整个 API!

在我们的示例中,我们希望用与评论相关的补充我们的 Listing 类型。这使得 Listing 类型成为一个完美的 候选人;它需要有在 两个 中定义的 。这让我们可以构建对 API 中“列表”的更强大的表示,以及构成它的不同数据。

要创建 ,一个 需要提供两样东西:一个 主键 和一个 引用解析器

定义主键

一个 主键(或字段)可以唯一地标识 中该 的一个实例。就像在数据库中一样,这是让我们能够区分 一个事物另一个事物 的信息。当我们谈论列表时,我们使用它们的 id 来识别 哪个 列表是我们正在谈论的。

使用主键从多个 中收集数据,并将它们与单个 实例关联起来。这就是我们如何知道每个子图都在谈论,并提供数据的 同一个 对象!

Illustration showing three entities with unique ids

我们使用 @key ,以及一个名为 fields 的属性来设置我们要用作 主键的

实体语法
type EntityType @key(fields: "id") {
# ...
}

引用解析器和实体表示

因为一个 可以跨 分布,因此每个 提供 的子图都需要一种方法来识别 正在收集数据的实例。当它能够识别此实例时, 可以提供其他数据。识别 的特定实例采用一种称为 引用解析器 的方法。

此方法接收一个名为 的基本对象。一个 实体表示 是一个对象, 用它来识别 的特定实例。表示包含该 类型名称 和特定实例的 @key

  • __typename 字段:此 自动存在于所有 类型中。它总是以字符串形式返回其包含类型的名称。例如,Listing.__typename 返回 "Listing"。

  • @key 字段 可以用来识别 实例的键值对。例如,如果我们使用 "id" 作为主键定义 Listing ,那么我们的实体表示将包含一个 "id" 属性,其值类似于 "listing-3"。

传递给每个 表示,用于解决特定 Listing ,可能看起来像这样:

示例 Listing 实体表示
{
"__typename": "Listing",
"id": "listing-3"
}

您可以将 表示视为 需要关联来自多个 的数据的最小基本信息,并确保每个子图都在讨论同一个对象。

正如我们很快将看到的那样,特定清单的 表示将为我们的 reviews 提供它需要的所有信息(不多也不少!),以便贡献相关的评论数据。

创建 Listing 实体

将所有这些都带回到我们梦寐以求的 !我们希望将 Listing 类型设置为一个 ,以便 reviews 可以为其贡献两个 overallRatingreviews

让我们开始吧!

listings 子图中

在您的 rover dev 进程仍在运行的情况下,打开 listings 并导航到 schema.graphqls 。向下滚动以找到 Listing 类型。

在这里,我们将应用 @key ,传入一个设置为 "id"fields 属性。

(listings) schema.graphqls
type Listing @key(fields: "id") {
id: ID!
# ... other Listing fields
}

当我们保存更改时,rover dev 将自动获取新的模式并重新启动 过程。确保在继续到 reviews 之前它成功合成。

reviews 子图中

打开您的代码编辑器以进入 reviews ,并导航到 src/main/resources/schema/schema.graphqls 文件。我们首先添加 Listing 类型的基本存根:它包含类型名称、@key 以及作为其主键分配的 id

(reviews) schema.graphqls
type Listing @key(fields: "id") {
id: ID!
}

请注意,我们不包含 任何其他 来自 Listing (如 listings 中所定义)。我们可以让我们的 reviews 保持干净,并且 关注它有责任提供的数据。

让我们将 reviews 添加到 Listing 类型。我们将其返回类型设置为 [Review!]! 。我们还将定义 overallRating ,它返回一个可为空的 Float 类型。

(reviews) schema.graphqls
type Listing @key(fields: "id") {
id: ID!
"The submitted reviews for this listing"
reviews: [Review!]!
"The overall calculated rating for a listing"
overallRating: Float
}

测试我们的模式更改

我们的 rover dev 进程应该仍在运行,所以让我们回到 https://127.0.0.1:4000

现在,我们将看到 reviews 可用于 Listing 类型。我们的小型模式更改使我们能够构建我们梦寐以求的

https://127.0.0.1:4000

Sandbox with our dream query syntax written into the Operation panel

query GetListingAndReviews {
listing(id: "listing-1") {
title
description
numOfBeds
amenities {
name
category
}
overallRating
reviews {
id
text
}
}
}

虽然看起来很漂亮,但我们的 实际上还不能返回数据。虽然 listings 可以轻松解决 的清单 idtitledescriptionnumOfBedsamenities ),但我们还没有让 reviews 了解 该怎么做 请求特定清单的 reviewsoverallRating

事实上,如果我们运行 ,我们将看到一堆令人讨厌的错误。

练习

检查您的理解!
实体的主键用于标识实体在 
 
中的唯一实例。要定义主键,请应用  
 
 指令并将主键字段的名称作为 
 
 属性的值传递。一个实体可以拥有 
 
 个主键。

将项目从该框拖到上面的空白处

  • 多个

  • 引用解析器

  • 只有一个

  • 字段

  • @primary

  • 路由器

  • @unique

  • @key

  • 子图

关键要点

  • 一个 是一种可以跨多个 解析其 的类型。
  • 要创建 ,我们可以使用 @key 来指定哪些 (或字段组)可以唯一地标识该类型的对象。
  • 我们可以以两种方式使用实体
    • 作为 的返回类型(引用 )。
    • 定义 来构建一个 (从多个 中获取信息)。

接下来

在下一课中,我们将为我们的 reviews 添加逻辑,使其可以实际返回数据。

上一个

分享您关于本课的问题和评论

本课程目前处于

测试版
.您的反馈有助于我们改进!如果您卡住了或感到困惑,请告诉我们,我们会帮助您。所有评论都是公开的,必须遵循  Apollo 行为准则。请注意,已解决或已处理的评论可能会被删除。

您需要一个 GitHub 帐户才能在下面发布。没有帐户? 请在我们的 Odyssey 论坛中发帖。