升级 Prisma ORM 层
概述
本页解释你的升级过程的第一步:获取你的 Prisma 1 配置并将其升级到 Prisma ORM 2。具体来说,你将学习如何
- 将 Prisma ORM 2 CLI 添加为开发依赖项
- 创建你的 Prisma ORM 2 模式
- 确定你的连接 URL 并连接到你的数据库
- 内省你的数据库(到目前为止使用 Prisma 1 管理)
- 使用 Prisma 1 升级 CLI 来解决新的 Prisma ORM 2 数据模型中的模式不兼容性
- 安装并生成 Prisma 客户端
完成这些步骤后,你可以继续下一份指南,该指南解释了如何升级应用程序层以使用 Prisma 客户端进行数据库查询。
注意:在升级过程中,获取数据库的图形视图可能会有所帮助。因此,建议使用图形数据库客户端连接到你的数据库,例如 TablePlus 或 Postico。
1. 安装 Prisma ORM 2 CLI
Prisma ORM 2 CLI 可作为 npm 上的 prisma
包使用,并通过 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(例如 1.30)的 CLI 版本,你可以按如下方式安装它
# installs v1.30 of the Prisma 1 CLI
npm uninstall -g [email protected]
npm install [email protected] --save-dev
你现在可以按如下方式调用它
npx prisma
2. 创建你的 Prisma ORM 2 模式
在本指南中,你将首先使用 prisma init
命令创建一个新的 Prisma 模式,然后使用内省用数据模型“填充”它。
运行以下命令以创建你的 Prisma 模式(请注意,如果你的目录中已经有一个名为 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 模式,指定了数据源、生成器和数据模型(请注意,数据模型尚不存在,它将通过内省生成)。.env
:一个dotenv 文件,用于配置你的数据库连接 URL。
你的初始 Prisma 模式如下所示
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
使用 Prisma 1,你可以在 prisma.yml
中指定要使用的 Prisma 客户端的语言变体。使用 Prisma ORM 2,此信息现在通过 generator
块在 Prisma 模式内指定。
注意:与 Prisma 1 不同,Prisma 客户端 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 客户端应用程序代码的所有数据库请求。该 HTTP 端点在你的 prisma.yml
中指定。
使用 Prisma ORM 2,HTTP 层不再公开,Prisma 客户端 2.0 配置为“直接”针对数据库运行请求(也就是说,请求由 Prisma ORM 的查询引擎代理,但不再有额外的服务器)。
因此,下一步你需要告诉 Prisma ORM 2 你使用哪种数据库(MySQL 或 PostgreSQL)以及它位于何处。
首先,你需要确保 schema.prisma
内的 datasource
块上的 provider
字段配置为使用正确的数据库
- 如果你使用 PostgreSQL,则需要在
provider
字段中定义值"postgresql"
。 - 如果你使用 MySQL,则需要在
provider
字段中定义值"mysql"
。
在代码块中使用选项卡切换,以查看两者的示例
- PostgreSQL
- MySQL
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
设置 provider
字段后,你可以继续在 .env
文件中配置连接 URL。
假设你用于部署 Prisma ORM 服务器的 Docker Compose 文件中的数据库配置如下所示
PRISMA_CONFIG: |
port: 4466
databases:
default:
connector: postgres
host: postgres
port: 5432
user: prisma
password: prisma
还假设你在 prisma.yml
中的 endpoint
配置如下所示
endpoint: http://127.0.0.1:4466/myproject/dev
根据这些连接详细信息,你需要按如下方式在 .env
文件中配置 DATABASE_URL
环境变量
DATABASE_URL="postgresql://janedoe:randompassword@localhost:5432/prisma?schema=myproject$dev"
请注意,schema
参数通常由你的服务名称和服务阶段组成(它们是 prisma.yml
中 endpoint
的一部分),并用 $
字符分隔。
有时,prisma.yml
中没有指定服务名称和阶段。
endpoint: http://127.0.0.1:4466/
在这种情况下,必须按如下方式指定 schema
DATABASE_URL="postgresql://janedoe:randompassword@localhost:5432/prisma?schema=default$default"
请访问连接 URL 页面了解更多信息。
4. 内省你的数据库
为了本指南的目的,我们将使用以下 Prisma 1 数据模型(选择下面的 SQL 选项卡,查看该数据模型在 SQL 中的映射方式)
- Prisma 1 数据模型
- 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
}
CREATE TABLE"User" (
id character varying(25) PRIMARY KEY,
email text,
name text NOT NULL,
role text NOT NULL,
"jsonData" text
);
CREATE UNIQUE INDEX "User_pkey" ON"User"(id text_ops);
CREATE UNIQUE INDEX "default$default.User.email._UNIQUE" ON"User"(email text_ops);
CREATE TABLE"Post" (
id character varying(25) PRIMARY KEY,
title text NOT NULL,
published boolean NOT NULL,
"createdAt" timestamp(3) without time zone NOT NULL,
"updatedAt" timestamp(3) without time zone NOT NULL,
content text
);
CREATE UNIQUE INDEX "Post_pkey" ON"Post"(id text_ops);
CREATE TABLE"Profile" (
id character varying(25) PRIMARY KEY,
bio text,
user character varying(25) REFERENCES"User"(id) ON DELETE SET NULL
);
CREATE UNIQUE INDEX "Profile_pkey" ON"Profile"(id text_ops);
CREATE TABLE"Category" (
id character varying(25) PRIMARY KEY,
name text NOT NULL
);
CREATE UNIQUE INDEX "Category_pkey" ON"Category"(id text_ops);
CREATE TABLE"_PostToUser" (
"A" character varying(25) NOT NULL REFERENCES"Post"(id) ON DELETE CASCADE,
"B" character varying(25) NOT NULL REFERENCES"User"(id) ON DELETE CASCADE
);
CREATE UNIQUE INDEX "_PostToUser_AB_unique" ON"_PostToUser"("A" text_ops,"B" text_ops);
CREATE INDEX "_PostToUser_B" ON"_PostToUser"("B" text_ops);
CREATE TABLE"_CategoryToPost" (
"A" character varying(25) NOT NULL REFERENCES"Category"(id) ON DELETE CASCADE,
"B" character varying(25) NOT NULL REFERENCES"Post"(id) ON DELETE CASCADE
);
CREATE UNIQUE INDEX "_CategoryToPost_AB_unique" ON"_CategoryToPost"("A" text_ops,"B" text_ops);
CREATE INDEX "_CategoryToPost_B" ON"_CategoryToPost"("B" text_ops);
请注意,此数据模型有三个关系
- 1-1:
User
↔Profile
- 1-n:
User
↔Post
(通过_PostToUser
关系表维护) - m-n:
Post
↔Category
(通过_CategoryToPost
关系表维护)
现在你可以使用以下命令对你的数据库运行 Prisma ORM 的内省功能
npx prisma db pull
以下是调用 db pull
时发生的图形说明
对于上面的 Prisma 1 数据模型,这将产生以下 Prisma ORM 2 模式(请注意,模型已重新排序以匹配 Prisma 1 数据模型的初始顺序)
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 模式,但它缺少一些属于其 Prisma 1 等效项的功能
Post
上的createdAt
和updatedAt
字段没有自动生成的日期值User
上的role
字段没有默认值Post
上的published
字段没有默认值
此外,还存在一些不一致之处,这会导致 Prisma Client API 不够惯用/符合人体工程学
User
↔Profile
是 1-n 关系,而不是 1-1 关系User
↔Post
是 m-n 关系,而不是 1-n 关系- 关系字段是大写的(例如,
User
上的Profile
和Post
) User
上的jsonData
字段的类型是String
,而不是Json
User
上的role
字段的类型是String
,而不是Role
,角色枚举的定义完全缺失
虽然这些不一致实际上不会影响你的 Prisma Client API 中可用的“功能集”,但它们会让你失去以前存在的某些约束/保证。
例如,由于表之间的关系在内省期间被识别为 1-n,因此 Prisma ORM 现在不能保证一个 User
最多连接到一个 Profile
,因此一个 User
记录现在可能连接到多个 Profile
记录。
另一个问题是,你可以为 jsonData
和 role
字段存储任何文本,而不管它是否为有效的 JSON 或表示 Role
枚举的值。
要了解有关这些不一致的更多信息,请查看模式不兼容性页面。
在下文中,我们将使用 Prisma 模式升级 CLI 逐一解决这些不兼容性。
5. 使用 Prisma 模式升级 CLI 解决模式不兼容性
Prisma 1 升级 CLI是一个交互式工具,可帮助你升级 Prisma 模式并解决上面列出的大多数不一致之处。
Prisma 1 升级 CLI 分两个主要阶段工作
- 通过纯 SQL 修复数据库模式
- 将缺失的属性添加到 Prisma ORM 2 模式和其他模式修复
在第一阶段,它将生成并打印一些 SQL 语句,你应该针对数据库运行这些语句以调整数据库模式。你可以在继续第二阶段之前运行所有语句或其中一部分语句。
在第二阶段,你无需手动执行任何操作。升级 CLI 将通过添加某些 Prisma ORM 级别的属性(如 @default(cuid)
或 @updatedAt
)来更改你的 Prisma 模式,调整关系字段的名称以匹配你的 Prisma 1 数据模型中的名称,并确保 Prisma 1 数据模型中双方都需要的 1-1 关系在 Prisma ORM 2 模式中也是必需的。
请注意,你可以在此过程中的任何时间重新开始,并从第二阶段返回到第一阶段。
在此图中,绿色区域显示第一阶段,蓝色区域显示第二阶段。请注意,你也可以选择在阶段之间运行 prisma db pull
,以更新你的 Prisma ORM 数据模型
要使用升级 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
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
CREATE TYPE "default$default"."Role" AS ENUM ('ADMIN', 'CUSTOMER');
ALTER TABLE "default$default"."User" ALTER COLUMN "role" SET DATA TYPE "default$default"."Role" using "role"::"default$default"."Role";
Add missing `DEFAULT` constraints to the database
https://pris.ly/d/schema-incompatibilities#default-values-arent-represented-in-database
ALTER TABLE "default$default"."User" ALTER COLUMN "role" SET DEFAULT 'CUSTOMER';
ALTER TABLE "default$default"."Post" ALTER COLUMN "published" SET DEFAULT false;
Fix columns with JSON data types
https://pris.ly/d/schema-incompatibilities#json-type-is-represented-as-text-in-database
ALTER TABLE "default$default"."User" ALTER COLUMN "jsonData" SET DATA TYPE JSONB USING "jsonData"::TEXT::JSONB;
Replicate `@createdAt` behavior in Prisma ORM 2
https://pris.ly/d/schema-incompatibilities#createdat-isnt-represented-in-database
ALTER TABLE "default$default"."Post" ALTER COLUMN "createdAt" SET 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 "default$default"."Profile" ADD UNIQUE ("user");
Migrate IDs from varchar(25) to varchar(30)
https://pris.ly/d/schema-incompatibilities#mismatching-cuid-length
ALTER TABLE "default$default"."Category" ALTER COLUMN "id" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."Post" ALTER COLUMN "id" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."Profile" ALTER COLUMN "id" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."Profile" ALTER COLUMN "user" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."User" ALTER COLUMN "id" SET DATA TYPE character varying(30);
➤ 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 语句被分为多个“存储桶”,所有这些都旨在解决特定的模式不兼容性
- 修复具有 ENUM 数据类型的列
- 将缺失的
DEFAULT
约束添加到数据库 - 修复具有 JSON 数据类型的列
- 在 Prisma 2 中复制
@createdAt
行为 - 通过添加
UNIQUE
约束来修复 1-1 关系
下一步,你可以开始将 SQL 语句发送到你的数据库。请注意,所有这些更改都是非破坏性的,你将能够并行使用 Prisma 1 和 Prisma ORM 2。
接下来的章节将分别介绍要发送到你的数据库的不同类型的 SQL 语句。
5.1. 通过纯 SQL 修复数据库模式(非破坏性)
在本节中,我们将逐步介绍打印的 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
CREATE TYPE "default$default"."Role" AS ENUM ('ADMIN', 'CUSTOMER');
ALTER TABLE "default$default"."User" ALTER COLUMN "role" SET DATA TYPE "default$default"."Role" using "role"::"default$default"."Role";
⚠️ 警告:如果你正在并行运行 Prisma 1 和 Prisma ORM 2,则这些SQL 语句将破坏你的 Prisma 1 设置。文档将很快更新以反映这一点。
继续并立即针对你的数据库运行这些语句。
5.1.2. 将缺失的 DEFAULT
约束添加到数据库
接下来,升级 CLI 通过生成将各自的 DEFAULT
约束直接添加到数据库的 SQL 语句,帮助你解决默认值未在数据库中表示的问题。
在这种情况下,缺少工具建议的两个 DEFAULT
约束
Add missing `DEFAULT` constraints to the database
https://pris.ly/d/schema-incompatibilities#default-values-arent-represented-in-database
ALTER TABLE "default$default"."User" ALTER COLUMN "role" SET DEFAULT 'CUSTOMER';
ALTER TABLE "default$default"."Post" ALTER COLUMN "published" SET DEFAULT false;
你现在可以使用命令行客户端或 Postico 等 GUI 针对你的数据库运行这些 SQL 语句
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 "default$default"."User" ALTER COLUMN "jsonData" TYPE JSON USING "jsonData"::json;
⚠️ 警告:如果你正在并行运行 Prisma 1 和 Prisma ORM 2,则这些SQL 语句将破坏你的 Prisma 1 设置。文档将很快更新以反映这一点。
你现在可以使用命令行客户端或 Postico 等 GUI 针对你的数据库运行这些 SQL 语句
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 "default$default"."Post" ALTER COLUMN "createdAt" SET DEFAULT CURRENT_TIMESTAMP;
你现在可以使用命令行客户端或 Postico 等 GUI 针对你的数据库运行这些 SQL 语句
5.1.5. 通过添加 UNIQUE
约束来修复 1-1 关系
现在,该工具将通过在数据库中名为 user
的外键列(在 Prisma 1 数据模型中以关系字段命名)上添加 UNIQUE
约束,帮助你将 User
↔ Profile
之间的当前 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 "default$default"."Profile" ADD UNIQUE ("user");
你现在可以使用命令行客户端或 Postico 等 GUI 针对你的数据库运行这些 SQL 语句
5.1.6. 修复 CUID 长度不匹配
注意:即使你已更改底层数据库中的列类型,这些 SQL 语句仍会继续在升级 CLI 中显示。这是当前升级 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
ALTER TABLE "default$default"."Category" ALTER COLUMN "id" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."Post" ALTER COLUMN "id" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."Profile" ALTER COLUMN "id" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."Profile" ALTER COLUMN "user" SET DATA TYPE character varying(30);
ALTER TABLE "default$default"."User" ALTER COLUMN "id" SET DATA TYPE character varying(30);
你现在可以使用命令行客户端或 Postico 等 GUI 针对你的数据库运行这些 SQL 语句
5.1.7. 检测到重大更改
如果升级 CLI 已打印关于重大更改的说明,你的数据库模式需要进行一些调整,这些调整将破坏 Prisma 1 兼容性,以便完全优化。
如果没有检测到重大更改,你可以跳到第 5.2 节
根据你的升级策略,你可以立即执行这些更改,也可以跳到升级 CLI 的下一阶段
- 如果您正在遵循渐进式并排升级策略,请不要执行这些更改,因为它们会破坏您的 Prisma 1 设置。在这种情况下,您可以键入 n 并按 RETURN 继续升级 CLI 的下一阶段。
- 如果您正在遵循一次性升级策略,则可以立即执行这些更改。在这种情况下,请键入 Y 并按 RETURN 继续。
5.2. 通过纯 SQL 修复数据库模式(破坏性更改)
在本节中,您将解决破坏 Prisma 1 设置的模式不兼容问题。如果您仍在项目中运行 Prisma 1,请不要执行这些更改!
5.2.1. 修复不正确的 m-n 关系
现在,升级 CLI 会帮助您修复所有 Prisma 1 用关系表表示的 1-1 和 1-n 关系,以及那些在您的新 Prisma ORM 2 模式中当前仅作为 m-n 关系存在的关系。具体来说,User
↔ Post
关系就是这种情况,它目前被定义为 m-n,但实际上应该是 1-n 关系。
要修复此问题,您需要执行以下迁移
- 在
Post
上创建一个新的外键列,以直接链接到User
表。 - 将关系表中的外键值迁移到
Post
上新的外键列中。 - 删除关系表。
这些说明现在由 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 "default$default"."Post" ADD COLUMN "authorId" character varying(25) ;
ALTER TABLE "default$default"."Post" ADD CONSTRAINT "author" FOREIGN KEY ("authorId") REFERENCES "default$default"."User"("id");
UPDATE "default$default"."Post" SET "authorId" = "default$default"."_PostToUser"."B" FROM "default$default"."_PostToUser" WHERE "default$default"."_PostToUser"."A" = "default$default"."Post"."id";
DROP TABLE "default$default"."_PostToUser";
➤ 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]?
对于此修复,您需要运行三个 SQL 语句
- 在
Post
表上创建新列authorId
。此列应该是一个外键,引用User
表的id
字段ALTER TABLE `Post` ADD COLUMN `authorId` VARCHAR(25);
ALTER TABLE `Post` ADD FOREIGN KEY (`authorId`) REFERENCES `User` (`id`); - 编写一个 SQL 查询,读取
_PostToUser
关系表中的所有行,并针对每一行- 通过查找列
A
中的值来查找相应的Post
记录 - 将列
B
中的值作为authorId
的值插入到该Post
记录中
UPDATE Post, _PostToUser
SET Post.authorId = _PostToUser.B
WHERE Post.id = _PostToUser.A - 通过查找列
- 删除
_PostToUser
关系表DROP TABLE `_PostToUser`;
执行这些命令后,关系表列 B
中记录的用户 ID 值将迁移到新的 authorId
列。
5.2. 重新内省您的数据库以更新您的 Prisma 模式
此时,您已使用升级 CLI 解决了模式不兼容问题。您现在可以通过键入 n 并按 RETURN 退出升级 CLI。
在本节中,您将使用另一轮内省来更新您的 Prisma 模式。这一次,Prisma 模式的先前缺陷将被解决,因为数据库模式已调整
npx prisma db pull
这次,生成的 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
}
此模式已解决大多数问题,但仍缺少以下内容
5.2. 将缺少的属性添加到 Prisma 2 模式和其他模式修复
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 语句,要么跳过了一些语句。无论哪种方式,您现在都可以继续最后一步,让升级 CLI 添加缺少的 Prisma ORM 2 属性。通常这些属性包括以下内容
- 您的
@id
字段的@default(cuid())
- Prisma 1 中使用此属性的任何字段的
@updatedAt
@map
和@@map
作为 Prisma 1 中@db
和@@db
的替代品
在这一步中,升级 CLI 还会修复过渡到 Prisma ORM 2 时发生的其他问题
- 它确保 Prisma 1 中双方都需要的 1-1 关系在您的 Prisma ORM 2 模式中也是必需的
- 它将关系字段重命名为它们在您的 Prisma 1 数据模型中拥有的相同名称 (即将推出)
要应用这些更改,您可以重新运行升级 CLI
npx prisma-upgrade prisma1/prisma.yml prisma/schema.prisma
如果您没有解决所有模式不兼容问题,则升级 CLI 现在会打印剩余的 SQL 语句(以及用于迁移 ID 的语句)。您现在可以忽略它们,并在出现提示时通过连续键入 Y 并按 RETURN 继续最后一步。
如果您已解决所有模式不兼容问题,则不会打印 SQL 语句,并且升级 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 进行确认。
升级 CLI 的最后提示现在会要求您确认它将对您的 Prisma 模式进行的上述更改
➤ 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 进行确认。
这是升级 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 模式的最终版本应如下所示
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 模式的一件事是,所有关系字段都以其各自的模型命名,例如
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])
}
这并不理想,事实上您可以手动将它们全部重命名为以前的版本!
因为所有关系字段都是虚拟的,这意味着它们不会在数据库中体现,所以您可以随意命名它们。在这种情况下,所有关系字段都为小写,有时为复数。
这是重命名后的样子
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])
}
注意:对于
User
和Profile
之间的 1-1 关系,无法为关系字段设置旧名称user
。这是因为与已存在的保存外键的关系标量字段存在命名冲突。在这种情况下,您可以选择不同的名称,或者通过 SQL 直接在数据库中重命名外键列。
5.5. 解决剩余的模式不兼容问题
升级 CLI 尚未解决一些模式不兼容问题。此时,您仍然没有修复标量列表。您可以在模式不兼容页面上找到针对此问题和其他问题的建议解决方法。
6. 安装并生成 Prisma Client
现在您已经准备好 Prisma ORM 2 模式,您可以使用以下命令安装 Prisma Client
npm install @prisma/client
7. 后续步骤
恭喜,您现在已将 Prisma ORM 层升级到 Prisma ORM 2!从这里开始,您可以继续使用以下指南之一来更新您的应用程序代码
- 旧到新 Nexus:如果您当前正在使用 GraphQL Nexus 运行 Prisma 1,请选择本指南。
- prisma-binding 到 Nexus:如果您当前正在使用
prisma-binding
运行 Prisma 1,并且想要升级到 Nexus(和 TypeScript),请选择本指南。 - prisma-binding 到 SDL-first:如果您当前正在使用
prisma-binding
运行 Prisma 1,并且想要升级到 SDL-first GraphQL 服务器,请选择本指南。 - REST API:如果您当前正在使用 Prisma Client 1 运行 Prisma 1 并正在构建 REST API,请选择本指南。
奖励:Prisma Client API 比较
本节包含 Prisma 1 和 Prisma ORM 2 的 Prisma Client API 的高级并排比较。有关新的 Prisma Client API 的更多详细信息,您可以浏览Prisma Client 文档。
读取单个记录
const user = await prisma.user({ id: 1 })
await prisma.user.findUnique({
where: { id: 1 },
})
读取记录列表
const user = await prisma.users()
await prisma.user.findMany()
筛选列表
const users = await prisma.users({
where: {
name: 'Alice',
},
})
await prisma.user.findMany({
where: {
name: 'Alice',
},
})
分页列表
const posts = await prisma.posts({
skip: 5,
first: 10,
})
await prisma.user.findMany({
skip: 5,
take: 10,
})
列表排序
await prisma.posts({
orderBy: 'title_ASC',
})
await prisma.posts({
orderBy: {
title: 'asc',
},
})
创建记录
await prisma.createUser({
name: 'Alice',
})
await prisma.user.create({
data: {
name: 'Alice',
},
})
更新记录
await prisma.updateUser({
where: { id: 1 },
data: {
name: 'James',
email: '[email protected]',
},
})
await prisma.user.update({
where: { id: 1 },
data: {
name: 'James',
email: '[email protected]',
},
})
删除记录
await prisma.deleteUser({ id: 1 })
await prisma.user.delete({
where: { id: 1 },
})
选择字段 & 加载关系
在 Prisma 1 中,选择特定字段和/或加载对象关系的唯一方法是使用基于字符串的 $fragment
和 $graphql
函数。在 Prisma ORM 2 中,现在可以使用 select
和 include
以一种清晰且类型安全的方式完成此操作。
这种方法的另一个好处是您可以在任何 Prisma Client 查询中使用 select
和 include
,例如 findUnique()
、findMany
、create
、update
、delete
等。
await prisma.user({ id: 1 }).$fragment(`
fragment NameAndEmail on User { id email }`
`)
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,
},
})