跳到主要内容

升级 Prisma ORM 层

概览

本页解释了升级过程的第一步:将你的 Prisma 1 配置升级到 Prisma ORM 2。具体来说,你将学习如何

  1. 将 Prisma ORM 2 CLI 添加为开发依赖
  2. 创建你的 Prisma ORM 2 Schema
  3. 确定你的连接 URL 并连接到数据库
  4. 内省你的数据库(该数据库目前由 Prisma 1 管理)
  5. 使用Prisma 1 Upgrade CLI 解决新的 Prisma ORM 2 数据模型中的Schema 不兼容性
  6. 安装并生成 Prisma Client

完成这些步骤后,你可以继续阅读下一篇指南,了解如何升级应用层以使用 Prisma Client 进行数据库查询。

注意:在升级过程中,获取数据库的图形化视图会很有帮助。因此,建议使用图形化数据库客户端连接到你的数据库,例如 TablePlusPostico

1. 安装 Prisma ORM 2 CLI

Prisma ORM 2 CLI 以 prisma 包的形式在 npm 上提供,并通过 prisma 命令调用。

请注意,Prisma 1 的前 prisma 命令已重命名为 prisma1。你可以在此处了解更多信息。

你可以如下在你的 Node.js 项目中安装 Prisma ORM 2 CLI(请确保在你的 package.json 文件所在的目录中调用此命令)

npm install prisma --save-dev

注意:对于 Prisma 1,通常建议全局安装 CLI。我们现在建议本地安装 Prisma CLI 以防止版本冲突。

现在,你可以通过在其前加上 npx 来使用本地安装的 prisma CLI

npx prisma

如果你正在一次性升级整个项目,你现在也可以卸载 Prisma 1 CLI(否则请展开下方内容)

# remove global installation
npm uninstall -g prisma1

# remove local installation
npm uninstall prisma1

如果你想同时使用 Prisma 1 CLI,请展开

如果你想继续使用 Prisma 1 CLI,建议移除其全局安装,并将 prisma1 CLI 添加为开发依赖

# installs v1.34 of the Prisma 1 CLI
npm uninstall -g prisma
npm install prisma1 --save-dev

现在你可以如下调用它

npx prisma1

请注意,如果你需要小于 1.34 的 CLI 版本(例如 1.30),可以如下安装它

# installs v1.30 of the Prisma 1 CLI
npm uninstall -g prisma@1.30
npm install prisma@1.30 --save-dev

现在你可以如下调用它

npx prisma

2. 创建你的 Prisma ORM 2 Schema

在本指南中,你首先将使用 prisma init 命令创建一个新的 Prisma schema,然后使用内省为它“填充”数据模型。

运行以下命令创建你的 Prisma schema(注意,如果已有名为 prisma 的文件夹,此命令会抛出错误)

npx prisma init

如果你看到以下错误,你需要重命名当前的 prisma 目录

ERROR  A folder called prisma already exists in your project.
Please try again in a project that is not yet using Prisma.

你可以将当前的 prisma 目录重命名为 prisma1,以表明其中包含的是原 Prisma 1 配置

mv prisma prisma1

现在你可以运行 init,它将成功

npx prisma init

它应该会打印以下输出

✔ Your Prisma schema was created at prisma/schema.prisma.
You can now open it in your favorite editor.

Next steps:
1. Set the `DATABASE_URL` in the `.env` file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started
2. Set the `provider` of your `datasource` block in `schema.prisma` to match your database: `postgresql`, `mysql` or `sqlite`.
3. Run `prisma db pull` to turn your database schema into a Prisma data model.
4. Run `prisma generate` to install Prisma Client. You can then start querying your database.

More information in our documentation:
https://pris.ly/d/getting-started

该命令创建了一个名为 prisma 的新文件夹,以及两个文件

  • prisma/schema.prisma: 你的 Prisma schema 文件,指定了数据源生成器数据模型(注意,数据模型尚不存在,将通过内省生成)。
  • .env: 一个 dotenv 文件,用于配置你的数据库连接 URL

你的初始 Prisma schema 如下所示

schema.prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}

generator client {
provider = "prisma-client-js"
}

对于 Prisma 1,你在 prisma.yml 中指定要使用哪种语言变体的 Prisma Client。对于 Prisma ORM 2,此信息现在通过 generator 块在 Prisma schema 中指定。

注意:与 Prisma 1 不同,Prisma Client 2.0 的 TypeScript 和 JavaScript 变体使用同一个名为 prisma-client-js 的生成器。即使在纯 JavaScript 项目中,生成的 index.d.ts 类型始终包含在内。这使得即使在不使用 TypeScript 时也能在 VS Code 中启用自动补全等功能。

