升級 Prisma ORM 層
概觀
本頁面說明您的升級流程的第一步:取得您的 Prisma 1 設定並將其升級至 Prisma ORM 2。具體而言,您將學習如何
- 將 Prisma ORM 2 CLI 新增為開發依賴項
- 建立您的 Prisma ORM 2 schema
- 決定您的連線網址並連線至您的資料庫
- 內省您的資料庫(到目前為止使用 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 以防止版本衝突。
您現在可以使用 prisma
CLI 的本機安裝,方法是在其前面加上 npx
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 檔案,用於設定您的資料庫 連線網址。
您的初始 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 中,此資訊現在透過產生器區塊在 Prisma schema 內部指定。
請注意:與 Prisma 1 不同,Prisma Client 2.0 的 TypeScript 和 JavaScript 變體使用相同的產生器,稱為
prisma-client-js
。index.d.ts
中產生的類型始終包含在內,即使在純 JavaScript 專案中也是如此。即使不使用 TypeScript,這也能啟用 VS Code 中的自動完成等功能。
3. 決定您的連線網址並連線至您的資料庫
在 Prisma 1 中,資料庫連線是在 Docker Compose 檔案中設定的,該檔案用於啟動 Prisma ORM 伺服器。然後,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
內資料來源區塊上的 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
檔案內設定連線網址。
假設您用於部署 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"
在「連線網址」頁面了解更多資訊。
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
而不是Json
User
上的role
欄位類型為String
而不是Role
,role 的列舉定義完全遺失
雖然這些不一致實際上並不會影響您在 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
類型,目前它們表示為純字串(例如 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;
您現在可以使用命令列用戶端或 GUI(如 Postico)針對您的資料庫執行這些 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 設定。文件將會更新以儘快反映這一點。
您現在可以使用命令列用戶端或 GUI(如 Postico)針對您的資料庫執行這些 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;
您現在可以使用命令列用戶端或 GUI(如 Postico)針對您的資料庫執行這些 SQL 語句
5.1.5. 透過新增 UNIQUE
約束修正 1-1 關聯
現在,該工具將協助您透過將 UNIQUE
約束新增至資料庫中名為 user 的外鍵欄位(以 Prisma 1 資料模型中的關聯欄位命名),將 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");
您現在可以使用命令列用戶端或 GUI(如 Postico)針對您的資料庫執行這些 SQL 語句
5.1.6. 修正 CUID 長度不符
請注意:即使您已變更底層資料庫中的欄位類型,這些 SQL 語句仍會繼續出現在升級 CLI 中。這是目前升級 CLI 中的一個限制。
最後,該工具將協助您透過將 UNIQUE
約束新增至資料庫中名為 user 的外鍵欄位(以 Prisma 1 資料模型中的關聯欄位命名),將目前類型為 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);
您現在可以使用命令列用戶端或 GUI(如 Postico)針對您的資料庫執行這些 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 關聯,以及目前僅以 m-n 關聯形式存在於您的新 Prisma ORM 2 schema 中的關聯。具體而言,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 屬性。通常這些屬性如下
@id
欄位的@default(cuid())
- Prisma 1 中任何使用此屬性的欄位的
@updatedAt
@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 不相容性
有一些 schema 不相容性尚未由升級 CLI 解決。此時,您仍然尚未修正純量列表。您可以在「Schema 不相容性」頁面找到針對此問題和其他問題的建議解決方案。
6. 安裝並產生 Prisma Client
現在您已準備好 Prisma ORM 2 schema,您可以使用以下命令安裝 Prisma Client
npm install @prisma/client
7. 後續步驟
恭喜,您現在已將您的 Prisma ORM 層升級至 Prisma ORM 2!從這裡開始,您可以繼續使用以下指南之一更新您的應用程式程式碼
- 從舊版 Nexus 升級至新版 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,
},
})