跳到主要內容

模型

Prisma schema 的資料模型定義部分定義了你的應用程式模型(也稱為 Prisma 模型)。模型

  • 代表你的應用程式域的實體
  • 對映到資料庫中的(關係型資料庫如 PostgreSQL)或集合(MongoDB)
  • 構成生成的 Prisma Client API 中可用查詢的基礎
  • 與 TypeScript 一起使用時,Prisma Client 為你的模型及其任何變體提供生成的型別定義,以使資料庫訪問完全型別安全。

以下模式描述了一個部落格平臺 - 資料模型定義被高亮顯示

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

generator client {
provider = "prisma-client-js"
}

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}

model Profile {
id Int @id @default(autoincrement())
bio String
user User @relation(fields: [userId], references: [id])
userId Int @unique
}

model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
categories Category[]
}

model Category {
id Int @id @default(autoincrement())
name String
posts Post[]
}

enum Role {
USER
ADMIN
}

資料模型定義由以下部分組成

對應的資料庫看起來像這樣

Sample database

模型對映到資料來源的底層結構。
  • 在 PostgreSQL 和 MySQL 等關係型資料庫中,model 對映到一張
  • 在 MongoDB 中,model 對映到一個集合

注意:未來可能會有針對非關係型資料庫和其他資料來源的聯結器。例如,對於 REST API,它將對映到資源

以下查詢使用從這個資料模型生成的 Prisma Client 來建立

  • 一個 User 記錄
  • 兩個巢狀的 Post 記錄
  • 三個巢狀的 Category 記錄
const user = await prisma.user.create({
data: {
email: 'ariadne@prisma.io',
name: 'Ariadne',
posts: {
create: [
{
title: 'My first day at Prisma',
categories: {
create: {
name: 'Office',
},
},
},
{
title: 'How to connect to a SQLite database',
categories: {
create: [{ name: 'Databases' }, { name: 'Tutorials' }],
},
},
],
},
},
})

你的資料模型反映了你的應用程式域。例如

  • 電子商務應用程式中,你可能擁有 CustomerOrderItemInvoice 等模型。
  • 社交媒體應用程式中,你可能擁有 UserPostPhotoMessage 等模型。

內省和遷移

定義資料模型有兩種方式

  • 手動編寫資料模型並使用 Prisma Migrate:你可以手動編寫資料模型並使用 Prisma Migrate 將其對映到你的資料庫。在這種情況下,資料模型是應用程式模型的單一真實來源。
  • 透過內省生成資料模型:當你擁有現有資料庫或偏好使用 SQL 遷移資料庫模式時,你可以透過內省資料庫來生成資料模型。在這種情況下,資料庫模式是應用程式模型的單一真實來源。

定義模型

模型代表你的應用程式域的實體。模型由 model 塊表示,並定義了許多欄位。在上面的示例資料模型中,UserProfilePostCategory 都是模型。

部落格平臺可以透過以下模型進行擴充套件

model Comment {
// Fields
}

model Tag {
// Fields
}

將模型名稱對映到表或集合

Prisma 模型的命名約定(單數形式,PascalCase)並不總是與資料庫中的表名匹配。資料庫中命名錶/集合的常見方法是使用複數形式和snake_case表示法——例如:comments。當你內省一個名為 comments 的資料庫表時,結果 Prisma 模型將如下所示

model comments {
// Fields
}

但是,你仍然可以透過使用 @@map 屬性來遵守命名約定,而無需重新命名資料庫中底層的 comments

model Comment {
// Fields

@@map("comments")
}

透過此模型定義,Prisma ORM 會自動將 Comment 模型對映到底層資料庫中的 comments 表。

注意:你也可以 @map 一個列名或列舉值,以及 @@map 一個列舉名。

@map@@map 允許你透過將模型和欄位名稱與底層資料庫中的表和列名稱解耦,從而調整 Prisma Client API 的形狀

定義欄位

模型的屬性稱為欄位,它們包括

欄位的型別決定其結構,並分為兩類

  • 標量型別(包括列舉),它們對映到資料庫中的列(關係型資料庫)或文件欄位(MongoDB)——例如,StringInt
  • 模型型別(此時該欄位稱為關係欄位)——例如 PostComment[]

