自定義遷移
在某些情況下,你需要在應用遷移檔案之前對其進行編輯。例如,為了在不丟失資料的情況下更改一對一關係的方向(將外部索引鍵從一側移動到另一側),你需要將資料移動作為遷移的一部分——這些 SQL 不屬於預設遷移,必須手動編寫。
本指南解釋瞭如何編輯遷移檔案,並給出了一些你可能需要這樣做的用例示例。
如何編輯遷移檔案
要在應用遷移檔案之前對其進行編輯,一般步驟如下:
-
進行需要自定義 SQL 的 schema 更改(例如,為了保留現有資料)
-
使用以下命令建立草稿遷移:
npx prisma migrate dev --create-only -
修改生成的 SQL 檔案。
-
透過執行以下命令應用修改後的 SQL:
npx prisma migrate dev
示例:重新命名欄位
預設情況下,在 schema 中重新命名欄位會導致遷移執行以下操作:
CREATE新列(例如,fullname)DROP現有列(例如,name)及其中的資料
要實際**重新命名**欄位並避免在生產環境中執行遷移時資料丟失,你需要在將生成的遷移 SQL 應用到資料庫之前對其進行修改。考慮以下 schema 片段——biograpy 欄位拼寫錯誤。
model Profile {
id Int @id @default(autoincrement())
biograpy String
userId Int @unique
user User @relation(fields: [userId], references: [id])
}
將 biograpy 欄位重新命名為 biography
-
在 schema 中重新命名欄位
model Profile {
id Int @id @default(autoincrement())
biograpy String
biography String
userId Int @unique
user User @relation(fields: [userId], references: [id])
} -
執行以下命令以建立**草稿遷移**,你可以在將其應用到資料庫之前進行編輯:
npx prisma migrate dev --name rename-migration --create-only -
按所示編輯草稿遷移,將
DROP/DELETE更改為單個RENAME COLUMN- 之前
- 之後
./prisma/migrations/20210308092620_rename_migration/migration.sqlALTER TABLE "Profile" DROP COLUMN "biograpy",
ADD COLUMN "biography" TEXT NOT NULL;./prisma/migrations/20210308092620_rename_migration/migration.sqlALTER TABLE "Profile"
RENAME COLUMN "biograpy" TO "biography"對於 SQL Server,你應該使用儲存過程
sp_rename而不是ALTER TABLE RENAME COLUMN。./prisma/migrations/20210308092620_rename_migration/migration.sqlEXEC sp_rename 'dbo.Profile.biograpy', 'biography', 'COLUMN'; -
儲存並應用遷移
npx prisma migrate dev
你可以使用相同的技術重新命名 model——編輯生成的 SQL 以重新命名表,而不是刪除並重新建立它。
示例:使用擴充套件和收縮模式在不中斷服務的情況下演進 Schema
對現有欄位進行 schema 更改,例如重新命名欄位,可能會導致停機。這發生在應用修改現有欄位的遷移與部署使用修改後欄位的新版應用程式程式碼之間的時間段內。
你可以透過將修改欄位所需的步驟分解為一系列旨在逐步引入更改的離散步驟來防止停機。這種模式被稱為擴充套件和收縮模式。
該模式涉及兩個組成部分:訪問資料庫的應用程式程式碼和你打算修改的資料庫 schema。
使用擴充套件和收縮模式,將欄位 bio 重新命名為 biography 在 Prisma 中將如下所示:
-
將新的
biography欄位新增到你的 Prisma schema 並建立遷移model Profile {
id Int @id @default(autoincrement())
bio String
biography String
userId Int @unique
user User @relation(fields: [userId], references: [id])
} -
擴充套件:更新應用程式程式碼,同時寫入
bio和biography欄位,但繼續從bio欄位讀取,然後部署程式碼 -
建立一個空遷移,並將現有資料從
bio複製到biography欄位npx prisma migrate dev --name copy_biography --create-onlyprisma/migrations/20210420000000_copy_biography/migration.sqlUPDATE "Profile" SET biography = bio; -
驗證資料庫中
biography欄位的完整性 -
更新應用程式程式碼以從新的
biography欄位**讀取** -
更新應用程式程式碼以**停止寫入**
bio欄位 -
收縮:從 Prisma schema 中移除
bio,並建立遷移以移除bio欄位model Profile {
id Int @id @default(autoincrement())
bio String
biography String
userId Int @unique
user User @relation(fields: [userId], references: [id])
}npx prisma migrate dev --name remove_bio
透過使用這種方法,你可以避免因更改應用程式程式碼中使用的現有欄位而可能導致的停機,並減少應用遷移和部署更新後的應用程式程式碼之間所需的協調量。
請注意,此模式適用於任何涉及更改具有資料且正在被應用程式程式碼使用的列的情況。示例包括將兩個欄位合併為一個,或將 1:n 關係轉換為 m:n 關係。
要了解更多資訊,請檢視 Data Guide 中關於擴充套件和收縮模式的文章。
示例:改變一對一關係的方向
要改變一對一關係的方向
-
在 schema 中進行更改
model User {
id Int @id @default(autoincrement())
name String
posts Post[]
profile Profile? @relation(fields: [profileId], references: [id])
profileId Int @unique
}
model Profile {
id Int @id @default(autoincrement())
biography String
user User
} -
執行以下命令以建立**草稿遷移**,你可以在將其應用到資料庫之前進行編輯:
npx prisma migrate dev --name rename-migration --create-only顯示CLI結果⚠️ There will be data loss when applying the migration:
• The migration will add a unique constraint covering the columns `[profileId]` on the table `User`. If there are existing duplicate values, the migration will fail. -
按所示編輯草稿遷移
- 之前
- 之後
-- DropForeignKey
ALTER TABLE "Profile" DROP CONSTRAINT "Profile_userId_fkey";
-- DropIndex
DROP INDEX "Profile_userId_unique";
-- AlterTable
ALTER TABLE "Profile" DROP COLUMN "userId";
-- AlterTable
ALTER TABLE "User" ADD COLUMN "profileId" INTEGER NOT NULL;
-- CreateIndex
CREATE UNIQUE INDEX "User_profileId_unique" ON "User"("profileId");
-- AddForeignKey
ALTER TABLE "User" ADD FOREIGN KEY ("profileId") REFERENCES "Profile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- DropForeignKey
ALTER TABLE "Profile" DROP CONSTRAINT "Profile_userId_fkey";
-- DropIndex
DROP INDEX "Profile_userId_unique";
-- AlterTable
ALTER TABLE "User" ADD COLUMN "profileId" INTEGER;
UPDATE "User"
SET "profileId" = "Profile".id
FROM "Profile"
WHERE "User".id = "Profile"."userId";
ALTER TABLE "User" ALTER COLUMN "profileId" SET NOT NULL;
-- AlterTable
ALTER TABLE "Profile" DROP COLUMN "userId";
-- CreateIndex
CREATE UNIQUE INDEX "User_profileId_unique" ON "User"("profileId");
-- AddForeignKey
ALTER TABLE "User" ADD FOREIGN KEY ("profileId") REFERENCES "Profile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-
儲存並應用遷移
npx prisma migrate dev