# 从实体服务 API 到文档服务 API

> Source: https://strapi.nodejs.cn/cms/migration/v4-to-v5/additional-resources/from-entity-service-to-document-service

🌐 Entity Service API to Document Service API migration reference

文档服务 API 在 Strapi 5 中取代了实体服务 API。升级工具的代码修改（codemod）会自动转换函数调用和 `publicationState` 到 `status`，但 `documentId` 的值以及像 `publish()` 和 `unpublish()` 这样的发布方法仍需手动干预。

🌐 The Document Service API replaces the Entity Service API in Strapi 5. The upgrade tool's codemod automatically converts function calls and `publicationState` to `status`, but manual intervention is required for `documentId` values and publication methods like `publish()` and `unpublish()`.

在 Strapi 5 中，[文档服务 API](/cms/api/document-service) 替代了 Strapi v4 的实体服务 API（见 [重大更改说明](/cms/migration/v4-to-v5/breaking-changes/entity-service-deprecated)）。

🌐 In Strapi 5, the [Document Service API](/cms/api/document-service) replaces the Entity Service API from Strapi v4 (see [breaking change description](/cms/migration/v4-to-v5/breaking-changes/entity-service-deprecated)).

本页面旨在向开发者说明如何从实体服务 API 迁移，通过描述哪些自定义代码的更改将由 [升级工具](/cms/upgrade-tool) 的代码修改（codemods）处理，以及哪些将需要手动处理。

🌐 The present page is intended to give developers an idea of how to migrate away from the Entity Service API, by describing which changes in custom code will be handled by codemods from the [upgrade tool](/cms/upgrade-tool) and which will have to be handled manually.

## 使用升级工具进行迁移 {#migration-using-the-upgrade-tool}

🌐 Migration using the upgrade tool

在使用 [升级工具](/cms/upgrade-tool) 时，会运行一个代码修改工具（codemod），并处理 `entityService` 迁移的某些部分。

🌐 When using the [upgrade tool](/cms/upgrade-tool), a codemod is run and handles some parts of the `entityService` migration.

:::caution

该 codemod 只更改函数调用和一些参数。这不能被视为完整的迁移，因为 codemod 永远无法将 `entityId` 转换为 `documentId`。

🌐 The codemod is only changing the function calls and some parameters. This can not be considered as a complete migration as the codemod will never be able to convert an `entityId` into a `documentId`.

:::

### Codemod 范围 {#codemod-scope}

🌐 Codemod scope

以下列表解释了 codemod 自动处理的内容（✅）、codemod 未处理的内容且必须 100% 手动处理的内容（❌）以及 codemod 运行后仍需要手动干预的内容（🚧）：

🌐 The following list explains what is automatically handled by the codemod (✅), what is not handled by the codemod and must be handled 100% manually (❌) and what will still require manual intervention after the codemod has run (🚧):