3. 确定你的连接 URL 并连接到数据库

对于 Prisma 1,数据库连接配置在用于启动 Prisma ORM 服务器的 Docker Compose 文件中。Prisma ORM 服务器随后暴露一个 GraphQL 端点(通过 HTTP),该端点代理来自 Prisma Client 应用代码的所有数据库请求。该 HTTP 端点在你的 prisma.yml 中指定。

对于 Prisma ORM 2,HTTP 层不再暴露,Prisma Client 2.0 配置为“直接”对数据库运行请求(也就是说,请求由 Prisma ORM 的查询引擎代理,但不再有额外的服务器)。

因此,下一步你需要告诉 Prisma ORM 2 你使用的数据库类型(MySQL 或 PostgreSQL)及其位置。

首先,你需要确保 schema.prisma 文件中的 datasource 块上的 provider 字段配置为使用正确的数据库。

  • 如果你使用的是 PostgreSQL,需要在 provider 字段中定义值 "postgresql"
  • 如果你使用的是 MySQL,需要在 provider 字段中定义值 "mysql"

切换代码块中的选项卡,查看两者的示例

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

设置好 provider 字段后,你可以继续在 .env 文件中配置连接 URL。

假设你用于部署 Prisma ORM 服务器的 Docker Compose 文件中的数据库配置如下所示

docker-compose.yml
PRISMA_CONFIG: |
port: 4466
databases:
default:
connector: mysql
host: mysql
port: 3306
user: root
password: randompassword

再假设你的 prisma.yml 中的 endpoint 配置如下所示

prisma.yml
endpoint: http://localhost:4466/myproject/dev

根据这些连接详情,你需要如下配置你的 .env 文件中的 DATABASE_URL 环境变量

.env
DATABASE_URL="mysql://root:randompassword@localhost:3306/myproject@dev"

请注意,连接 URL 中的数据库名称通常由你的服务名称和服务阶段组成(这部分在 prisma.yml 的 endpoint 中),两者用 @ 字符分隔。

有时在 prisma.yml 中未指定服务名称和阶段

prisma.yml
endpoint: http://localhost:4466/

在这种情况下,数据库名称必须如下指定

.env
DATABASE_URL="mysql://root:randompassword@localhost:3306/default@default"

连接 URL 页面了解更多信息。

4. 内省你的数据库

为了本指南的目的,我们将使用以下 Prisma 1 数据模型(选择下方的 SQL 选项卡查看数据模型映射到 SQL 的内容)

type User {
id: ID! @id
email: String @unique
name: String!
role: Role! @default(value: CUSTOMER)
jsonData: Json
profile: Profile
posts: [Post!]!
}

type Post {
id: ID! @id
createdAt: DateTime! @createdAt
updatedAt: DateTime! @updatedAt
title: String!
content: String
published: Boolean! @default(value: false)
author: User @relation(link: TABLE)
categories: [Category!]!
}

type Profile {
id: ID! @id
bio: String
user: User! @relation(link: INLINE)
}

type Category {
id: ID! @id
name: String!
posts: [Post!]!
}

enum Role {
ADMIN
CUSTOMER
}

请注意,此数据模型有三个关系

  • 1-1:UserProfile
  • 1-n:UserPost(通过 _PostToUser 关系表维护)
  • m-n:PostCategory(通过 _CategoryToPost 关系表维护)

现在你可以使用以下命令对数据库运行 Prisma ORM 的内省

npx prisma db pull

这是调用 db pull 时发生情况的图形化说明

Introspect your database

对于上述 Prisma 1 数据模型,这会生成以下 Prisma ORM 2 schema(请注意,模型已重新排序以匹配 Prisma 1 数据模型的初始顺序)

schema.prisma
model User {
id String @id @default(cuid())
email String? @unique
name String
role String
jsonData String?
Profile Profile[]
Post Post[]
}

model Post {
id String @id @default(cuid())
createdAt DateTime
updatedAt DateTime
title String
content String?
published Boolean
Category Category[]
User User[]
}

model Profile {
id String @id @default(cuid())
bio String?
user String? @unique
User User? @relation(fields: [user], references: [id])
}

model Category {
id String @id @default(cuid())
name String
Post Post[]
}

虽然这已经是一个有效的 Prisma ORM 2 schema,但它缺少 Prisma 1 版本中的许多特性

  • Post 模型中 createdAtupdatedAt 字段没有自动生成的日期值
  • User 模型中 role 字段没有默认值
  • Post 模型中 published 字段没有默认值

