自定义迁移
在某些情况下,你需要在应用迁移文件之前对其进行编辑。例如,为了不丢失数据的 改变 1-1 关系的方向(将外键从一侧移动到另一侧),你需要在迁移过程中移动数据 - 此 SQL 不是默认迁移的一部分,必须手动编写。
¥In some scenarios, you need to edit a migration file before you apply it. For example, to change the direction of a 1-1 relation (moving the foreign key from one side to another) without data loss, you need to move data as part of the migration - this SQL is not part of the default migration, and must be written by hand.
本指南介绍了如何编辑迁移文件,并提供了一些你可能想要执行此操作的用例示例。
¥This guide explains how to edit migration files and gives some examples of use cases where you may want to do this.
如何编辑迁移文件
¥How to edit a migration file
要在应用迁移文件之前对其进行编辑,一般过程如下:
¥To edit a migration file before applying it, the general procedure is the following:
-
进行需要自定义 SQL 的架构更改(例如,为了保留现有数据)
¥Make a schema change that requires custom SQL (for example, to preserve existing data)
-
使用以下命令创建草稿迁移:
¥Create a draft migration using:
npx prisma migrate dev --create-only
-
修改生成的 SQL 文件。
¥Modify the generated SQL file.
-
通过运行以下命令应用修改后的 SQL:
¥Apply the modified SQL by running:
npx prisma migrate dev
示例:重命名字段
¥Example: Rename a field
默认情况下,重命名架构中的字段会导致迁移:
¥By default, renaming a field in the schema results in a migration that will:
-
CREATE
一个新列(例如,fullname
)¥
CREATE
a new column (for example,fullname
) -
DROP
现有列(例如name
)以及该列中的数据¥
DROP
the existing column (for example,name
) and the data in that column
为了在生产中运行迁移时实际重命名字段并避免数据丢失,你需要在将生成的迁移 SQL 应用到数据库之前修改它。考虑以下模式片段 - biograpy
字段拼写错误。
¥To actually rename a field and avoid data loss when you run the migration in production, you need to modify the generated migration SQL before applying it to the database. Consider the following schema fragment - the biograpy
field is spelled wrong.
model Profile {
id Int @id @default(autoincrement())
biograpy String
userId Int @unique
user User @relation(fields: [userId], references: [id])
}
要将 biograpy
字段重命名为 biography
:
¥To rename the biograpy
field to biography
:
-
重命名架构中的字段:
¥Rename the field in the schema:
model Profile {
id Int @id @default(autoincrement())
biograpy String
biography String
userId Int @unique
user User @relation(fields: [userId], references: [id])
} -
运行以下命令来创建草稿迁移,你可以在应用到数据库之前对其进行编辑:
¥Run the following command to create a draft migration that you can edit before applying to the database:
npx prisma migrate dev --name rename-migration --create-only
-
如图所示编辑草稿迁移,将
DROP
/DELETE
更改为单个RENAME COLUMN
:¥Edit the draft migration as shown, changing
DROP
/DELETE
to a singleRENAME COLUMN
:
- Before
- After
ALTER TABLE "Profile" DROP COLUMN "biograpy",
ADD COLUMN "biography" TEXT NOT NULL;
ALTER TABLE "Profile"
RENAME COLUMN "biograpy" TO "biography"
For SQL Server, you should use the stored procedure sp_rename
instead of ALTER TABLE RENAME COLUMN
.
EXEC sp_rename 'dbo.Profile.biograpy', 'biography', 'COLUMN';
-
保存并应用迁移:
¥Save and apply the migration:
npx prisma migrate dev
你可以使用相同的技术重命名 model
- 编辑生成的 SQL 以重命名表,而不是删除并重新创建它。
¥You can use the same technique to rename a model
- edit the generated SQL to rename the table rather than drop and re-create it.
示例:使用扩展和收缩模式在不停机的情况下发展模式
¥Example: Use the expand and contract pattern to evolve the schema without downtime
对现有字段进行架构更改(例如重命名字段)可能会导致停机。它发生在应用修改现有字段的迁移和部署使用修改后的字段的应用代码的新版本之间的时间范围内。
¥Making schema changes to existing fields, e.g., renaming a field can lead to downtime. It happens in the time frame between applying a migration that modifies an existing field, and deploying a new version of the application code which uses the modified field.
你可以通过将更改字段所需的步骤分解为一系列旨在逐渐引入更改的离散步骤来防止停机。这种模式称为扩展和收缩模式。
¥You can prevent downtime by breaking down the steps required to alter a field into a series of discrete steps designed to introduce the change gradually. This pattern is known as the expand and contract pattern.
该模式涉及两个组成部分:你的应用代码访问数据库以及你想要更改的数据库模式。
¥The pattern involves two components: your application code accessing the database and the database schema you intend to alter.
通过扩展和收缩模式,使用 Prisma 将字段 bio
重命名为 biography
如下所示:
¥With the expand and contract pattern, renaming the field bio
to biography
would look as follows with Prisma:
-
将新的
biography
字段添加到你的 Prisma 架构中并创建迁移¥Add the new
biography
field to your Prisma schema and create a migrationmodel Profile {
id Int @id @default(autoincrement())
bio String
biography String
userId Int @unique
user User @relation(fields: [userId], references: [id])
} -
扩张:更新应用代码并写入
bio
和biography
字段,但继续从bio
字段读取,然后部署代码¥Expand: update the application code and write to both the
bio
andbiography
fields, but continue reading from thebio
field, and deploy the code -
创建一个空迁移并将现有数据从
bio
复制到biography
字段¥Create an empty migration and copy existing data from the
bio
to thebiography
fieldnpx prisma migrate dev --name copy_biography --create-only
prisma/migrations/20210420000000_copy_biography/migration.sqlUPDATE "Profile" SET biography = bio;
-
验证数据库中
biography
字段的完整性¥Verify the integrity of the
biography
field in the database -
更新应用代码以从新的
biography
字段读取¥Update application code to read from the new
biography
field -
更新应用代码以停止写入
bio
字段¥Update application code to stop writing to the
bio
field -
合同:从 Prisma 架构中删除
bio
,并创建迁移以删除bio
字段¥Contract: remove the
bio
from the Prisma schema, and create a migration to remove thebio
fieldmodel 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
通过使用此方法,你可以避免更改应用代码中使用的现有字段可能导致的潜在停机,并减少应用迁移和部署更新的应用代码之间所需的协调量。
¥By using this approach, you avoid potential downtime that altering existing fields that are used in the application code are prone to, and reduce the amount of coordination required between applying the migration and deploying the updated application code.
请注意,此模式适用于涉及对包含数据且由应用代码使用的列进行更改的任何情况。示例包括将两个字段合并为一个字段,或者将 1:n
关系转换为 m:n
关系。
¥Note that this pattern is applicable in any situation involving a change to a column that has data and is in use by the application code. Examples include combining two fields into one, or transforming a 1:n
relation to a m:n
relation.
要了解更多信息,请查看 扩展和收缩模式 上的数据指南文章
¥To learn more, check out the Data Guide article on the expand and contract pattern
示例:改变 1-1 关系的方向
¥Example: Change the direction of a 1-1 relation
要更改 1-1 关系的方向:
¥To change the direction of a 1-1 relation:
-
在架构中进行更改:
¥Make the change in the 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
} -
运行以下命令来创建草稿迁移,你可以在应用到数据库之前对其进行编辑:
¥Run the following command to create a draft migration that you can edit before applying to the database:
npx prisma migrate dev --name rename-migration --create-only
Show CLI results⚠️ 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. -
编辑草稿迁移,如下所示:
¥Edit the draft migration as shown:
- Before
- After
-- 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;
-
保存并应用迁移:
¥Save and apply the migration:
npx prisma migrate dev