跳到主要内容

升级到 Prisma ORM 4

Prisma ORM 4 引入了多项破坏性变更,当您从早期 Prisma ORM 版本升级时会遇到。本指南解释了此次升级可能如何影响您的应用程序,并提供了处理所有变更的说明。

破坏性变更

本节概述了 Prisma ORM 4 中的破坏性变更,分为影响 Prisma Schema 和 Prisma Client 的一般变更Schema 变更以及Client 变更

我们建议您首先解决任何 Prisma schema 验证错误,然后拉取您的数据库以反映新的 Prisma schema 功能,最后修复 Prisma Client 中的所有类型错误并通过运行测试套件进行验证。

升级您的 Prisma Schema

  1. 仔细浏览变更列表,检查您是否受到任何破坏性变更的影响。
  2. 审查 Prisma schema 验证错误(通过 npx prisma validate 或通过 Prisma VS Code 扩展)。
    1. 如果您没有验证错误,请继续执行步骤 3。
    2. 如果您有验证错误
      1. 尝试将验证错误映射到下面的列表中,以了解哪个变更导致了无效的 Prisma schema,并阅读链接的升级说明。它可能来自:
  3. 重复此过程,直到您的 Prisma schema 有效。
  4. 运行 npx prisma db pull 以将 Prisma schema 升级到所有新功能(例如 extendedIndexes)。
  5. 审查 Prisma schema 的变更并验证其有效性。
  6. 继续执行 Prisma Client 步骤。

升级您的 Prisma Client 用法

  1. 仔细浏览变更列表,以了解您是否受到破坏性变更的影响。
    1. 如果是,请阅读详细的升级说明。
    2. 如果否,请继续执行 2。
  2. Prisma Client 中的一些 API 变更会影响运行时行为,因此请运行您的测试套件。

享受 Prisma ORM 4 吧!

一般变更

本节包含影响 Prisma Schema 和 Prisma Client 的变更。

Node.js 最低版本变更

从 Prisma ORM 4.0.0 版本开始,我们支持的 Node.js 最低版本是 14.17.x。如果您使用更早的 Node.js 版本,您将需要进行更新。

请参阅我们的系统要求以了解所有最低版本要求。

Schema 变更

本节包含影响 Prisma Schema 的变更。

索引配置

在 Prisma ORM 4 中,extendedIndexes 预览特性现已普遍可用。这包括以下索引配置选项:

  • MySQL 的索引、唯一约束和主键约束的长度配置(在 3.5.0 及更高版本中为预览版)
  • 索引、唯一约束和主键约束的排序顺序配置(在 3.5.0 及更高版本中为预览版)
  • PostgreSQL 的新索引类型:Hash(在 3.6.0 及更高版本中为预览版)和 GIN、GiST、SP-GiST 和 BRIN(在 3.14.0 及更高版本中为预览版)
  • SQL Server 的索引集群(在 3.13.0 及更高版本中为预览版)

有关这些特性的更多详细信息,请参阅我们关于索引配置的文档。

升级路径

如果您之前在数据库级别配置这些属性,则这些都可能是破坏性变更。在这种情况下,您需要:

  1. 按照这些说明升级到新的 Prisma ORM 4 包
  2. 之后运行 npx prisma db pull 以检索任何现有的索引和约束配置。这需要在运行任何 npx prisma db pushnpx prisma migrate dev 命令之前完成,否则您可能会丢失数据库中定义但之前未在 Prisma schema 中表示的任何配置。

有关更多详细信息,请参阅我们索引配置文档中的从早期版本升级部分。

标量列表默认值

对于支持标量列表的数据库连接器(PostgreSQL、CockroachDB 和 MongoDB),Prisma ORM 4 引入了在 Prisma schema 中使用 @default 属性设置默认值的功能。

model User {
id Int @id @default(autoincrement())
posts Post[]
favoriteColors String[] @default(["red", "yellow", "purple"])
}
升级路径

如果您之前在数据库级别为标量列表定义了默认值,这是一个破坏性变更。在这种情况下,您需要:

  1. 按照这些说明升级到新的 Prisma ORM 4 包
  2. 之后运行 npx prisma db pull 以检索任何现有的索引和约束配置。这需要在运行任何 npx prisma db pushnpx prisma migrate dev 命令之前完成,否则您将丢失数据库中定义但之前未在 Prisma schema 中表示的任何默认值。