此外,还有一些不一致之处,导致 Prisma Client API 不够地道/不符合人体工程学

  • UserProfile 是 1-n 关系,而不是 1-1 关系
  • UserPost 是 m-n 关系,而不是 1-n 关系
  • 关系字段为大写(例如 User 模型中的 ProfilePost
  • User 模型中的 jsonData 字段类型为 String,而不是 Json
  • User 模型中的 role 字段类型为 String,而不是 Role,并且完全缺少 role 的 enum 定义

虽然这些不一致之处实际上不会影响你在 Prisma Client API 中可用的“功能集”,但它们会让你失去之前存在的一些约束/保证。

例如,Prisma ORM 现在无法保证一个 User 最多连接到一个 Profile,因为在内省过程中,表之间的关系被识别为 1-n,所以现在一个 User 记录可能连接到多个 Profile 记录。

另一个问题是,你可以为 jsonDatarole 字段存储任何文本,无论它是否是有效的 JSON 或代表 Role 枚举的值。

要了解有关这些不一致之处的更多信息,请查看Schema 不兼容性页面。

接下来,我们将使用 Prisma schema 升级 CLI 逐一解决这些不一致之处。

5. 使用 Prisma schema 升级 CLI 解决 Schema 不兼容性

Prisma 1 Upgrade CLI 是一个交互式工具,可帮助你升级 Prisma schema 并解决上述大多数不一致之处。

Prisma 1 Upgrade CLI 主要分两个阶段工作

  1. 通过纯 SQL 修复数据库 schema
  2. 向 Prisma ORM 2 schema 添加缺失属性及其他 schema 修复

在第一阶段,它将生成并打印一系列 SQL 语句,你应该针对数据库运行这些语句以调整数据库 schema。你可以在继续进入第二阶段之前运行所有语句或其中一部分。

在第二阶段,你无需手动执行任何操作。Upgrade CLI 将通过添加某些 Prisma ORM 级别的属性(例如 @default(cuid))@updatedAt)、调整关系字段名称以匹配 Prisma 1 数据模型中的名称,以及确保在 Prisma 1 数据模型中两端都必需的 1-1 关系在 Prisma ORM 2 schema 中也必需,来更改你的 Prisma schema。

请注意,在此过程中的任何时候,你都可以重新开始,并从第二阶段返回到第一阶段。

在此图中,绿色区域显示第一阶段,蓝色区域显示第二阶段。请注意,你可以在两个阶段之间选择性地运行 prisma db pull 来更新你的 Prisma ORM 数据模型

Fixing the schema incompatibilities

要使用 Upgrade CLI,你可以在项目中本地安装它,或者像这里一样使用 npx 无需安装即可调用一次

npx prisma-upgrade prisma1/prisma.yml prisma/schema.prisma

CLI 将显示以下消息欢迎你

◮ Welcome to the interactive Prisma Upgrade CLI that helps with the
upgrade process from Prisma 1 to Prisma ORM 2.

Please read the docs to learn more about the upgrade process:
https://pris.ly/d/how-to-upgrade

➤ Goal
The Upgrade CLI helps you resolve the schema incompatibilities
between Prisma 1 and Prisma ORM 2. Learn more in the docs:
https://pris.ly/d/schema-incompatibilities

➤ How it works
Throughout the process, you'll need to adjust your database schema by sending
SQL statements to it. The SQL statements are provided by the Upgrade CLI.

Note that the Upgrade CLI never makes changes to your database,
you are in full control over any operations that are executed against it.

You can stop and re-run the Upgrade CLI at any time.

These are the different steps of the upgrade process:

1. The Upgrade CLI generates SQL commands for you to run on your database.
2. You run the SQL commands against your database.
3. You run the `npx prisma db pull` command again.
4. You run the `npx prisma-upgrade` command again.
5. The Upgrade CLI adjusts the Prisma ORM 2 schema by adding missing attributes.

➤ Note
It is recommended that you make a full backup of your existing data before starting
the upgrade process. If possible, the migration should be performed in a staging
environment before executed against a production environment.

➤ Help
If you have any questions or run into any problems along the way,
please create an issue at:
https://github.com/prisma/prisma1-upgrade/issues/new

Are you ready? [Y/n]

按下 Y 键,然后按键盘上的 RETURN 确认继续。

确认后,CLI 将输出你应该针对数据库运行的 SQL 语句

