跳至主要内容

升级到 Prisma ORM 4

从早期 Prisma ORM 版本升级时,Prisma ORM 4 引入了许多重大更改。本指南解释了此升级可能如何影响您的应用程序,并提供了如何处理任何更改的说明。

重大更改

本节概述了 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 引入了使用 @default 属性在您的 Prisma schema 中设置默认值的功能

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 作为输入的用户定义函数冲突。

升级路径

如果您在 PostgreSQL 数据库中使用 $queryRaw 或参数化 $queryRawUnsafe 查询,请执行以下操作之一

  • 将您的用户定义函数中任何整数的输入类型更新为 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 字段的值传递时遇到类型错误,这可能表明您的代码存在错误,而我们的类型在 4.0.0 版本之前没有捕获到。您尝试存储 DbNull 的字段在您的 schema 中可能不是可空字段。因此,数据库中存储的是字符串字面量 DbNull 而不是 NULL

  3. 现在在 MongoDB 中使用 Prisma.DbNullPrisma.JsonNullPrisma.AnyNull 时,您可能会遇到类型错误或运行时验证错误。这从未有效,但在 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
Argument `age`: 在 Int 类型上获取了无效值 12345678901234567890。此数字过大,无法放入 32 位整数中。

如果您将 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 的录制直播