自訂遷移
在某些情況下,您需要在套用遷移檔案之前先編輯它。例如,若要變更 1-1 關係的方向(將外鍵從一側移到另一側)而不會遺失資料,您需要將資料作為遷移的一部分移動 - 此 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-only
prisma/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 上關於擴展和收縮模式的文章
範例:變更 1-1 關係的方向
若要變更 1-1 關係的方向
-
在 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