➤ Adjust your database schema
Run the following SQL statements against your database:

Fix columns with ENUM data types
https://pris.ly/d/schema-incompatibilities#enums-are-represented-as-text-in-database

ALTER TABLE `User` CHANGE `role` `role` ENUM('ADMIN', 'CUSTOMER') NOT NULL;


Add missing `DEFAULT` constraints to the database
https://pris.ly/d/schema-incompatibilities#default-values-arent-represented-in-database

ALTER TABLE `User` CHANGE `role` `role` ENUM('ADMIN', 'CUSTOMER') NOT NULL DEFAULT 'CUSTOMER';
ALTER TABLE `Post` CHANGE `published` `published` TINYINT(1) NOT NULL DEFAULT 0;


Fix columns with JSON data types
https://pris.ly/d/schema-incompatibilities#json-type-is-represented-as-text-in-database

ALTER TABLE `User` CHANGE `jsonData` `jsonData` JSON ;


Replicate `@createdAt` behavior in Prisma ORM 2.0
https://pris.ly/d/schema-incompatibilities#createdat-isnt-represented-in-database

ALTER TABLE `Post` CHANGE `createdAt` `createdAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP;


Fix 1-1 relations by adding `UNIQUE` constraints
https://pris.ly/d/schema-incompatibilities#inline-1-1-relations-are-recognized-as-1-n-missing-unique-constraint

ALTER TABLE `Profile` ADD UNIQUE (`user`);


Migrate IDs from varchar(25) to varchar(30)
https://pris.ly/d/schema-incompatibilities#mismatching-cuid-length

SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE `Category` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
ALTER TABLE `Post` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
ALTER TABLE `Profile` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
ALTER TABLE `Profile` CHANGE `user` `user` char(30) CHARACTER SET utf8 ;
ALTER TABLE `User` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
SET FOREIGN_KEY_CHECKS=1;

➤ Breaking changes detected

In order to fully optimize your database schema, you'll need to run a few SQL
statements that can break your Prisma 1 setup. Note that these changes are optional
and if you are upgrading gradually and running Prisma 1 and Prisma ORM 2 side-by-side,
you should not perform these changes yet. Instead, you can perform them whenever
you are ready to completely remove Prisma 1 from your project.
If you are upgrading all at once, you can safely perform these changes now.

Learn more in the docs:
https://pris.ly/d/how-to-upgrade'

注意:如果你看到关于重大变更的说明,现在可以忽略它。我们稍后会讨论。

显示的 SQL 语句被归类到多个“类别”中,所有这些都旨在解决某种schema 不兼容性

  • 修复 ENUM 数据类型的列
  • 向数据库添加缺失的 DEFAULT 约束
  • 修复 JSON 数据类型的列
  • 在 Prisma 2 中复制 @createdAt 行为
  • 通过添加 UNIQUE 约束修复 1-1 关系

下一步,你可以开始向数据库发送 SQL 语句。请注意,所有这些更改都是非破坏性的,你将能够继续与 Prisma ORM 2 同时使用 Prisma 1。

接下来的章节将单独介绍要发送到数据库的不同类型的 SQL 语句。

5.1. 通过纯 SQL 修复数据库 schema(非破坏性)

在本节中,我们将逐一浏览打印的 SQL 语句并针对数据库运行它们。

5.1.1. 修复 ENUM 数据类型的列

该工具首先做的是帮助你确保 Prisma 1 数据模型中的 enum 定义将在底层数据库中表示为实际的 ENUM 类型,目前它们表示为普通字符串(例如在 MySQL 中为 MEDIUMTEXT)。

CLI 当前显示以下输出

Fix columns with ENUM data types
https://pris.ly/d/schema-incompatibilities#enums-are-represented-as-text-in-database

ALTER TABLE `User` CHANGE `role` `role` ENUM('ADMIN', 'CUSTOMER') NOT NULL;

现在就开始针对数据库运行这些语句吧。

Altering columns to use ENUM with SQL

5.1.2. 向数据库添加缺失的 DEFAULT 约束

接下来,Upgrade CLI 通过生成 SQL 语句,将相应的 DEFAULT 约束直接添加到数据库,帮助你解决默认值未在数据库中表示的问题。

在此情况下,缺少两个由该工具建议的 DEFAULT 约束

Add missing `DEFAULT` constraints to the database
https://pris.ly/d/schema-incompatibilities#default-values-arent-represented-in-database

ALTER TABLE `User` CHANGE `role` `role` ENUM('ADMIN', 'CUSTOMER') NOT NULL DEFAULT 'CUSTOMER';
ALTER TABLE `Post` CHANGE `published` `published` TINYINT(1) NOT NULL DEFAULT 0;

你现在可以使用命令行客户端或 TablePlus 等 GUI 针对数据库运行这些 SQL 语句

TablePlus GUI

5.1.3. 修复 JSON 数据类型的列

接下来,该工具帮助你确保 Prisma 1 数据模型中的 Json 字段将在底层数据库中表示为 JSON 列,目前它们表示为普通字符串(例如在 MySQL 中为 MEDIUMTEXT)。

将列类型更改为 JSON 将确保该字段在 Prisma ORM 2 内省过程中被正确识别为 Json

CLI 当前显示以下输出

Fix columns with JSON data types
https://pris.ly/d/schema-incompatibilities#json-type-is-represented-as-text-in-database

ALTER TABLE `User` CHANGE `jsonData` `jsonData` JSON ;

你现在可以使用命令行客户端或 TablePlus 等 GUI 针对数据库运行这些 SQL 语句

TablePlus GUI

5.1.4. 在 Prisma ORM 2 中复制 @createdAt 行为

该工具接下来做的是帮助你解决@createdAt 的行为未在数据库中表示的问题

CLI 当前显示以下输出

Replicate `@createdAt` behavior in Prisma ORM 2.0
https://pris.ly/d/schema-incompatibilities#createdat-isnt-represented-in-database

ALTER TABLE `Post` CHANGE `createdAt` `createdAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP;

