内省
你可以使用 Prisma CLI 内省你的数据库,以便在你的 Prisma 模式中生成数据模型。需要数据模型来生成 Prisma 客户端。
当将 Prisma ORM 添加到现有项目时,内省通常用于生成数据模型的初始版本。
然而,它也可以在应用程序中重复使用。当你不使用 Prisma Migrate,而是使用纯 SQL 或其他迁移工具执行模式迁移时,这种情况最为常见。在这种情况下,你还需要重新内省你的数据库,并随后重新生成 Prisma 客户端,以反映你的 Prisma Client API 中的模式更改。
内省的作用是什么?
内省有一个主要功能:使用反映当前数据库模式的数据模型填充你的 Prisma 模式。
以下是在 SQL 数据库上的主要功能的概述
- 将数据库中的表映射到 Prisma 模型
- 将数据库中的列映射到 Prisma 模型的字段
- 将数据库中的索引映射到 Prisma 模式中的索引
- 将数据库约束映射到 Prisma 模式中的属性或类型修饰符
在 MongoDB 上,主要功能如下
- 将数据库中的集合映射到 Prisma 模型。由于 MongoDB 中的集合没有预定义的结构,Prisma ORM 会采样集合中的文档,并相应地推导出模型结构(即,它将文档的字段映射到 Prisma 模型的字段)。如果在集合中检测到嵌入式类型,这些类型将被映射到 Prisma 模式中的复合类型。
- 如果集合中至少包含一个包含索引中包含的字段的文档,则将数据库中的索引映射到 Prisma 模式中的索引
你可以在相应的数据源连接器文档页面上了解更多关于 Prisma ORM 如何将数据库中的类型映射到 Prisma 模式中可用的类型的信息
prisma db pull
命令
你可以使用 Prisma CLI 的 prisma db pull
命令来内省你的数据库。请注意,使用此命令需要你的 连接 URL 在你的 Prisma 模式datasource
中设置。
以下是 prisma db pull
在内部执行的步骤的高级概述
- 从 Prisma 模式中的
datasource
配置中读取连接 URL - 打开与数据库的连接
- 内省数据库模式(即,读取表、列和其他结构...)
- 将数据库模式转换为 Prisma 模式数据模型
- 将数据模型写入 Prisma 模式或更新现有模式
内省工作流程
不使用 Prisma Migrate,而是使用纯 SQL 或其他迁移工具的项目的一般工作流程如下
- 更改数据库模式(例如,使用纯 SQL)
- 运行
prisma db pull
以更新 Prisma 模式 - 运行
prisma generate
以更新 Prisma 客户端 - 在你的应用程序中使用更新的 Prisma 客户端
请注意,随着应用程序的发展,这个过程可以重复无限次。
规则和约定
Prisma ORM 采用许多约定来将数据库模式转换为 Prisma 模式中的数据模型
模型、字段和枚举名称
字段、模型和枚举名称(标识符)必须以字母开头,并且通常只能包含下划线、字母和数字。你可以在各自的文档页面上找到每个标识符的命名规则和约定
标识符的一般规则是它们需要遵循这个正则表达式
[A-Za-z][A-Za-z0-9_]*
无效字符的清理
无效字符在内省期间被清理
- 如果它们出现在标识符中的字母之前,则会被删除。
- 如果它们出现在第一个字母之后,则会被下划线替换。
此外,转换后的名称使用 @map
或 @@map
映射到数据库,以保留原始名称。
考虑以下表格作为示例
CREATE TABLE "42User" (
_id SERIAL PRIMARY KEY,
_name VARCHAR(255),
two$two INTEGER
);
由于表名中的前导 42
以及列上的前导下划线和 $
在 Prisma ORM 中被禁止,因此内省会添加 @map
和 @@map
属性,以便这些名称符合 Prisma ORM 的命名约定
model User {
id Int @id @default(autoincrement()) @map("_id")
name String? @map("_name")
two_two Int? @map("two$two")
@@map("42User")
}
清理后重复的标识符
如果清理导致重复的标识符,则不会立即进行错误处理。你稍后会收到错误,并且可以手动修复它。
考虑以下两个表的情况
CREATE TABLE "42User" (
_id SERIAL PRIMARY KEY
);
CREATE TABLE "24User" (
_id SERIAL PRIMARY KEY
);
这将导致以下内省结果
model User {
id Int @id @default(autoincrement()) @map("_id")
@@map("42User")
}
model User {
id Int @id @default(autoincrement()) @map("_id")
@@map("24User")
}
尝试使用 prisma generate
生成你的 Prisma 客户端,你将收到以下错误
npx prisma generate
$ npx prisma generate
Error: Schema parsing
error: The model "User" cannot be defined because a model with that name already exists.
--> schema.prisma:17
|
16 | }
17 | model User {
|
Validation Error Count: 1
在这种情况下,你必须手动更改两个生成的 User
模型之一的名称,因为 Prisma 模式中不允许重复的模型名称。
字段顺序
内省以与数据库中相应表列相同的顺序列出模型字段。
属性顺序
内省按照以下顺序添加属性(此顺序由 prisma format
反映)
- 块级:
@@id
、@@unique
、@@index
、@@map
- 字段级:
@id
、@unique
、@default
、@updatedAt
、@map
、@relation
关系
Prisma ORM 将在你的数据库表中定义的外键转换为关系。
一对一关系
当表上的外键具有 UNIQUE
约束时,Prisma ORM 会将一对一关系添加到你的数据模型中,例如
CREATE TABLE "User" (
id SERIAL PRIMARY KEY
);
CREATE TABLE "Profile" (
id SERIAL PRIMARY KEY,
"user" integer NOT NULL UNIQUE,
FOREIGN KEY ("user") REFERENCES "User"(id)
);
Prisma ORM 将其转换为以下数据模型
model User {
id Int @id @default(autoincrement())
Profile Profile?
}
model Profile {
id Int @id @default(autoincrement())
user Int @unique
User User @relation(fields: [user], references: [id])
}
一对多关系
默认情况下,Prisma ORM 会将一对多关系添加到你的数据模型中,以表示它在你的数据库模式中找到的外键
CREATE TABLE "User" (
id SERIAL PRIMARY KEY
);
CREATE TABLE "Post" (
id SERIAL PRIMARY KEY,
"author" integer NOT NULL,
FOREIGN KEY ("author") REFERENCES "User"(id)
);
这些表被转换为以下模型
model User {
id Int @id @default(autoincrement())
Post Post[]
}
model Post {
id Int @id @default(autoincrement())
author Int
User User @relation(fields: [author], references: [id])
}
多对多关系
Prisma ORM 支持在 Prisma 模式中定义多对多关系的两种方式
如果隐式多对多关系符合 Prisma ORM 的 关系表约定,则会被识别。否则,关系表会在 Prisma 模式中渲染为一个模型(因此成为一个显式多对多关系)。
关于关系的文档页面对此主题进行了广泛的介绍。
消除关系歧义
Prisma ORM 通常会在 @relation
属性上省略 name
参数,如果不需要的话。考虑上一节中的 User
↔ Post
示例。 @relation
属性只有 references
参数,省略了 name
,因为在这种情况下不需要它。
model Post {
id Int @id @default(autoincrement())
author Int
User User @relation(fields: [author], references: [id])
}
如果 Post
表上定义了两个外键,则需要该参数。
CREATE TABLE "User" (
id SERIAL PRIMARY KEY
);
CREATE TABLE "Post" (
id SERIAL PRIMARY KEY,
"author" integer NOT NULL,
"favoritedBy" INTEGER,
FOREIGN KEY ("author") REFERENCES "User"(id),
FOREIGN KEY ("favoritedBy") REFERENCES "User"(id)
);
在这种情况下,Prisma ORM 需要使用专用的关系名称来消除关系的歧义。
model Post {
id Int @id @default(autoincrement())
author Int
favoritedBy Int?
User_Post_authorToUser User @relation("Post_authorToUser", fields: [author], references: [id])
User_Post_favoritedByToUser User? @relation("Post_favoritedByToUser", fields: [favoritedBy], references: [id])
}
model User {
id Int @id @default(autoincrement())
Post_Post_authorToUser Post[] @relation("Post_authorToUser")
Post_Post_favoritedByToUser Post[] @relation("Post_favoritedByToUser")
}
请注意,您可以将Prisma-ORM 级别关系字段重命名为任何您喜欢的名称,以便在生成的 Prisma Client API 中看起来更友好。
使用现有模式进行自省
对于具有现有 Prisma 模式的关系数据库,运行 prisma db pull
会将对模式进行的手动更改与数据库中所做的更改合并。(此功能首次在 2.6.0 版本中添加。)对于 MongoDB,自省目前仅用于初始数据模型。重复运行会导致自定义更改丢失,如下所示。
关系数据库的自省会保留以下手动更改
model
块的顺序enum
块的顺序- 注释
@map
和@@map
属性@updatedAt
@default(cuid())
(cuid()
是 Prisma-ORM 级别的函数)@default(uuid())
(uuid()
是 Prisma-ORM 级别的函数)- 自定义
@relation
名称
注意:只会提取数据库级别的模型之间的关系。这意味着必须设置外键。
模式的以下属性由数据库确定
model
块内字段的顺序enum
块内值的顺序
注意:所有
enum
块都列在model
块的下面。
强制覆盖
要覆盖手动更改,并仅基于自省的数据库生成模式,并忽略任何现有的 Prisma 模式,请将 --force
标志添加到 db pull
命令中
npx prisma db pull --force
用例包括
- 您想从头开始使用从底层数据库生成的模式
- 您的模式无效,必须使用
--force
才能使自省成功
仅自省数据库模式的子集
仅自省数据库模式的子集尚未得到 Prisma ORM 的 官方支持。
但是,您可以通过创建一个新的数据库用户来实现此目的,该用户仅有权访问您希望在 Prisma 模式中表示的表,然后使用该用户执行自省。自省将仅包括新用户有权访问的表。
如果您的目标是从 Prisma Client 生成中排除某些模型,您可以在 Prisma 模式中的模型定义中添加 @@ignore
属性。被忽略的模型将从生成的 Prisma Client 中排除。
关于不支持功能的自省警告
Prisma 模式语言 (PSL) 可以表达 Prisma ORM 支持的目标数据库的大部分数据库功能。但是,Prisma 模式语言仍然需要表达一些特性和功能。
对于这些功能,Prisma CLI 将在您的数据库中检测到该功能的使用并返回警告。Prisma CLI 还将在 Prisma 模式中使用这些功能的模型和字段中添加注释。警告还将包含一个解决方法建议。
prisma db pull
命令将显示以下不支持的功能
您可以在 GitHub 上找到我们计划支持的功能列表(标记为 topic:database-functionality
)。
针对不支持的功能的自省警告的解决方法
如果您正在使用关系数据库,并且使用了上一节中列出的上述功能之一
- 创建一个草稿迁移
npx prisma migrate dev --create-only
- 添加在警告中显示的功能的 SQL。
- 将草稿迁移应用到您的数据库
npx prisma migrate dev