下表描述了示例模式中 User 模型的欄位

展開以查看錶格
名稱型別標量 vs 關係型別修飾符屬性
idInt標量-@id@default(autoincrement())
emailString標量-@unique
nameString標量?-
roleRole標量 (enum)-@default(USER)
postsPost關係 (Prisma 級別欄位)[]-
profileProfile關係 (Prisma 級別欄位)?-

標量欄位

以下示例使用多個標量型別擴充套件了 CommentTag 模型。有些欄位包含屬性

model Comment {
id Int @id @default(autoincrement())
title String
content String
}

model Tag {
name String @id
}

參閱標量欄位型別的完整列表

關係欄位

關係欄位的型別是另一個模型——例如,一個帖子 (Post) 可以有多個評論 (Comment[])

model Post {
id Int @id @default(autoincrement())
// Other fields
comments Comment[] // A post can have many comments
}

model Comment {
id Int
// Other fields
post Post? @relation(fields: [postId], references: [id]) // A comment can have one post
postId Int?
}

有關模型之間關係的更多示例和資訊,請參閱關係文件

原生型別對映

版本 2.17.0 及更高版本支援原生資料庫型別屬性(型別屬性),它們描述了底層資料庫型別

model Post {
id Int @id
title String @db.VarChar(200)
content String
}