你现在可以使用命令行客户端或 TablePlus 等 GUI 针对数据库运行这些 SQL 语句。

5.1.5. 通过添加 UNIQUE 约束修复 1-1 关系

现在,该工具将通过向数据库中名为 user(以 Prisma 1 数据模型中的关系字段命名)的外键列添加 UNIQUE 约束,帮助你UserProfile 之间的当前 1-n 关系变回 1-1 关系

CLI 当前显示以下输出

Fix 1-1 relations by adding `UNIQUE` constraints
https://pris.ly/d/schema-incompatibilities#inline-1-1-relations-are-recognized-as-1-n-missing-unique-constraint

ALTER TABLE `Profile` ADD UNIQUE (`user`);

你现在可以使用命令行客户端或 TablePlus 等 GUI 针对数据库运行这些 SQL 语句。

5.1.6. 修复 CUID 长度不匹配问题

注意:即使你在底层数据库中更改了列类型,这些 SQL 语句仍会继续出现在 Upgrade CLI 中。这是 Upgrade CLI 当前的一个限制。

最后,该工具将通过向数据库中名为 user(以 Prisma 1 数据模型中的关系字段命名)的外键列添加 UNIQUE 约束,帮助你将当前类型为 VARCHAR(25) 的 ID 列变为 VARCHAR(30)

CLI 当前显示以下输出

Migrate IDs from varchar(25) to varchar(30)
https://pris.ly/d/schema-incompatibilities#mismatching-cuid-length

SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE `Category` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
ALTER TABLE `Post` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
ALTER TABLE `Profile` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
ALTER TABLE `Profile` CHANGE `user` `user` char(30) CHARACTER SET utf8 ;
ALTER TABLE `User` CHANGE `id` `id` char(30) CHARACTER SET utf8 NOT NULL;
SET FOREIGN_KEY_CHECKS=1;

你现在可以使用命令行客户端或 TablePlus 等 GUI 针对数据库运行这些 SQL 语句。

5.1.7. 检测到重大变更

如果 Upgrade CLI 打印了关于重大变更的说明,你的数据库 schema 需要进行一些调整,这些调整会破坏 Prisma 1 的兼容性,以便完全优化。

如果未检测到重大变更,你可以跳过本节,继续阅读 5.2 节

根据你的升级策略,你现在可以执行这些更改,或跳过 Upgrade CLI 的下一阶段

  • 如果你采用渐进式并行升级策略,请暂时不要执行这些更改,因为它们会破坏你的 Prisma 1 设置。在这种情况下,你可以通过输入 n 并按 RETURN 继续进入 Upgrade CLI 的下一阶段。
  • 如果你采用一次性升级策略,你现在可以执行这些更改。在这种情况下,通过输入 Y 并按 RETURN 继续。

5.2. 通过纯 SQL 修复数据库 schema(破坏性)

在本节中,你将解决破坏 Prisma 1 设置的 schema 不兼容性。如果你的项目仍在使用 Prisma 1,请勿执行这些更改!

5.2.1. 修复不正确的 m-n 关系

