首页 / Prisma ORM 入门教程 / 枚举与原生数据库类型

Prisma ORM 入门教程

枚举与原生数据库类型

本教程共 54 篇 · 第 10 篇 · 更新于 2026-08-11 · 约 5 分钟阅读

Prisma枚举enum原生类型@dbSQLitePostgreSQL迁移

本节目标:定义并使用 enum,掌握 @db.* 原生类型与 SQLite 的限制。

枚举(enum)把字段的值限定在固定集合里。用户的角色只有 USER 和 ADMIN 几种,文章状态只有 DRAFT、PUBLISHED、ARCHIVED——用枚举建模,数据库和 TypeScript 两侧都会拦下非法值。

定义 enum 块

enum 块和 model 块平级,写在 Schema 顶层:

enum Role {
  USER
  ADMIN
}

model User {
  id   Int  @id @default(autoincrement())
  role Role @default(USER)
}

命名有约定:枚举名用 PascalCase 单数(Role),值用 UPPER_SNAKE_CASE(USER)。字段类型直接写枚举名,@default(USER) 指定默认值。枚举字段同样支持可选(Role?)和列表(Role[],PostgreSQL 支持)。

枚举值也能映射到数据库里的不同名字,用值级 @map

enum Role {
  USER
  ADMIN @map("administrator")
}

代码里还是写 Role.ADMIN,数据库里存的是 administrator。枚举名整体映射用 @@map,用法与模型的 @@map 相同。

Note

在 PostgreSQL 中,枚举会生成真实的 CREATE TYPE;SQLite 没有原生枚举,Prisma 在 ORM 层校验、以 TEXT 存储;MySQL 则是内联的 ENUM 列。MongoDB 与枚举同为 ORM 层实现(v7 不支持 MongoDB,留 v6.19)。

在代码里使用枚举

生成客户端后,枚举从生成目录导入(v7 路径,不再是 @prisma/client):

import { PrismaClient } from "./generated/prisma/client";
import { Role } from "./generated/prisma/enums";

const prisma = new PrismaClient({ adapter });

await prisma.user.create({
  data: { email: "ada@example.com", role: Role.ADMIN },
});

过滤时枚举能参与全部比较操作符:

const admins = await prisma.user.findMany({
  where: { role: { in: [Role.ADMIN, Role.EDITOR] } },
});

innotInnotequals 都可用。更新枚举字段同样简单,直接赋新值:

await prisma.user.update({
  where: { id: 1 },
  data: { role: Role.EDITOR },
});

TS 里枚举是联合类型,switch 分支能获得穷尽检查,写错值编译期就报错。

Tip

外部输入(比如 HTTP 请求参数)是字符串,先校验再转枚举,别直接 as Role 强转。可以用 z.nativeEnum(Role)(Zod)这类方案。

枚举迁移的安全边界

枚举改动会触发迁移,三种操作风险不同:

  • 加值:安全。PostgreSQL 生成 ALTER TYPE ... ADD VALUE,追加到类型末尾。
  • 重命名值:危险。底层是删旧值建新值,已有数据引用旧值会失败,需要先写数据迁移。
  • 删值:危险。若还有行引用该值,删除直接报错。

改默认值也一样要迁移,DEFAULT 子句写在数据库层。所以枚举值一经发布,尽量只增不改。涉及枚举的迁移在 PostgreSQL 上生成 ALTER TYPE 语句,改默认值生成 ALTER TABLE ... ALTER COLUMN ... SET DEFAULT

@db.*:指定原生类型

Prisma 的每种标量类型都有默认映射,比如 String 在 PostgreSQL 里是 text。想精确控制列类型,用 @db.* 属性。它只在两种情况下需要:默认类型不满足需求,或内省出的库本就用了特殊类型

常用速查(PostgreSQL 主线):

Prisma 类型原生类型写法场景
String@db.VarChar(255)限制长度,配合索引
String@db.Text长文本(默认即 text,可省略)
String@db.Uuid原生 UUID 列,配合 uuid() 默认值
String@db.Citext大小写不敏感文本,需先启用扩展
Int@db.SmallInt小整数,省空间
DateTime@db.Timestamptz(6)带时区时间,精度 6 位
DateTime@db.Date只存日期
Json@db.JsonB二进制 JSON,支持更多查询操作
Decimal@db.Decimal(12,2)金额,两位小数
model Post {
  id        Int      @id @default(autoincrement())
  title     String   @db.VarChar(150)
  createdAt DateTime @default(now()) @db.Timestamptz(6)
  metadata  Json     @db.JsonB
}

迁移时,@db.VarChar(150) 会生成 VARCHAR(150) 列,@db.Timestamptz(6) 生成 TIMESTAMPTZ(6)——原生类型直接反映到建表 SQL。内省(prisma db pull)已有数据库时,如果列类型和 Prisma 默认映射不同,也会自动补上 @db.* 属性。

Tip

时间字段选 Timestamptz(带时区)还是 Timestamp(不带)是个经典取舍。存「这一刻」用带时区,能避免时区换算的坑;DateTime 在 JS 侧始终是 Date,差异只影响数据库层。

SQLite 的限制与 PG 扩展类型

SQLite 是轻量跟练线,限制要提前知道:标量类型只有 INTEGER、REAL、TEXT、BLOB,枚举靠 ORM 层实现,@db.* 基本无处可用,Json 也以 TEXT 存储。SQLite 适合学语法,生产环境换 PostgreSQL 即可平滑迁移。

PostgreSQL 的扩展类型则要先装扩展再用。比如 citext,通过自定义迁移执行 CREATE EXTENSION IF NOT EXISTS citext; 启用,之后才能写 @db.Citextgen_random_uuid() 同理,PG 13 以下需先启用 pgcrypto

参考来源

  • Prisma 官方文档:Models(Defining enums、Native types mapping)
  • Prisma 官方文档:Prisma schema reference(enum、@db 原生类型映射表)
  • Prisma 官方文档:Native database types、PostgreSQL extensions