升級 Prisma ORM 層 (PostgreSQL)
概覽
本頁面解釋了您升級過程的第一步:將 Prisma 1 配置升級到 Prisma ORM 2。具體來說,您將學習如何
- 新增 Prisma ORM 2 CLI 作為開發依賴
- 建立您的 Prisma ORM 2 schema
- 確定您的連線 URL 並連線到資料庫
- 內省您的資料庫(目前由 Prisma 1 管理)
- 使用 Prisma 1 升級 CLI 解決新 Prisma ORM 2 資料模型中的 schema 不相容性
- 安裝並生成 Prisma Client
完成這些步驟後,您可以繼續閱讀下一份指南,其中解釋瞭如何升級應用程式層以使用 Prisma Client 進行資料庫查詢。
注意:在升級過程中,獲取資料庫的圖形檢視會很有幫助。因此,建議使用圖形資料庫客戶端連線到資料庫,例如 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 的 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 如下所示
// 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 Client 語言變體。使用 Prisma ORM 2 時,此資訊現在透過 generator 塊在 Prisma schema 內部指定。
注意:與 Prisma 1 不同,Prisma Client 2.0 的 TypeScript 和 JavaScript 變體使用相同的生成器,名為
prisma-client-js。生成的型別在index.d.ts中始終包含,即使在純 JavaScript 專案中也是如此。這使得即使不使用 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"。
切換程式碼塊中的選項卡以檢視這兩個示例
- 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://: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://: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 schema(請注意,模型已重新排序以匹配 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 schema,但它缺少其 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而不是JsonUser上的role欄位型別為String而不是Role,enum定義完全缺失
儘管這些不一致實際上不會影響您在 Prisma Client API 中可用的“功能集”,但它們會讓您失去以前存在的一些約束/保證。
例如,Prisma ORM 現在無法保證 User 最多連線到一個 Profile,因為表之間的關係在內省期間被識別為 1-n,所以一個 User 記錄現在可以連線到多個 Profile 記錄。
另一個問題是,您可以為 jsonData 和 role 欄位儲存任何文字,無論它是否是有效的 JSON 或代表 Role 列舉的值。
要了解有關這些不一致的更多資訊,請檢視Schema 不相容性頁面。
接下來,我們將透過 Prisma schema 升級 CLI 逐一解決這些不相容性。
5. 使用 Prisma schema 升級 CLI 解決 schema 不相容性
Prisma 1 升級 CLI 是一個互動式工具,可幫助您升級 Prisma schema 並解決上述大多數不一致問題。
Prisma 1 升級 CLI 主要分兩個階段工作
- 透過純 SQL 修復資料庫 schema
- 向 Prisma ORM 2 schema 新增缺失屬性和其他 schema 修復
在第一階段,它將生成並列印一些 SQL 語句,您應該針對您的資料庫執行這些語句以調整資料庫 schema。您可以執行所有語句或其中一部分,然後再繼續第二階段。
在第二階段,您無需手動執行任何操作。升級 CLI 將透過新增某些 Prisma ORM 級別屬性(如 @default(cuid)) 或 @updatedAt)、調整關係欄位的名稱以匹配 Prisma 1 資料模型中的名稱,並確保 Prisma 1 資料模型中在兩邊都必需的 1-1 關係在 Prisma ORM 2 schema 中也必需來更改您的 Prisma schema。
請注意,您可以在過程中的任何時候重新開始,並從第二階段回到第一階段。
在此圖中,綠色區域顯示第一階段,藍色區域顯示第二階段。請注意,您可以在階段之間選擇性地執行 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 語句被分類到多個“桶”中,所有這些都旨在解決特定的schema 不相容性
- 修復帶有 ENUM 資料型別的列
- 向資料庫新增缺失的
DEFAULT約束 - 修復帶有 JSON 資料型別的列
- 在 Prisma 2 中複製
@createdAt行為 - 透過新增
UNIQUE約束脩復 1-1 關係
下一步,您可以開始向資料庫傳送 SQL 語句。請注意,所有這些更改都是非破壞性的,您將能夠繼續將 Prisma 1 與 Prisma ORM 2 並排使用。
以下各節分別涵蓋了要傳送到資料庫的不同型別的 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
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 幫助您解決資料庫中未表示預設值的問題,透過生成 SQL 語句將相應的 DEFAULT 約束直接新增到資料庫。
在這種情況下,缺少兩個 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 列印了有關重大更改的說明,則您的資料庫 schema 需要進行一些調整,這些調整將破壞 Prisma 1 相容性以實現完全最佳化。
如果沒有檢測到重大更改,您可以跳到第 5.2 節
根據您的升級策略,您現在可以執行這些更改,或者跳到升級 CLI 的下一階段
- 如果您遵循逐步並排升級策略,請暫時不要執行這些更改,因為它們會破壞您的 Prisma 1 設定。在這種情況下,您可以鍵入 n 並按下 RETURN 繼續升級 CLI 的下一階段。
- 如果您遵循一次性升級策略,您現在可以執行這些更改。在這種情況下,請鍵入 Y 並按下 RETURN 繼續。
5.2. 透過純 SQL 修復資料庫 schema (破壞性)
在本節中,您將解決破壞 Prisma 1 設定的 schema 不相容性。如果您的專案中仍在執行 Prisma 1,請勿執行這些更改!
5.2.1. 修復不正確的 m-n 關係
現在,升級 CLI 幫助您修復 Prisma 1 使用關係表表示的所有 1-1 和 1-n 關係,以及在新的 Prisma ORM 2 schema 中目前僅存在為 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 schema
此時,您已經使用升級 CLI 解決了 schema 不相容性。您現在可以輸入 n 並按下 RETURN 暫時退出升級 CLI。
在本節中,您將透過另一次內省來更新您的 Prisma schema。這次,Prisma schema 之前的缺陷將得到解決,因為資料庫 schema 已經調整
npx prisma db pull
這次,生成的 Prisma schema 如下所示
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 語句,要麼跳過了一些。無論哪種方式,您現在都可以繼續執行最後一步,讓升級 CLI 新增缺失的 Prisma ORM 2 屬性。通常這些是以下內容
@default(cuid())用於您的@id欄位@updatedAt用於 Prisma 1 中使用此屬性的任何欄位@map和@@map作為 Prisma 1 中@db和@@db的替代
在此步驟中,升級 CLI 還修復了向 Prisma ORM 2 過渡中出現的其他問題
- 它確保 Prisma 1 中在兩邊都必需的 1-1 關係在您的 Prisma ORM 2 schema 中也必需
- 它將關係欄位重新命名為與 Prisma 1 資料模型中相同的名稱(即將推出)
要應用這些更改,您可以重新執行升級 CLI
npx prisma-upgrade prisma1/prisma.yml prisma/schema.prisma
如果您沒有解決所有 schema 不相容性,升級 CLI 現在會列印剩餘的 SQL 語句(以及用於遷移 ID 的語句)。此時您可以忽略它們,並透過在提示時持續輸入 Y 並按下 RETURN 來繼續執行最後一步。
如果您解決了所有 schema 不相容性,則不會列印任何 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 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 確認。
這是升級 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 的最終版本應如下所示
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 的一件事是,所有關係欄位都以其各自的模型命名,例如
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. 解決剩餘的 schema 不相容性
升級 CLI 尚未解決一些 schema 不相容性。此時您仍未修復標量列表。您可以在Schema 不相容性頁面上找到此問題及其他問題的推薦解決方法。
6. 安裝並生成 Prisma Client
現在您的 Prisma ORM 2 schema 已準備就緒,您可以使用以下命令安裝 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: 'james@prisma.io',
},
})
await prisma.user.update({
where: { id: 1 },
data: {
name: 'James',
email: 'james@prisma.io',
},
})
刪除記錄
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,
},
})