现在,Upgrade CLI 帮助你修复所有 Prisma 1 使用关系表表示的 1-1 和 1-n 关系,这些关系目前在你的新 Prisma ORM 2 schema 中仅作为 m-n 关系存在。具体来说,UserPost 关系就是这种情况,它目前被定义为 m-n,但实际上应该是一个 1-n 关系。

要修复此问题,你需要执行以下迁移

  1. Post 表上创建一个新的外键列,直接链接到 User 表。
  2. 将关系表中的外键值迁移到 Post 表上的新外键列中。
  3. 删除关系表。

这些说明现在由 CLI 打印

➤ Adjust your database schema
Run the following SQL statements against your database:

Fix one-to-many table relations
https://pris.ly/d/schema-incompatibilities#all-non-inline-relations-are-recognized-as-m-n

ALTER TABLE `Post` ADD COLUMN `authorId` char(25) CHARACTER SET utf8 ;
ALTER TABLE `Post` ADD CONSTRAINT author FOREIGN KEY (`authorId`) REFERENCES `User`(`id`);
UPDATE `Post`, `_PostToUser` SET `Post`.`authorId` = `_PostToUser`.B where `_PostToUser`.A = `Post`.`id`;
DROP TABLE `_PostToUser`;


➤ Next Steps

After you executed one or more of the above SQL statements against your database,
please run the following two commands to refresh your Prisma ORM 2 Schema and check
the changes.

1. Run `npx prisma db pull` again to refresh your Prisma ORM 2 schema.
2. Run `npx prisma-upgrade` again.

If you can't or don't want to execute the remaining SQL statements right now, you can
skip to the last step where the Upgrade CLI adds missing attributes to your Prisma ORM 2
schema that are not picked up by introspection.

Skip to the last step? [Y/n]?

要进行此修复,你需要运行三个 SQL 语句

  1. Post 表上创建新列 authorId。此列应为引用 User 表的 id 字段的外键
    ALTER TABLE `Post` ADD COLUMN `authorId` char(25) CHARACTER SET utf8 ;
    ALTER TABLE `Post` ADD CONSTRAINT author FOREIGN KEY (`authorId`) REFERENCES `User`(`id`);
  2. 编写一个 SQL 查询,读取 _PostToUser 关系表中的所有行,并为每一行
    1. 通过查找列 A 的值找到相应的 Post 记录
    2. 将列 B 的值作为 authorId 的值插入到该 Post 记录中
    UPDATE `Post`, `_PostToUser` SET `Post`.`authorId` = `_PostToUser`.B where `_PostToUser`.A = `Post`.`id`;
  3. 删除 _PostToUser 关系表
    DROP TABLE `_PostToUser`;

Fixing incorrect m-n relations with SQL

执行这些命令后,关系表列 B 中记录的用户 ID 值将迁移到新的 authorId 列。

5.2. 重新内省数据库以更新你的 Prisma schema

至此,你已经使用 Upgrade CLI 解决了 schema 不兼容性问题。现在可以通过输入 n 并按 RETURN 暂时退出 Upgrade CLI。

在本节中,你将通过另一轮内省更新你的 Prisma schema。这次,Prisma schema 之前的缺陷将得到解决,因为数据库 schema 已经过调整

npx prisma db pull

这次,生成的 Prisma schema 如下所示

schema.prisma
model User {
id String @id
name String
email String? @unique
jsonData Json?
role Role @default(CUSTOMER)
Post Post[]
Profile Profile?
}

model Post {
id String @id
createdAt DateTime @default(now())
updatedAt DateTime
title String
content String?
published Boolean @default(false)
authorId String?
User User? @relation(fields: [authorId], references: [id])
Category Category[] @relation(references: [id])
}

model Category {
id String @id
name String
Post Post[] @relation(references: [id])
}

model Profile {
bio String?
id String @id
user String? @unique
User User? @relation(fields: [user], references: [id])
}

enum Role {
ADMIN
CUSTOMER
}

此 schema 大部分问题已解决,但仍缺少以下内容

5.2. 向 Prisma 2 schema 添加缺失属性及其他 schema 修复

CLI 现在打印以下内容

➤ What happens next
As a last step, some final adjustments will be made to your Prisma ORM 2 schema
to carry over some Prisma ORM-level attributes that aren't picked up by introspection.

As a last step, some final adjustments will be made to your Prisma ORM 2.0
schema to carry over some Prisma ORM-level attributes that aren't picked
up by introspection.

Warning
Your current Prisma ORM 2.0 schema will be overwritten, so please
make sure you have a backup!

