模型与字段:标量类型与修饰符
本教程共 54 篇 · 第 8 篇 · 更新于 2026-08-11 · 约 6 分钟阅读
本节目标:掌握 model 块的写法、九种标量类型与
?/[]修饰符,认识常用字段属性。
模型(model)是 Schema 的主角。一个模型代表业务里的一个实体,比如用户、订单、文章;在关系型数据库里,它对应一张表。模型的名字用 PascalCase 单数形式(User 而不是 users),字段名用 camelCase(firstName)。命名要满足正则 [A-Za-z][A-Za-z0-9_]*:字母开头,后面可以是字母、数字、下划线。表名想用复数或 snake_case,那是数据库层的事,用 @@map 解耦(下文细说)。
字段的四要素
每个字段由四部分组成:名字、类型、可选的修饰符、可选的属性。
model User {
id Int @id @default(autoincrement()) // 名字 类型 属性
email String @unique
name String? // ? 是修饰符
createdAt DateTime @default(now())
}
字段类型分两类:标量类型(对应数据库的一列)和模型类型(即关系字段,指向另一个模型,第 11 章详解)。本节只看标量。
九种标量类型
| Prisma 类型 | TypeScript 类型 | PostgreSQL 默认 | 用途 |
|---|---|---|---|
String | string | text | 文本 |
Boolean | boolean | boolean | 真假值 |
Int | number | integer | 32 位整数 |
BigInt | bigint | bigint | 大整数,超出 Int 范围时用 |
Float | number | double precision | 浮点数 |
Decimal | Decimal.js | decimal(65,30) | 高精度小数,金额推荐 |
DateTime | Date | timestamp(3) | 时间 |
Json | JsonValue | jsonb | 任意 JSON 数据 |
Bytes | Uint8Array | bytea | 二进制数据 |
选择原则很简单:整数用 Int,超大整数用 BigInt,钱用 Decimal 而不是 Float(浮点有精度误差),结构化数据用 Json。
几个容易踩的类型细节:
Int是 32 位整数,上限约 21 亿。计数、ID 完全够用;一旦可能超过(比如埋点数据的累计值),提前用BigInt。Decimal精度可达 65 位,钱和精确计算用它;Float适合不需要精确相等的科学计算。Json适合结构不固定的数据(配置、元数据)。注意它是「不透明」的,查询过滤能力有限。Bytes存二进制,比如文件哈希、图片数据。DateTime在 JS 侧永远是Date对象,存的是时间戳语义,别拿它当字符串用。
修饰符:? 与 []
修饰符改变字段的可选性:
?让字段可空,对应数据库的NULL。name String?表示名字可以没有。[]让字段变成列表,如String[]存多个字符串。列表修饰符在关系里更常见(Post[])。
model Comment {
id Int @id @default(autoincrement())
title String // 必填,数据库里是 NOT NULL
content String? // 可选,可为 NULL
tags String[] // 标量列表
}
不加修饰符的字段必填。在 TypeScript 侧,可选字段类型是 string | null,编译期就强制你处理空值。数据库层面对应 NOT NULL 约束——迁移时 Prisma 会按修饰符自动生成 NOT NULL 或可空列。
一个完整的模型
把本节知识拼起来,看一个完整例子:
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
age Int @default(18)
score Decimal @default(0) @db.Decimal(10, 2)
createdAt DateTime @default(now())
posts Post[]
@@map("users")
}
既有必填、可选、默认值,又有原生类型和表名映射。模型之间的关系字段(posts Post[])留到第 11 章,这里先把标量字段的骨架搭扎实。
Note
?和[]不能组合使用——不支持「可选的列表」。另外标量列表需要数据库原生支持,PostgreSQL 没问题,SQLite 不支持。
常用字段属性总览
属性(attribute)以 @ 开头,修改字段或模型的行为。先认识最常见的几个,细节在后续章节展开:
| 属性 | 作用 |
|---|---|
@id | 标记为主键(第 9 章) |
@unique | 唯一约束(第 9 章) |
@default(...) | 默认值,可填静态值或函数(第 9 章) |
@map("列名") | 把字段映射到指定数据库列名 |
@updatedAt | 更新时自动写时间(第 9 章) |
@ignore | 从生成的 Prisma Client 中排除该字段 |
@db.XXX | 指定原生数据库类型,如 @db.VarChar(255)(第 10 章) |
以 @@ 开头的是块属性,作用于整个模型:@@map("表名")、@@id([...])、@@unique([...])、@@index([...])。
@map:模型名与表名解耦
Prisma 的命名习惯(PascalCase 单数)未必和数据库一致。数据库表常用复数 snake_case,比如 comments。用 @@map 让两边各用各的名字:
model Comment {
id Int @id @default(autoincrement())
author String @map("author_name") // 列名是 author_name
content String
@@map("comments") // 表名是 comments
}
代码里依然用 prisma.comment 和 author,数据库里却是 comments 表和 author_name 列。@map 管字段,@@map 管模型,互不干扰。
@ignore:不想暴露的字段
有些字段(比如内部标志位)不想让 Prisma Client 碰。加上 @ignore,它就从生成的客户端里消失:
model User {
id Int @id @default(autoincrement())
name String
email String @ignore // 客户端看不到这个字段
}
Note必填字段若加
@ignore且没有默认值,模型的 create 方法会被禁用,因为数据库无法在没有该数据的情况下建行。内省对无法表达的列用Unsupported标记;想排除模型需手动加@@ignore。
默认值函数一览
@default() 除了填静态值(5、"draft"、false),还可以调函数:
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
uuid String @default(uuid())
status String @default("draft")
}
常用函数有 now()(当前时间)、uuid()(UUID)、cuid()(CUID)、nanoid()(NanoID)、autoincrement()(自增)、dbgenerated("SQL")(原生 SQL 默认值)。每个函数的适用场景和细节,第 9 章逐个讲透。
参考来源
- Prisma 官方文档:Models(数据模型定义)、Prisma schema reference(标量类型与属性)
- Prisma 官方文档:Attribute functions