型別屬性是

  • 特定於底層提供者——例如,PostgreSQL 對 Boolean 使用 @db.Boolean,而 MySQL 使用 @db.TinyInt(1)
  • 以 PascalCase 編寫(例如,VarCharText
  • @db 為字首,其中 db 是模式中 datasource 塊的名稱

此外,在內省期間,只有當底層原生型別**不是預設型別**時,型別屬性才會被新增到模式中。例如,如果你使用的是 PostgreSQL 提供程式,那麼底層原生型別為 textString 欄位將不會有型別屬性。

請參閱每種標量型別和提供者的原生資料庫型別屬性的完整列表

優勢和工作流

  • 控制 Prisma Migrate 在資料庫中建立的精確原生型別——例如,一個 String 可以是 @db.VarChar(200)@db.Char(50)
  • 當你內省時,檢視豐富的模式

型別修飾符

欄位型別可以透過附加以下兩種修飾符之一進行修改

  • [] 將欄位設為列表
  • ? 將欄位設為可選

注意:你**不能**組合型別修飾符——不支援可選列表。

列表

以下示例包含標量列表和相關模型列表

model Post {
id Int @id @default(autoincrement())
// Other fields
comments Comment[] // A list of comments
keywords String[] // A scalar list
}

注意:只有當資料庫聯結器原生或在 Prisma ORM 級別支援標量列表時,才支援標量列表。

可選欄位和必填欄位

model Comment {
id Int @id @default(autoincrement())
title String
content String?
}

model Tag {
name String @id
}

當一個欄位**未**用 ? 型別修飾符註釋時,該欄位在模型的每條記錄上都是必需的。這在兩個層面產生影響

  • 資料庫
    • 關係型資料庫:必需欄位透過底層資料庫中的 NOT NULL 約束表示。
    • MongoDB:必需欄位在 MongoDB 資料庫級別不是一個概念。
  • Prisma Client:Prisma Client 生成的代表應用程式程式碼中模型的TypeScript 型別也將這些欄位定義為必需,以確保它們在執行時始終帶有值。

注意:可選欄位的預設值為 null

不支援的型別

當你內省關係型資料庫時,不支援的資料型別會以 Unsupported 的形式新增

location    Unsupported("POLYGON")?

Unsupported 型別允許你在 Prisma 模式中定義 Prisma ORM 尚未支援的資料庫型別的欄位。例如,MySQL 的 POLYGON 型別目前不受 Prisma ORM 支援,但現在可以使用 Unsupported("POLYGON") 型別新增到 Prisma 模式中。

型別為 Unsupported 的欄位不會出現在生成的 Prisma Client API 中,但你仍然可以使用 Prisma ORM 的原始資料庫訪問功能來查詢這些欄位。

注意:如果模型有**強制性的 Unsupported 欄位**,則生成的客戶端將不包含該模型的 createupdate 方法。

注意:MongoDB 聯結器不支援也不要求 Unsupported 型別,因為它支援所有標量型別。

定義屬性

屬性修改欄位或模型塊的行為。以下示例包含三個欄位屬性(@id@default@unique)和一個塊屬性(@@unique

model User {
id Int @id @default(autoincrement())
firstName String
lastName String
email String @unique
isAdmin Boolean @default(false)

@@unique([firstName, lastName])
}

一些屬性接受引數——例如,@default 接受 truefalse

isAdmin   Boolean @default(false) // short form of @default(value: false)

請參閱欄位和塊屬性的完整列表

定義 ID 欄位

ID 唯一標識模型的單個記錄。一個模型只能有一個 ID

  • 在**關係型資料庫**中,ID 可以是單個欄位或基於多個欄位。如果模型沒有 @id@@id,則必須定義一個強制性的 @unique 欄位或 @@unique 塊來代替。
  • 在**MongoDB**中,ID 必須是一個定義了 @id 屬性和 @map("_id") 屬性的單一欄位。

在關係型資料庫中定義 ID

在關係型資料庫中,ID 可以透過使用 @id 屬性的單個欄位來定義,或者透過使用 @@id 屬性的多個欄位來定義。

單欄位 ID

在以下示例中,User 的 ID 由 id 整數字段表示

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}
複合 ID

在下面的例子中,User 的 ID 由 firstNamelastName 欄位的組合表示

model User {
firstName String
lastName String
email String @unique
isAdmin Boolean @default(false)

@@id([firstName, lastName])
}

預設情況下,此欄位在 Prisma Client 查詢中的名稱將為 firstName_lastName

你也可以使用 @@id 屬性的 name 欄位為複合 ID 提供自己的名稱

model User {
firstName String
lastName String
email String @unique
isAdmin Boolean @default(false)

@@id(name: "fullName", fields: [firstName, lastName])
}

firstName_lastName 欄位現在將命名為 fullName

資訊

請參閱使用複合 ID 的文件,瞭解如何在 Prisma Client 中與複合 ID 互動。

@unique 欄位作為唯一識別符號

在以下示例中,使用者透過 @unique 欄位唯一標識。由於 email 欄位充當模型的唯一識別符號(這是必需的),因此它必須是強制性的

model User {
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}
資訊

關係型資料庫中的約束名稱
你可以選擇在底層資料庫中定義一個自定義主鍵約束名稱

在 MongoDB 中定義 ID

MongoDB 聯結器對於定義 ID 欄位有特定的規則,這些規則與關係型資料庫不同。ID 必須由一個使用 @id 屬性的單個欄位定義,並且必須包含 @map("_id")

在以下示例中,User 的 ID 由 id 字串欄位表示,該欄位接受一個自動生成的 ObjectId

model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}

在以下示例中,User 的 ID 由 id 字串欄位表示,該欄位接受除 ObjectId 之外的值——例如,一個唯一的使用者名稱

model User {
id String @id @map("_id")
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}
警告

MongoDB 不支援 @@id
MongoDB 不支援複合 ID,這意味著你不能用 @@id 塊來標識一個模型。

定義預設值

你可以使用 @default 屬性為模型的標量欄位定義預設值

model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
title String
published Boolean @default(false)
data Json @default("{ \"hello\": \"world\" }")
author User @relation(fields: [authorId], references: [id])
authorId Int
categories Category[] @relation(references: [id])
}

@default 屬性要麼

  • 代表底層資料庫中的 DEFAULT 值(僅限關係型資料庫)或者
  • 使用 Prisma ORM 級別的函式。例如,cuid()uuid() 由 Prisma Client 的查詢引擎為所有聯結器提供。

