跳到主要內容

模型

Prisma 結構描述的資料模型定義部分定義了您的應用程式模型(也稱為 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 對於 Boolean 使用 @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。

單一欄位 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 由接受自動產生的 ObjectIdid 字串欄位表示

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 由接受 ObjectId 以外內容(例如,唯一的使用者名稱)的 id 字串欄位表示

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 複合類型的 number 欄位,該複合類型在 User.address 中使用

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 結構描述資料模型中被視為純量類型。因此,它們預設情況下包含在 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 結構描述支援許多函數。這些函數可用於指定模型欄位的預設值

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

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

cuid()uuid() 由 Prisma ORM 實作,因此在底層資料庫結構描述中「不可見」。當使用 內省 (introspection) 時,您仍然可以使用它們,方法是手動變更您的 Prisma 結構描述產生 Prisma Client,在這種情況下,這些值將由 Prisma Client 的 查詢引擎 產生。

對於 autoincrement()now()dbgenerated(...) 的支援在不同資料庫之間有所差異。

關聯式資料庫連接器 在資料庫層級實作 autoincrement()dbgenerated(...)now()MongoDB 連接器 不支援 autoincrement()dbgenerated(...),而 now() 則在 Prisma ORM 層級實作。auto() 函數用於產生 ObjectId

關聯 (Relations)

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

Prisma Client 中的模型 (Models in Prisma Client)

查詢 (CRUD) (Queries (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()

類型定義 (Type definitions)

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)。

限制 (Limitations)

記錄必須是唯一可識別的 (Records must be uniquely identifiable)

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

  • 單欄位或多欄位主鍵約束的 @id@@id (每個模型最多一個)
  • 單欄位或多欄位唯一約束的 @unique@@unique