Prisma Schema 速查
schema.prisma 是 Prisma 自己的 DSL(领域语言)。它描述「数据库里有哪些表、字段、关系」,Prisma 会据此:
-
生成/迁移真实数据库表(migration SQL)
-
生成 TypeScript 客户端类型和查询 API
示例
model User {
id Int @id @default(autoincrement())
email String @unique
passwordHash String @map("password_hash")
name String?
todos Todo[]
orders Order[]
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("users")
}
model Todo {
id Int @id @default(autoincrement())
title String
done Boolean @default(false)
userId Int @map("user_id")
user User @relation(fields: [userId], references: [id])
deletedAt DateTime? @map("deleted_at") // 软删除,第 7--8 周会用到
createdAt DateTime @default(now()) @map("created_at")
@@map("todos")
}
Model 是什么
model User { ... } 表示:数据库里的一张表,在代码里叫 User。
| Model | 业务实体 |
|---|---|
User |
用户 |
Todo |
待办 |
Prisma 会把每个 model 变成:
-
数据库中的一张表(默认表名是 model 名,可被
@@map改掉) -
TypeScript 里的一个类型,例如
User、Todo -
查询 API,例如
prisma.user.findMany()、prisma.todo.create()
可以把它理解成:ORM 里的「实体类 / 表定义」,一份定义,数据库和 TS 两边都用。
-
主键列 (如
User.id):在这张表里标识「我是谁」 -
外键列 (如
Todo.userId):在这张表里标识「我属于谁 / 我指向谁」
数据库设计常见缩写
| 缩写 | 全称 | 中文 |
|---|---|---|
| PK | Primary Key | 主键 |
| FK | Foreign Key | 外键 |
| UK | Unique Key | 唯一键 |
| IDX | Index | 索引 |
字段类型
字段名后面为「字段类型 + 若干修饰符(attributes)」。
常见 Prisma 类型:
-
Int、String、Boolean、DateTime -
String?、DateTime?→ 可空 -
User、Todo[]→ 关联到其他 model
属性:@ 与 @@
在 Prisma 里:
-
@xxx(一个@)→ 字段级属性,作用在这一列上 -
@@xxx(两个@)→ 模型级属性,作用在整个表上
常见字段级 @
| 写法 | 作用 |
|---|---|
@id |
主键 |
@default(autoincrement()) |
自增主键 |
@default(now()) |
插入时默认当前时间 |
@default(false) |
默认 false |
@unique |
唯一约束 |
@updatedAt |
更新记录时自动改时间 |
@map("xxx") |
代码字段名 ↔ 数据库列名映射 |
@relation(...) |
定义表与表之间的外键关系 |
@relation 常见参数
@relation(
fields: [userId], // 本表哪些列是外键
references: [id], // 对方表哪一列被引用(通常是主键)
name: "UserTodos", // 可选:关系名,复杂关系时区分
onDelete: Cascade, // 可选:删 User 时怎么处理 Todo
onDelete: SetNull, // 可选:删 User 时把 userId 设为 null
map: "fk_todo_user" // 可选:数据库里外键约束的名字
)
fields + references 是最核心的:
-
fields: [userId]→ 在Todo表上,user_id这一列 -
references: [id]→ 引用User表的id列
为什么 User 那边不用写 @relation?
model User {
todos Todo[]
}
在一对多里,外键在「多」的那一侧(Todo 有 userId),所以:
-
Todo 侧 :必须写完整的
@relation(fields: ..., references: ...) -
User 侧 :只写
todos Todo[]即可,Prisma 会从 Todo 那边推断
这叫 关系的两面。
这里其实是两个字段配合:
| 字段 | 类型 | 是否占数据库列 | 作用 |
|---|---|---|---|
userId |
Int |
✅ 占一列 | 存外键值,例如 3 表示属于 id=3 的用户 |
user |
User |
❌ 不占列 | 关系对象,查 Todo 时可以 include: { user: true } 带出 User |
-
Todo→User:多对一(many-to-one) -
User→Todo:一对多(one-to-many)
多对多(扩展了解)
如果 User 和 Role 是多对多,会多一张中间表,两边都要写 @relation,例如:
model User {
id Int @id @default(autoincrement())
roles UserRole[]
}
model Role {
id Int @id @default(autoincrement())
users UserRole[]
}
model UserRole {
userId Int @map("user_id")
roleId Int @map("role_id")
user User @relation(fields: [userId], references: [id])
role Role @relation(fields: [roleId], references: [id])
@@id([userId, roleId]) // 联合主键
}
常见模型级 @@
1. @@map("表名") --- 表名映射
model User {
id Int @id
email String
@@map("users") // Prisma 里叫 User,数据库表叫 users
}
| 层面 | 名字 |
|---|---|
| Prisma model | User |
| 数据库真实表 | users |
和 @map("xxx") 的关系:
-
@map→ 列名映射(userId↔user_id) -
@@map→ 表名映射(User↔users)
2. @@unique([列1, 列2, ...]) --- 多列联合唯一
model Favorite {
userId Int
todoId Int
@@unique([userId, todoId]) // (userId, todoId) 这一对不能重复
}
-
单列
@unique:这一列全表不能重复(如email) -
@@unique:几列组合起来不能重复(如「同一用户不能重复收藏同一条 Todo」)
还可命名:
@@unique([userId, todoId], name: "user_todo_unique")
3. @@id([列1, 列2, ...]) --- 联合主键
model UserRole {
userId Int
roleId Int
@@id([userId, roleId]) // 两列一起当主键,没有单独的自增 id
}
@@id |
@@unique |
|
|---|---|---|
| 作用 | 标识一行(主键) | 只限制不能重复 |
是否还能有 @id 自增列 |
通常二选一 | 可以:另有 id @id,再加 @@unique |
中间表、关联表常用 @@id;业务表更常见单个 id @id @default(autoincrement())。
4. @@index([列1, 列2, ...]) --- 普通索引(加速查询)
model Todo {
userId Int
done Boolean
@@index([userId]) // 按 userId 查 Todo 更快
@@index([userId, done]) // 联合索引
}
-
@unique/@@unique:唯一 + 常带索引 -
@@index:只加速,不要求唯一
例如常查「某用户未完成的 Todo」:where: { userId: 1, done: false },给 (userId, done) 建索引会更快。
5. 其他(了解即可)
| 写法 | 作用 |
|---|---|
@@schema("auth") |
PostgreSQL 下指定 schema(如 auth.users) |
@@ignore |
这个 model 不生成到 Client,不参与 migrate |
@@fulltext([title]) |
MySQL 全文索引 |
@@check(...) |
检查约束(如 age >= 0,视数据库版本支持) |
初学阶段,@@map、@@unique、@@index、@@id 最常用。