預設值可以是

  • 與欄位型別對應的靜態值,例如 5 (Int)、Hello (String) 或 false (Boolean)
  • 靜態值的列表,例如 [5, 6, 8] (Int[]) 或 ["Hello", "Goodbye"] (String[])。這些在 Prisma ORM 4.0.0 及更高版本中可用,並且在使用支援的資料庫(PostgreSQL、CockroachDB 和 MongoDB)時。
  • 函式,例如 now()uuid()
  • JSON 資料。請注意,JSON 需要在 @default 屬性中用雙引號括起來,例如:@default("[]")。如果要提供 JSON 物件,需要用雙引號括起來,然後使用反斜槓轉義任何內部雙引號,例如:@default("{ \"hello\": \"world\" }")
資訊

有關聯結器對函式支援的資訊,請參閱屬性函式參考文件

定義唯一欄位

你可以向模型新增唯一屬性,以便能夠唯一標識該模型的單個記錄。唯一屬性可以在單個欄位上使用@unique屬性定義,也可以在多個欄位上(也稱為複合或組合唯一約束)使用@@unique屬性定義。

在以下示例中,email 欄位的值必須是唯一的

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}

在以下示例中,authorIdtitle 的組合必須是唯一的

model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
title String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
categories Category[] @relation(references: [id])

@@unique([authorId, title])
}
資訊

關係型資料庫中的約束名稱
你可以選擇在底層資料庫中定義一個自定義唯一約束名稱

預設情況下,此欄位在 Prisma Client 查詢中的名稱將為 authorId_title

你也可以使用 @@unique 屬性的 name 欄位為複合唯一約束提供自己的名稱

model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
createdAt DateTime @default(now())
title String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId
categories Category[] @relation(references: [id])

@@unique(name: "authorTitle", [authorId, title])
}

authorId_title 欄位現在將命名為 authorTitle

資訊

有關使用複合唯一識別符號的文件,請參閱如何在 Prisma Client 中與複合唯一約束互動。

複合型別唯一約束

在使用版本 3.12.0 及更高版本的 MongoDB 提供程式時,你可以使用語法 @@unique([compositeType.field])複合型別的欄位上定義唯一約束。與其他欄位一樣,複合型別欄位可以用作多列唯一約束的一部分。

以下示例定義了一個基於 User 模型的 email 欄位和 Address 複合型別(在 User.address 中使用)的 number 欄位的多列唯一約束

schema.prisma
type Address {
street String
number Int
}

model User {
id Int @id
email String
address Address

@@unique([email, address.number])
}

如果存在多個巢狀複合型別,則可以鏈式使用此表示法

schema.prisma
type City {
name String
}

type Address {
number Int
city City
}

model User {
id Int @id
address Address[]

@@unique([address.city.name])
}

定義索引

你可以透過模型上的 @@index 在模型的一個或多個欄位上定義索引。以下示例定義了一個基於 titlecontent 欄位的多列索引

model Post {
id Int @id @default(autoincrement())
title String
content String?

@@index([title, content])
}
資訊

關係型資料庫中的索引名稱
你可以選擇在底層資料庫中定義一個自定義索引名稱

定義複合型別索引

當在版本 3.12.0 及更高版本中使用 MongoDB 提供程式時,你可以使用語法 @@index([compositeType.field])複合型別的欄位上定義索引。與其他欄位一樣,複合型別欄位可以用作多列索引的一部分。

以下示例定義了一個基於 User 模型的 email 欄位和 Address 複合型別的 number 欄位的多列索引

schema.prisma
type Address {
street String
number Int
}

model User {
id Int @id
email String
address Address

@@index([email, address.number])
}

如果存在多個巢狀複合型別,則可以鏈式使用此表示法

schema.prisma
type City {
name String
}

type Address {
number Int
city City
}

model User {
id Int @id
address Address[]

@@index([address.city.name])
}

定義列舉

如果你的資料庫聯結器支援列舉(原生或在 Prisma ORM 級別),你可以在資料模型中定義列舉。

列舉在 Prisma schema 資料模型中被視為標量型別。因此,它們預設情況下作為返回值包含在Prisma Client 查詢中。

列舉透過 enum 塊定義。例如,User 具有 Role

model User {
id Int @id @default(autoincrement())
email String @unique
name String?
role Role @default(USER)
}

