跳到主要內容

自訂遷移

警告

本指南不適用於 MongoDB
對於 MongoDB,請使用 db push,而非 migrate dev

在某些情況下,您需要在套用遷移檔案之前先編輯它。例如,若要變更 1-1 關係的方向(將外鍵從一側移到另一側)而不會遺失資料,您需要將資料作為遷移的一部分移動 - 此 SQL 不包含在預設遷移中,必須手動編寫。

本指南說明如何編輯遷移檔案,並提供一些您可能想要這樣做的用例範例。

如何編輯遷移檔案

若要在套用遷移檔案之前編輯它,一般程序如下

  1. 進行需要自訂 SQL 的 schema 變更 (例如,為了保留現有資料)

  2. 使用以下命令建立草稿遷移

    npx prisma migrate dev --create-only
  3. 修改產生的 SQL 檔案。

  4. 執行以下命令套用修改後的 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

  1. 在 schema 中重新命名欄位

    model Profile {
    id Int @id @default(autoincrement())
    biograpy String
    biography String
    userId Int @unique
    user User @relation(fields: [userId], references: [id])
    }
  2. 執行以下命令以建立草稿遷移,您可以在套用至資料庫之前編輯該遷移

    npx prisma migrate dev --name rename-migration --create-only
  3. 如下所示編輯草稿遷移,將 DROP / DELETE 變更為單個 RENAME COLUMN

    ./prisma/migrations/20210308092620_rename_migration/migration.sql
    ALTER TABLE "Profile" DROP COLUMN "biograpy",
    ADD COLUMN "biography" TEXT NOT NULL;
  4. 儲存並套用遷移

    npx prisma migrate dev

您可以使用相同的技術來重新命名 model - 編輯產生的 SQL 以重新命名表格,而不是刪除並重新建立它。

範例:使用擴展和收縮模式來演進 schema 而不停機

對現有欄位進行 schema 變更,例如,重新命名欄位可能會導致停機。停機發生在套用修改現有欄位的遷移,以及部署使用修改後欄位的新版本應用程式程式碼之間的時間範圍內。

您可以將變更欄位所需的步驟分解為一系列旨在逐步引入變更的離散步驟,來防止停機。此模式稱為擴展和收縮模式

該模式涉及兩個組件:您的應用程式程式碼存取資料庫,以及您打算變更的資料庫 schema。

使用擴展和收縮模式,將欄位 bio 重新命名為 biography 的步驟如下所示 (使用 Prisma)

  1. 將新的 biography 欄位新增至您的 Prisma schema 並建立遷移

    model Profile {
    id Int @id @default(autoincrement())
    bio String
    biography String
    userId Int @unique
    user User @relation(fields: [userId], references: [id])
    }
  2. 擴展:更新應用程式程式碼並同時寫入 biobiography 欄位,但繼續從 bio 欄位讀取,並部署程式碼

  3. 建立空的遷移,並將現有資料從 bio 複製到 biography 欄位

    npx prisma migrate dev --name copy_biography --create-only
    prisma/migrations/20210420000000_copy_biography/migration.sql
    UPDATE "Profile" SET biography = bio;
  4. 驗證資料庫中 biography 欄位的完整性

  5. 更新應用程式程式碼以從新的 biography 欄位讀取

  6. 更新應用程式程式碼以停止寫入 bio 欄位

  7. 收縮:從 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 關係的方向

  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
    }
  2. 執行以下命令以建立草稿遷移,您可以在套用至資料庫之前編輯該遷移

    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.
  3. 如下所示編輯草稿遷移


-- 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;
  1. 儲存並套用遷移

    npx prisma migrate dev