一对一关系上的显式 @unique 约束

在 Prisma ORM 4 中使用一对一关系时,您需要显式地将 @unique 属性添加到关系标量字段。例如,对于 UserProfile 模型之间的一对一关系,您需要将 @unique 属性添加到 profileId 字段

model User {
id Int @id @default(autoincrement())
profile Profile? @relation(fields: [profileId], references: [id])
profileId Int? @unique // <-- include this explicitly
}

model Profile {
id Int @id @default(autoincrement())
user User?
}
升级路径

升级到 Prisma ORM 4 后,任何没有在关系标量上添加 @unique 属性的一对一关系将触发验证错误。要升级,您需要:

  1. 按照这些说明升级到新的 Prisma ORM 4 包

  2. 通过向您的数据模型添加显式 @unique@id 属性来手动修复 Prisma schema 中的验证错误。

  3. 使用 prisma db push 将变更推送到您的 MongoDB 数据库,或使用 prisma migrate dev 推送到 MySQL 数据库。

强制对一对一和一对多关系使用 @unique@id 属性(MySQL 和 MongoDB)

在 Prisma ORM 4 中使用一对一和一对多关系时,您需要在关系字段上使用 @unique 属性,以确保关系的单侧只有一个记录。现在,这已对 MySQL 和 MongoDB 强制执行,使其与其他连接器保持一致。缺少 @unique 属性现在将触发验证错误。

UserPost 模型之间一对多关系的以下示例中,必须将 @unique 属性添加到 email 字段。

model User {
id Int @id @default(autoincrement())
email String @unique // <-- we enforce this attribute
posts Post[]
}

model Post {
id Int @id @default(autoincrement())
authorEmail String
author User @relation(fields: [authorEmail], references: [email])
}

UserProfile 模型之间一对一关系的以下示例中,必须将 @unique 属性添加到 email 字段。

model User {
id Int @id @default(autoincrement())
email String @unique // <- we enforce this unique attribute
profile Profile @relation(fields: [profileId], references: [id])
profileId Int
}

model Profile {
id Int @id @default(autoincrement())
userEmail String? @unique
user User?
}
升级路径

升级到 Prisma ORM 4 后,任何在关系字段上没有 @unique@id 属性的一对一或一对多关系将触发验证错误。要升级,您需要:

  1. 按照这些说明升级到新的 Prisma ORM 4 包
  2. 手动修复 Prisma schema 中的验证错误。或者,如果您有一个最新的实时数据库,运行 npx prisma db pull 将自动添加 @unique 属性。

禁止对隐式多对多关系使用 references 语法

在 Prisma ORM 4 中使用隐式多对多关系时,您将无法再使用之前可选的 references 参数。例如,以下关系现在将触发验证错误:

schema.prisma
model Post {
id Int @id @default(autoincrement())
categories Category[] @relation("my-relation", references: [id]) // <-- validation error
}

model Category {
id Int @id @default(autoincrement())
posts Post[] @relation("my-relation", references: [id]) // <-- validation error
}

相反,您可以这样写:

schema.prisma
model Post {
id Int @id @default(autoincrement())
categories Category[] @relation("my-relation")
}

model Category {
id Int @id @default(autoincrement())
posts Post[] @relation("my-relation")
}

这是因为 references 的唯一有效值是 id,因此删除此参数可以更清楚地表明什么可以更改,什么不能更改。

升级路径

升级到 Prisma ORM 4 后,任何带有 references 参数的隐式多对多关系将触发验证错误。要升级,您需要:

  1. 按照这些说明升级到新的 Prisma ORM 4 包
  2. 手动修复 Prisma schema 中的验证错误。或者,如果您有一个最新的实时数据库,运行 npx prisma db pull 将自动删除 references 参数。

更好的字符串字面量语法

您的 Prisma Schema 中的字符串字面量现在需要遵循与 JSON 中字符串相同的规则。这主要改变了一些特殊字符的转义方式。更多详细信息可以在JSON 规范JSON 网站上找到。

升级路径

这对于一些现有 schema 来说是一个破坏性变更。升级到 Prisma ORM 4 后,不正确转义的字符将触发验证错误。要升级,您需要:

  1. 按照这些说明升级到新的 Prisma ORM 4 包
  2. 手动修复 Prisma schema 中的验证错误。