Are you ready? [Y/n]

至此,你可能已经运行了 CLI 打印的所有 SQL 语句,或者跳过了一部分。无论哪种情况,你现在都可以进行最后一步,让 Upgrade CLI 添加缺失的 Prisma ORM 2 属性。通常这些属性如下所示

  • @default(cuid()) 用于你的 @id 字段
  • @updatedAt 用于在 Prisma 1 中使用此属性的任何字段
  • @map@@map 作为 Prisma 1 中 @db@@db 的替代

在该步骤中,Upgrade CLI 还修复了过渡到 Prisma ORM 2 过程中发生的其他问题

  • 它确保在 Prisma 1 中两端都必需的 1-1 关系在你的 Prisma ORM 2 schema 中也必需
  • 它将关系字段重命名为与你在 Prisma 1 数据模型中相同的名称(即将推出

要应用这些更改,你可以重新运行 Upgrade CLI

npx prisma-upgrade prisma1/prisma.yml prisma/schema.prisma

如果你未解决所有 schema 不兼容性,Upgrade CLI 现在会打印剩余的 SQL 语句(以及用于迁移 ID 的语句)。此时你可以忽略它们,并在出现提示时持续输入 Y 并按 RETURN 继续执行最后一步。

如果你解决了所有 schema 不兼容性,将不会打印 SQL 语句,并且 Upgrade CLI 只会输出以下内容

$ npx prisma-upgrade prisma1/prisma.yml prisma/schema.prisma

➤ Next Steps

After you executed one or more of the previous SQL statements against your database,
please run the following two commands to refresh your Prisma ORM 2 schema and check
the changes.

1. Run `npx prisma db pull` again to refresh your Prisma ORM 2 schema.
2. Run `npx prisma-upgrade` again.

If you can't or don't want to execute the remaining SQL statements right now, you can
skip to the last step where the Upgrade CLI adds missing attributes to your Prisma ORM 2
schema that are not picked up by introspection.

Skip to the last step? [Y/n]?

再次输入 Y 并按 RETURN 确认。

Upgrade CLI 的最终提示现在要求你确认它将对你的 Prisma schema 进行的上述更改

➤ What happens next
As a last step, some final adjustments will be made to your Prisma ORM 2 schema
to carry over some Prisma ORM-level attributes that aren't picked up by introspection.

As a last step, some final adjustments will be made to your Prisma ORM 2.0
schema to carry over some Prisma ORM-level attributes that aren't picked
up by introspection.

Warning
Your current Prisma ORM 2.0 schema will be overwritten, so please
make sure you have a backup!

Are you ready? [Y/n]

最后一次,输入 Y 并按 RETURN 确认。

这是 Upgrade CLI 的最终输出

Updating prisma/schema.prisma...
Done updating prisma/schema.prisma!

✔ Congratulations, you're all set!

➤ Note
If you didn't execute all generated SQL commands against your database,
you can re-run the Upgrade CLI at any time.

Note that the Upgrade CLI doesn't resolve all of the schema incompatibilities
between Prisma 1 and Prisma ORM 2. If you want to resolve the remaining ones,
you can do so manually by following this guide:
https://pris.ly/d/upgrading-the-prisma-layer

➤ Next steps
Otherwise you can continue your upgrade process by installing Prisma Client 2:
npm install @prisma/client

You can find guides for different upgrade scenarios in the docs:
https://pris.ly/d/upgrade-from-prisma-1

5.3. 最终结果

最终版本的 Prisma schema 应该如下所示

schema.prisma
model User {
id String @id @default(cuid())
name String
email String? @unique
jsonData Json?
role Role @default(CUSTOMER)
Post Post[]
Profile Profile?
}

model Post {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String
content String?
published Boolean @default(false)
authorId String?
User User? @relation(fields: [authorId], references: [id])
Category Category[] @relation(references: [id])
}

model Profile {
id String @id @default(cuid())
bio String?
user String? @unique
User User? @relation(fields: [user], references: [id])
}

model Category {
id String @id @default(cuid())
name String
Post Post[] @relation(references: [id])
}

enum Role {
ADMIN
CUSTOMER
}

5.4. 重命名关系字段

你会注意到此版本的 Prisma ORM 2 schema 的一个特点是,所有关系字段都以它们各自的模型命名,例如

schema.prisma
model User {
Post Post[]
Profile Profile?
}

model Post {
User User? @relation(fields: [authorId], references: [id])
Category Category[] @relation(references: [id])
}

model Profile {
User User? @relation(fields: [user], references: [id])
}

model Category {
Post Post[] @relation(references: [id])
}

这并不理想,实际上你可以手动将它们全部重命名回之前的版本!

由于所有关系字段都是虚拟的,这意味着它们不会在数据库中体现,你可以随意命名它们。在此情况下,所有关系字段都是小写字母,有时会使用复数形式。

重命名后的样子如下所示

schema.prisma
model User {
posts Post[]
profile Profile?
}

model Post {
author User? @relation(fields: [authorId], references: [id])
categories Category[] @relation(references: [id])
}

model Profile {
user String? @unique
owner User? @relation(fields: [user], references: [id])
}

model Category {
posts Post[] @relation(references: [id])
}

注意: 对于 UserProfile 之间的 1 对 1 关系,无法将关系字段的旧名称设置为 user。这是因为会与已有的用于存储外键的 关系标量 字段发生命名冲突。在这种情况下,您可以选择一个不同的名称,或者通过 SQL 直接在数据库中重命名外键列。

5.5. 解决剩余的模式不兼容问题

有一些模式不兼容问题尚未由 Upgrade CLI 解决。此时,您还没有修复标量列表。您可以在模式不兼容问题页面上找到针对此问题和其他问题的推荐解决方案。

6. 安装并生成 Prisma Client

现在您的 Prisma ORM 2 模式已准备就绪,您可以使用以下命令安装 Prisma Client

npm install @prisma/client

7. 下一步

恭喜您,您现在已将您的 Prisma ORM 层升级到 Prisma ORM 2!接下来,您可以按照以下指南之一更新您的应用程序代码

额外内容: Prisma Client API 对比

本节包含 Prisma 1 和 Prisma ORM 2 的 Prisma Client API 的高级别并排比较。有关新的 Prisma Client API 的更多详细信息,您可以查阅 Prisma Client 文档。

读取单条记录

Prisma Client (v1)
const user = await prisma.user({ id: 1 })
Prisma Client (v2)
await prisma.user.findUnique({
where: { id: 1 },
})

读取记录列表

Prisma Client (v1)
const user = await prisma.users()
Prisma Client (v2)
await prisma.user.findMany()

过滤列表

Prisma Client (v1)
const users = await prisma.users({
where: {
name: 'Alice',
},
})
Prisma Client (v2)
await prisma.user.findMany({
where: {
name: 'Alice',
},
})

列表分页

Prisma Client (v1)
const posts = await prisma.posts({
skip: 5,
first: 10,
})
Prisma Client (v2)
await prisma.user.findMany({
skip: 5,
take: 10,
})

注意: 您可以在相关的 发布说明 或文档中的分页页面了解更多关于新的分页 API 的信息。

列表排序

Prisma Client (v1)
await prisma.posts({
orderBy: 'title_ASC',
})
Prisma Client (v2)
await prisma.posts({
orderBy: {
title: 'asc',
},
})

创建记录

Prisma Client (v1)
await prisma.createUser({
name: 'Alice',
})
Prisma Client (v2)
await prisma.user.create({
data: {
name: 'Alice',
},
})

更新记录

Prisma Client (v1)
await prisma.updateUser({
where: { id: 1 },
data: {
name: 'James',
email: 'james@prisma.io',
},
})
Prisma Client (v2)
await prisma.user.update({
where: { id: 1 },
data: {
name: 'James',
email: 'james@prisma.io',
},
})

删除记录

Prisma Client (v1)
await prisma.deleteUser({ id: 1 })
Prisma Client (v2)
await prisma.user.delete({
where: { id: 1 },
})

选择字段和加载关系

在 Prisma 1 中,选择特定字段和/或加载对象关系的唯一方法是使用基于字符串的 $fragment$graphql 函数。使用 Prisma ORM 2,现在可以通过使用 selectinclude 以一种清晰且类型安全的方式完成此操作。

这种方法的另一个好处是,您可以在任何 Prisma Client 查询中使用 selectinclude,例如 findUnique, findMany, create, update, delete, ...

Prisma Client (v1)
await prisma.user({ id: 1 }).$fragment(`
fragment NameAndEmail on User { id email }`
`)
Prisma Client (v2)
await prisma.user.findUnique({
where: { id: 1 },
select: {
id: true,
email: true,
},
})

例如,在 Prisma 1 中无法创建新记录并仅在返回的对象中检索 id。使用 Prisma ORM 2,您可以按如下方式实现此操作

await prisma.user.create({
data: {
name: 'Alice',
},
select: {
id: true,
},
})