深入理解 Prisma Model:型別修飾、屬性設定與關聯設計
在 Prisma Schema 中,資料模型(model)由純量型別(Scalar Types)、型別修飾符(Type Modifiers)、欄位與模型屬性(Attributes)以及基數關聯(Cardinality / Relations)所組成。
1. 資料型別(Data Types)與修飾符
核心純量型別(Scalar Types)
Prisma 提供跨資料庫通用的純量型別,並可搭配 @db.* 指定底層資料庫的精確型別:
| Prisma 型別 | TypeScript 對應 | 常見資料庫對應 (PostgreSQL / MySQL) | 說明 |
|---|---|---|---|
String |
string |
VARCHAR, TEXT |
字串。可搭配 @db.VarChar(255) 或 @db.Text |
Boolean |
boolean |
BOOLEAN, TINYINT(1) |
布林值 |
Int |
number |
INTEGER, INT |
32 位元有號整數 |
BigInt |
bigint |
BIGINT |
64 位元整數(TS 中以原生 BigInt 呈現) |
Float |
number |
DOUBLE PRECISION, FLOAT |
浮點數(IEEE 754) |
Decimal |
Prisma.Decimal |
DECIMAL(p, s), NUMERIC |
高精度小數(適合金額計算,避免浮點誤差) |
DateTime |
Date |
TIMESTAMP, TIMESTAMPTZ |
ISO-8601 時間戳記 |
Json |
Prisma.JsonValue |
JSON, JSONB |
結構化 JSON 物件 |
Bytes |
Buffer |
BYTEA, BLOB |
二進位二進制資料 |
型別修飾符(Modifiers)
- **選填(Optional)
?**:允許欄位為NULL(如bio String?)。 - **陣列(List)
[]**:純量陣列(如tags String[],僅 PostgreSQL/CockroachDB 原生支援;在 MySQL/SQLite 通常需透過關聯表實作)。
列舉(Enums)
自訂常數集合(需資料庫支援或由 Prisma 模擬):
enum Role {
USER
ADMIN
MODERATOR
}
model User {
id Int @id @default(autoincrement())
role Role @default(USER)
}
2. 屬性(Attributes)與函式(Functions)
屬性分為欄位級屬性(以 @ 開頭)與模型級屬性(以 @@ 開頭)。
欄位級屬性(Field Attributes)
-
@id:將欄位設為主鍵(Primary Key)。 -
@default(...):設定預設值,支援內建函式: -
autoincrement():自增整數。 -
uuid()/cuid()/nanoid():產生唯一識別碼字串。 -
now():當前時間戳記。 -
dbgenerated(...):調用資料庫原生函式(如gen_random_uuid())。 -
@unique:設定唯一約束(Unique Constraint)。 -
@updatedAt:記錄更新時自動更新為當前時間。 -
@map("db_column_name"):映射到資料庫中實際的欄位名稱(蛇形命名 vs 駝峰命名)。 -
@ignore:Prisma Client 忽略該欄位(不產生型別)。
模型級屬性(Model Attributes)
@@id([field1, field2]):設定複合主鍵(Composite Primary Key)。@@unique([field1, field2]):設定複合唯一約束。@@index([field1, field2]):建立資料庫索引(支援指定索引類型,如@@index([name], type: Gin))。@@map("db_table_name"):映射到資料庫中實際的資料表名稱。@@ignore:Prisma Client 忽略整張資料表。
3. 關聯基數(Cardinality & Relations)
關聯基數描述兩個模型之間的對應數量關係。Prisma 透過 @relation 屬性定義外鍵(Foreign Key)與參照。
1. 一對一(1-1 / One-to-One)
一筆資料恰好對應另一筆資料(例如:User 與 Profile)。
- 規則:外鍵(
userId)必須加上@unique。
model User {
id Int @id @default(autoincrement())
email String @unique
profile Profile? // 反向關聯(虛擬欄位,不存於資料庫 User 表中)
}
model Profile {
id Int @id @default(autoincrement())
bio String
userId Int @unique // 核心:唯一約束確保 1-1
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
2. 一對多(1-N / One-to-Many)
一筆資料可對應多筆資料(例如:User 與 Post)。
- 規則:「多」的一方(
Post)持有外鍵欄位(authorId)。
model User {
id Int @id @default(autoincrement())
posts Post[] // 一個使用者擁有多篇文章
}
model Post {
id Int @id @default(autoincrement())
title String
authorId Int // 外鍵欄位
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
@@index([authorId])
}
3. 多對多(M-N / Many-to-Many)
隱式多對多(Implicit M-N)
雙方皆宣告為陣列(Tag[] 與 Post[]),Prisma 會自動在底層建立並管理中介表(如 _PostToTag),無需手動定義 Model。
model Post {
id Int @id @default(autoincrement())
tags Tag[] // 隱式多對多
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
posts Post[]
}
顯式多對多(Explicit M-N) 當中介表需要儲存額外屬性(如建立時間、角色權限、排序)時,必須手動定義中介 Model。
model Post {
id Int @id @default(autoincrement())
title String
categories PostOnCategory[]
}
model Category {
id Int @id @default(autoincrement())
name String
posts PostOnCategory[]
}
// 手動定義中介表
model PostOnCategory {
postId Int
categoryId Int
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)
assignedAt DateTime @default(now()) // 額外欄位
assignedBy String?
@@id([postId, categoryId]) // 複合主鍵
}
4. 參照動作(Referential Actions)
在 @relation 屬性中,可透過 onDelete 與 onUpdate 定義父記錄變更時子記錄的行為:
| 動作(Action) | 行為說明 |
|---|---|
Cascade |
父記錄刪除/更新時,自動刪除/更新關聯的子記錄。 |
SetNull |
父記錄刪除/更新時,將子記錄的外鍵設為 NULL(外鍵欄位必須為 Optional)。 |
Restrict |
若存在子記錄,阻止父記錄被刪除/更新。 |
NoAction |
資料庫原生行為(類似 Restrict,但在交易結束時才檢查約束)。 |
SetDefault |
父記錄刪除/更新時,將子記錄外鍵設為預設值。 |