Client 变更

本节包含影响 Prisma Client 的变更。

原始查询类型映射:标量值现在被反序列化为正确的 JavaScript 类型

在 3.14.x 和 3.15.x 版本中,原始查询类型映射通过预览特性 improvedQueryRaw 提供。在 4.0.0 版本中,我们已将原始查询类型映射普遍可用。在 4.0.0 及更高版本中,您无需使用 improvedQueryRaw 即可获得此功能。

原始查询现在将标量值反序列化为其相应的 JavaScript 类型。请注意,Prisma ORM 是从值本身推断类型,而不是从 Prisma Schema 类型推断。

查询和响应示例

const res =
await prisma.$queryRaw`SELECT bigint, bytes, decimal, date FROM "Table";`
console.log(res) // [{ bigint: BigInt("123"), bytes: Buffer.from([1, 2]), decimal: new Prisma.Decimal("12.34"), date: Date("<some_date>") }]
升级路径

从 4.0.0 版本开始,queryRawqueryRawUnsafe 返回的一些数据类型有所不同,如下所示:

数据类型4.0.0 版本之前从 4.0.0 版本开始
DateTime返回为 String返回为 Date
Numeric返回为 Float返回为 Decimal
Bytes返回为 String返回为 Buffer
Int64返回为 Integer返回为 BigInt

如果您使用 queryRawqueryRawUnsafe 返回上述任何数据类型,则必须更改代码以处理新类型。

例如,如果您返回 DateTime 数据,则需要考虑以下事项:

  • 您不再需要手动实例化返回数据的 DateTime 对象。
  • 如果您的代码当前使用返回的 String 数据,那么您现在需要将 DateTime 对象转换为 String

您必须对上表中其他数据类型进行等效的代码更改。

原始查询映射:PostgreSQL 类型转换

在 3.14.x 和 3.15.x 版本中,原始查询类型映射通过预览特性 improvedQueryRaw 提供。在 4.0.0 版本中,我们已将原始查询类型映射普遍可用。在 4.0.0 及更高版本中,您无需使用 improvedQueryRaw 即可获得此功能。

在 4.0.0 版本之前,许多 PostgreSQL 类型转换不起作用。我们已经收紧了类型强制转换规则,以便所有类型转换现在都起作用。因此,一些隐式转换现在会失败。

升级路径

我们建议您重新测试 $queryRaw 的使用,以确保您传递到原始查询中的类型与 PostgreSQL 期望的类型匹配。

例如,在 4.0.0 版本中,以下查询将失败:

await prisma.$queryRaw`select length(${42});`
// ERROR: function length(integer) does not exist
// HINT: No function matches the given name and argument types. You might need to add explicit type casts.

这是因为 PostgreSQL 的 length 函数期望 text 作为输入。Prisma ORM 以前会静默地将 42 强制转换为 text,但在 4.0.0 版本中不再这样做。要解决此问题,请显式地将 42 强制转换为 text,如下所示:

await prisma.$queryRaw`select length(${42}::text);`

原始查询映射:PostgreSQL 和 JavaScript 整数

在 3.14.x 和 3.15.x 版本中,原始查询类型映射通过预览特性 improvedQueryRaw 提供。在 4.0.0 版本中,我们已将原始查询类型映射普遍可用。在 4.0.0 及更高版本中,您无需使用 improvedQueryRaw 即可获得此功能。

Prisma ORM 将 JavaScript 整数作为 INT8 发送到 PostgreSQL。这可能与您只接受 INT4 作为输入的用户定义函数冲突。

升级路径

如果您使用 $queryRaw 或带参数的 $queryRawUnsafe 查询与 PostgreSQL 数据库,请执行以下操作之一:

  • 将用户定义函数中任何整数的输入类型更新为 INT8,或者
  • 将查询参数中的任何整数转换为 INT4

DbNullJsonNullAnyNull 现在是对象

JavaScript 中的 null 对于 JSON 列来说是模糊的,因此 Prisma ORM 使用 DbNullJsonNullAnyNull 来区分数据库 NULL 值和 JSON null 值。在 4.0.0 版本之前,DbNullJsonNullAnyNull 是字符串常量。从 4.0.0 版本开始,它们是对象。