| 主题 | 由 codemod 处理？ | 需要手动执行的步骤 |
|-------|------------------------|--------------------------|
| 代码结构 | ✅ 是 | 没有。<br/>代码结构已自动迁移。 |
| `publicationState` 已移除，取而代之的是 [`status`](/cms/api/document-service/status) | ✅ 是 | 没有。<br/>代码修改工具会自动进行转换。 | 
| 使用 `documentId` 代替 Strapi v4 的唯一标识符 | 🚧 部分完成:<ul><li>codemod 会向你的代码中添加新的 `documentId` 属性，因为 `documentId` 是在 Strapi 5 中需要使用的新唯一标识符。</li><li>但实际的 `documentId` 值无法被推测，所以在 codemod 运行后，你会在代码中发现 `__TODO__` 占位符值。</li></ul> | 👉 `__TODO__` 占位符值需要手动更新。<br/><br/>例如，你可能会将<br/>`documentId: "__TODO__"`<br/>改为类似<br/>`documentId: "ln1gkzs6ojl9d707xn6v86mw"` 的值。
| 更新 `published_at` 以触发发布 | ❌ 未处理.<br/> | 👉 请更新你的代码，改为使用文档服务 API 的新 [`publish()`](/cms/api/document-service#publish)、[`unpublish()`](/cms/api/document-service#publish) 和 [`discardDraft()`](/cms/api/document-service#publish) 方法。 |

### 函数调用迁移的示例 {#examples-of-function-calls-migration}

🌐 Examples of function calls migration

以下示例显示了升级工具中的 codemod 如何更新各种函数调用的代码。

🌐 The following examples show how the codemod from the upgrade tool updates the code for various function calls.

#### `findOne`

**之前：**

```tsx
strapi.entityService.findOne(uid, entityId);

```

**之后：**

```tsx
strapi.documents(uid).findOne({
  documentId: "__TODO__"
});
```

#### `findMany`

**之前：**

```tsx
strapi.entityService.findMany(uid, {
  fields: ["id", "name", "description"],
  populate: ["author", "comments"],
  publicationState: "preview",
});
```

**之后：**

```tsx
strapi.documents(uid).findMany({
  fields: ["id", "name", "description"],
  populate: ["author", "comments"],
  status: "draft",
});
```

#### `create`

**之前：**

```tsx
strapi.entityService.create(uid, {
  data: {
    name: "John Doe",
    age: 30,
  },
});
```
**之后：**

```tsx
strapi.documents(uid).create({
  data: {
    name: "John Doe",
    age: 30,
  },
});
```

#### `update`

**之前：**

```tsx
strapi.entityService.update(uid, entityId, {
  data: {
    name: "John Doe",
    age: 30,
  }
});

```
**之后：**

```tsx
strapi.documents(uid).update({
  documentId: "__TODO__",
  data: {
    name: "John Doe",
    age: 30,
  }
});
```

#### `delete`

**之前：**

```tsx
strapi.entityService.delete(uid, entityId);

```
**之后：**

```tsx
strapi.documents(uid).delete({
  documentId: "__TODO__"
});
```

#### `count`

**之前：**

```tsx
strapi.entityService.count(uid);
```
**之后：**

```tsx
strapi.documents(uid).count();
```

## 手动迁移 {#manual-migration}

🌐 Manual migration

- 希望手动迁移的用户可以通过复制 codemod 所做的操作来进行迁移（参考 [codemod 范围](#codemod-scope) 和 [函数调用示例](#examples-of-function-calls-migration)）。
- 在代码中使用实体服务（Entity Service）装饰器的插件开发者必须将其替换为文档服务（Document Service）中间件。下面的示例可以让你了解它们的工作原理，更多信息可以在专门的 [文档服务中间件文档](/cms/api/document-service/middlewares) 中找到：

  **在 Strapi v4 中：**

  ```tsx
  strapi.entityService.decorate((service) => {

    return Object.assign(service, {
    
      findOne(entityId, params = {}) {
        // e.g., exclude soft deleted content
        params.filters = { ...params.filters, deletedAt: { $notNull: true } } 
        return service.findOne(entityId, params)
      }
    });
  })
  ```

  **在 Strapi 5 中**

  ```tsx
  strapi.documents.use((ctx, next) => {
    if (ctx.uid !== "api::my-content-type.my-content-type") {
      return next();
    }
    
    if (ctx.action === 'findOne') {
      // customization
      ctx.params.filters = { ...params.filters, deletedAt: { $notNull: true } } 
      const res = await next();
      // do something with the response if you want
      return res;
    }
    
    return next();
  });
  ```

* 根据以下情况，更新你在单一类型上的 `findMany()` 自定义代码：
  - 在 Strapi v4 中，当在单一类型上调用 `findMany()` 函数时，它会返回单个项目。
  - 在 Strapi 5 中，`findMany()` 函数是通用的，并且总是返回数组，无论是对单一类型还是集合类型调用。要通过 `findMany()` 调用获取单一类型的数据，请从返回的数组中提取第一个项目。
