跳至主要内容

数据迁移

Prisma ORM 目前还不原生支持数据迁移,但你可以使用 扩展和收缩模式 来迁移你的数据。例如,从一个列迁移到另一个列。

本指南介绍如何使用 Prisma ORM 与扩展和收缩模式来

  • 扩展你的架构,添加新列
  • 创建并运行数据迁移
  • 收缩你的架构,删除旧列

步骤概述

本教程将引导你完成以下步骤

  1. 扩展你的架构,添加新列
  2. 创建并运行数据迁移文件
  3. 收缩你的架构,删除旧列

它还做出了以下假设

  • 生产数据库可以从开发机器访问
  • prisma migrate dev 仅针对开发数据库运行
  • 扩展和收缩步骤在不同的分支中处理

在本指南中,你将通过用 status 枚举替换 published 布尔字段来修改以下架构

prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
}

扩展你的架构,添加新列

从你的 main 分支检出到一个新分支

git checkout -b create-status-field

对你的 Prisma 架构进行以下更新

  • 创建一个 Status 枚举,包含以下值:UnknownDraftInReviewPublished
  • Post 模型添加 status
  • published 字段标记为可选
prisma/schema.prisma
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean? @default(false)
status Status
}

enum Status {
Unknown
Draft
InProgress
InReview
Published
}

创建一个新的迁移,将 Prisma 架构与数据库架构同步

npx prisma migrate dev --name add-status-column

Prisma Migrate 会给你以下警告,因为添加到数据库的字段是非空的,并且数据库包含需要默认值才能填充的现有数据。

Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "data-migration", schema "public" at "localhost:5401"

Error:
⚠️ We found changes that cannot be executed:

• Step 1 Added the required column `status` to the `Post` table without a default value. There are 4 rows in this table, it is not possible to execute this step.

You can use prisma migrate dev --create-only to create the migration file, and manually modify it to address the underlying issue(s).
Then run prisma migrate dev to apply it and verify it works.

退出迁移步骤,并通过添加 @default() 属性函数为 status 字段添加默认值来更新架构。

prisma/schema.prisma
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean? @default(false)
status Status @default(Unknown)
}

enum Status {
Unknown
Draft
InProgress
InReview
Published
}

使用以下命令生成并执行迁移

npx prisma migrate dev --name add-default

创建并运行数据迁移文件

创建一个数据迁移文件

在之前步骤中生成的迁移文件夹内,创建一个名为 data-migration.ts 的文件。此文件将包含一个数据迁移,该迁移将使用 Prisma Client 实现。

将以下代码添加到你刚刚创建的文件中,以将数据从 published 字段迁移到 status 字段

prisma/migrations/20230417131956_add-status-column/data-migration.ts
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

async function main() {
await prisma.$transaction(async (tx) => {
const posts = await tx.post.findMany()
for (const post of posts) {
await tx.post.update({
where: { id: post.id },
data: {
status: post.published ? 'Published' : 'Unknown',
},
})
}
})
}

main()
.catch(async (e) => {
console.error(e)
process.exit(1)
})
.finally(async () => await prisma.$disconnect())

数据迁移封装在事务中,以确保查询被回滚,从而允许你迭代你的数据迁移文件

下一步

  1. 将你的更改推送到远程源并创建一个新的拉取请求。
  2. 当你对更改感到满意后,将更改合并到你的 main 分支。

要将更改应用到你的生产数据库,请将 prisma migrate deploy 添加到你 CI 中的部署/构建步骤中

运行数据迁移

使用以下脚本更新 package.json 文件以执行数据迁移文件。请确保将 20230417131956_add-status-column 更新为你迁移文件的名称。

package.json
"scripts": {
"dev": "tsx ./script.ts",
"data-migration:add-status-column": "tsx ./prisma/migrations/20230417131956_add-status-column/data-migration.ts"
},

下一步

  1. 将你的更改推送到远程源并创建一个新的拉取请求。
  2. 当你对更改感到满意后,将更改合并到你的“main”分支。

要将更改应用到你的生产数据库,请将 prisma migrate deploy 添加到你 CI 中的部署/构建步骤中。

运行数据迁移

使用你的生产数据库的 URL 更新 DATABASE_URL 环境变量。运行数据迁移脚本

npm run data-migration:add-status-column

收缩你的架构,删除旧列

在你的开发机器上检出到一个单独的分支

git checkout -b drop-published-column

从你的架构中删除 published 字段并生成一个新的迁移

model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean? @default(false)
status Status @default(Unknown)
}

enum Status {
Draft
InProgress
InReview
Published
}

生成一个新的迁移

npx prisma migrate dev --name drop-published-column

下一步

  1. 将你的更改推送到远程源并创建一个新的拉取请求。
  2. 当你对更改感到满意后,将更改合并到你的 main 分支。

要将更改应用到你的生产数据库,请将 prisma migrate deploy 添加到你 CI 中的部署/构建步骤中

npx prisma migrate deploy

你已经成功地

  • 将数据从 published 列迁移到 status
  • 从你的架构中删除了 published