有关更多信息,请参阅按 null 值过滤

升级路径
  1. 如果您使用字符串字面量来处理这些值,则必须将其替换为以下命名常量:

    • DbNull: 替换为 Prisma.DbNull
    • JsonNull: 替换为 Prisma.JsonNull
    • AnyNull: 替换为 Prisma.AnyNull

    如果您已经使用这些命名常量,则无需采取任何操作。

  2. 如果您现在在将 Prisma.DbNull 作为 JSON 字段的值传递时遇到类型错误,那么这可能表明您的代码中存在一个 bug,而我们的类型在 4.0.0 版本之前并未捕获到。您尝试存储 DbNull 的字段在您的 schema 中可能不是可空的。因此,数据库中存储的是字面量 DbNull 字符串而不是 NULL

  3. 在使用 Prisma.DbNullPrisma.JsonNullPrisma.AnyNull 与 MongoDB 配合使用时,您现在可能会遇到类型错误或运行时验证错误。这以前从未有效,但在 Prisma ORM 4 之前被静默接受。您需要审查您的数据并将这些字段更改为 null

  4. 如果您在 Prisma Client 中向 JSON 列传递动态 JSON(例如 prisma.findMany({where: { jsonColumn: someJson } })),那么您必须检查 someJson 不能是字符串 "DBNull"、"JsonNull" 或 "AnyNull"。如果它是这些值中的任何一个,那么查询在 4.0.0 版本中将返回不同的结果。

MongoDB 复合类型上的默认字段

从 4.0.0 版本开始,如果您在满足以下所有条件时对复合类型执行数据库读取,Prisma Client 会将默认值插入到结果中。

条件

  • 复合类型上的一个字段是必填的,并且
  • 此字段具有默认值,并且
  • 此字段在返回的文档中不存在。

此行为现在与模型字段的行为保持一致。

要了解更多信息,请参阅复合类型必填字段的默认值

升级路径

如果您当前依赖于 null 的返回值,那么您需要重构您的代码以处理 Prisma ORM 4 中现在返回的默认值。

SQLite 中大数字的舍入误差

SQLite 是一个弱类型数据库。如果您的 schema 中有一个类型为 Int 的字段,那么 Prisma ORM 会阻止您插入大于整数的值。然而,没有什么能阻止数据库直接接受更大的数字。这些手动插入的大数字在查询时会导致舍入误差。

为避免此问题,Prisma ORM 4.0.0 及更高版本会在数字从数据库取出时进行检查,以验证它们是否在整数的边界内。如果一个数字不符合,Prisma ORM 将抛出 P2023 错误,例如:

Inconsistent column data: Conversion failed:
Value 9223372036854775807 does not fit in an INT column,
try migrating the 'int' column type to BIGINT
升级路径

如果您将 Prisma ORM 与 SQLite 结合使用,那么您需要查找任何查询 Int 字段的代码,并确保它能处理可能返回的任何 P2023 错误。

Prisma ORM 不再将 Prisma.dmmf.schema 导出到生成的 Prisma Client 中

从 4.0.0 版本开始,Prisma ORM 不再将 Prisma.dmmf.schema 导出到生成的 Prisma Client 中。这使得生成的 Prisma Client 效率更高,并避免了 Jest 带来的一些内存泄漏。

注意

  • 此变更不影响 Prisma ORM 传递给生成器的 DMMF。
  • 您可以使用 @prisma/internals 中的 getDmmf() 来访问 schema 属性。
  • 我们仍然将 Prisma.dmmf.datamodel 导出到生成的 Prisma Client 中。

prisma@prisma/client 包升级到版本 4

要从早期版本升级到 Prisma ORM 4,您需要更新 prisma@prisma/client 包。prisma@prisma/client 包都以脱字符 ^ 安装在其版本号中。这允许升级到新的次要版本,但不允许升级到主要版本,以防止破坏性变更。

要忽略脱字符 ^ 并跨主要版本升级,您可以在使用 npmyarn 升级时使用 @4 标签

危险

在升级之前,请检查每个**破坏性变更**,以了解升级可能如何影响您的应用程序。

npm install prisma@4 @prisma/client@4

视频指南

有关升级过程的视频演练和升级场景的示例,请参阅我们关于升级到 Prisma ORM 4 的录制直播。

© . All rights reserved.