enum Role {
USER
ADMIN
}

定義複合型別

資訊

複合型別是在版本 3.10.0 中以 mongodb 預覽功能標誌新增的,並自版本 3.12.0 起普遍可用。

警告

複合型別目前僅在 MongoDB 上可用。

複合型別(在 MongoDB 中稱為嵌入式文件)透過允許你定義新的物件型別來支援在其他記錄中嵌入記錄。複合型別的結構和型別與模型類似。

要定義複合型別,請使用 type 塊。例如,請看以下模式

schema.prisma
model Product {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String
photos Photo[]
}

type Photo {
height Int
width Int
url String
}

在這種情況下,Product 模型有一個儲存在 photos 中的 Photo 複合型別列表。

使用複合型別時的注意事項

複合型別僅支援有限的屬性集。支援以下屬性

複合型別中不支援以下屬性

  • @unique
  • @id
  • @relation
  • @ignore
  • @updatedAt

然而,唯一約束仍然可以透過在複合型別所使用的模型級別上使用 @@unique 屬性來定義。更多詳情,請參閱複合型別唯一約束

索引可以透過在複合型別所使用的模型級別上使用 @@index 屬性來定義。更多詳情,請參閱複合型別索引

使用函式

Prisma schema 支援許多函式。這些函式可用於指定模型欄位的預設值

例如,createdAt 的預設值是 now()

model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
}

cuid()uuid() 由 Prisma ORM 實現,因此在底層資料庫模式中是“不可見”的。你仍然可以透過手動更改你的 Prisma schema生成 Prisma Client 來在使用內省時使用它們,在這種情況下,這些值將由 Prisma Client 的查詢引擎生成

autoincrement()now()dbgenerated(...) 的支援因資料庫而異。

關係型資料庫聯結器在資料庫層面實現 autoincrement()dbgenerated(...)now()MongoDB 聯結器不支援 autoincrement()dbgenerated(...),並且 now() 在 Prisma ORM 層面實現。auto() 函式用於生成 ObjectId

關係

有關模型之間關係的更多示例和資訊,請參閱關係文件

Prisma Client 中的模型

查詢 (CRUD)

資料模型定義中的每個模型都將在生成的Prisma Client API中產生許多 CRUD 查詢

這些操作可透過 Prisma Client 例項上的生成屬性進行訪問。預設情況下,該屬性的名稱是模型名稱的小寫形式,例如,User 模型為 userPost 模型為 post

以下是說明 Prisma Client API 中 user 屬性使用情況的示例

const newUser = await prisma.user.create({
data: {
name: 'Alice',
},
})
const allUsers = await prisma.user.findMany()

型別定義

Prisma Client 還生成反映你的模型結構的**型別定義**。這些是生成的@prisma/client Node 模組的一部分。

使用 TypeScript 時,這些型別定義確保你的所有資料庫查詢在編譯時完全型別安全並經過驗證(即使是使用 selectinclude 的部分查詢)。

即使使用純 JavaScript,型別定義也仍然包含在 @prisma/client Node 模組中,從而在你的編輯器中啟用 IntelliSense/自動完成等功能。

注意:實際型別儲存在 .prisma/client 資料夾中。@prisma/client/index.d.ts 匯出此資料夾的內容。

例如,上面 User 模型的型別定義將如下所示

export type User = {
id: number
email: string
name: string | null
role: string
}

請注意,關係欄位 postsprofile 預設不包含在型別定義中。但是,如果你需要 User 型別的變體,你仍然可以使用 Prisma Client 生成的一些輔助型別來定義它們(在這種情況下,這些輔助型別將被稱為 UserGetIncludePayloadUserGetSelectPayload)。

限制

記錄必須是唯一可識別的

Prisma ORM 目前僅支援至少有一個唯一欄位或欄位組合的模型。實際上,這意味著每個 Prisma 模型都必須具有以下至少一個屬性

  • @id@@id 用於單欄位或多欄位主鍵約束(每個模型最多一個)
  • @unique@@unique 用於單欄位或多欄位唯一約束
© . This site is unofficial and not affiliated with Prisma Data, Inc.