06 - Prisma Schema

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 里的一个类型,例如 UserTodo

  • 查询 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 类型:

  • IntStringBooleanDateTime

  • String?DateTime? → 可空

  • UserTodo[] → 关联到其他 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[]
}

在一对多里,外键在「多」的那一侧(TodouserId),所以:

  • Todo 侧 :必须写完整的 @relation(fields: ..., references: ...)

  • User 侧 :只写 todos Todo[] 即可,Prisma 会从 Todo 那边推断

这叫 关系的两面

这里其实是两个字段配合:

字段 类型 是否占数据库列 作用
userId Int ✅ 占一列 存外键值,例如 3 表示属于 id=3 的用户
user User ❌ 不占列 关系对象,查 Todo 时可以 include: { user: true } 带出 User
  • TodoUser多对一(many-to-one)

  • UserTodo一对多(one-to-many)

多对多(扩展了解)

如果 UserRole 是多对多,会多一张中间表,两边都要写 @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 → 列名映射(userIduser_id

  • @@map → 表名映射(Userusers

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 最常用。