マイグレーションのカスタマイズ
場合によっては、マイグレーションファイルを適用する前に編集する必要があります。例えば、データ損失なしに1対1リレーションの方向を変更する(外部キーを一方から他方へ移動する)には、マイグレーションの一部としてデータを移動する必要があります。このSQLはデフォルトのマイグレーションには含まれていないため、手動で記述する必要があります。
このガイドでは、マイグレーションファイルを編集する方法と、それを実行したい場合のいくつかの使用例を説明します。
マイグレーションファイルの編集方法
マイグレーションファイルを適用する前に編集するには、一般的な手順は以下の通りです。
-
カスタムSQLを必要とするスキーマ変更を行います(例:既存のデータを保持するため)
-
以下を使用してドラフトマイグレーションを作成します
npx prisma migrate dev --create-only
-
生成されたSQLファイルを変更します。
-
以下を実行して、変更されたSQLを適用します
npx prisma migrate dev
例: フィールド名の変更
デフォルトでは、スキーマ内のフィールド名を変更すると、以下のマイグレーションが生成されます。
- 新しいカラムを
CREATE
する(例:fullname
) - 既存のカラム(例:
name
)とそのカラムのデータをDROP
する
本番環境でマイグレーションを実行する際にデータ損失を避けて実際にフィールドをリネームするには、生成されたマイグレーションSQLをデータベースに適用する前に変更する必要があります。以下のスキーマ断片を検討してください。biograpy
フィールドのスペルが間違っています。
model Profile {
id Int @id @default(autoincrement())
biograpy String
userId Int @unique
user User @relation(fields: [userId], references: [id])
}
biograpy
フィールドをbiography
にリネームするには
-
スキーマ内でフィールド名を変更します
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の場合、
ALTER TABLE RENAME COLUMN
の代わりにストアドプロシージャsp_rename
を使用する必要があります。./prisma/migrations/20210308092620_rename_migration/migration.sqlEXEC sp_rename 'dbo.Profile.biograpy', 'biography', 'COLUMN';
-
マイグレーションを保存して適用します
npx prisma migrate dev
同じ手法を使用してmodel
の名前を変更することもできます。生成されたSQLを編集して、テーブルを削除して再作成するのではなく、名前を変更します。
例: ダウンタイムなしでスキーマを進化させるための展開・縮小パターンを使用する
既存のフィールドにスキーマ変更を加えること(例:フィールド名の変更)は、ダウンタイムにつながる可能性があります。これは、既存のフィールドを変更するマイグレーションを適用してから、変更されたフィールドを使用する新しいバージョンのアプリケーションコードをデプロイするまでの期間に発生します。
フィールドを変更するために必要な手順を一連の段階的なステップに分割することで、ダウンタイムを防ぐことができます。このパターンは展開・縮小パターンとして知られています。
このパターンには、データベースにアクセスするアプリケーションコードと、変更しようとしているデータベーススキーマという2つのコンポーネントが含まれます。
展開・縮小パターンでは、Prismaでフィールドbio
をbiography
に名前変更するには、次のようになります。
-
新しい
biography
フィールドをPrismaスキーマに追加し、マイグレーションを作成します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スキーマから
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
このアプローチを使用することで、アプリケーションコードで使用されている既存のフィールドを変更する際に発生しがちな潜在的なダウンタイムを回避し、マイグレーションの適用と更新されたアプリケーションコードのデプロイに必要な調整の量を減らすことができます。
このパターンは、データがあり、アプリケーションコードで使用されているカラムに対する変更を伴うあらゆる状況に適用可能であることに注意してください。例としては、2つのフィールドを1つに結合したり、1:n
リレーションをm:n
リレーションに変換したりすることが含まれます。
詳細については、データガイド記事の展開・縮小パターンを確認してください。
例: 1対1リレーションの方向を変更する
1対1リレーションの方向を変更するには
-
スキーマで変更を行う
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