關係模式
在 Prisma schema 中,記錄間的關係透過 @relation 屬性定義。例如,在以下 schema 中,User 和 Post 模型之間存在一對多關係
model Post {
id Int @id @default(autoincrement())
title String
author User @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade)
authorId Int
}
model User {
id Int @id @default(autoincrement())
posts Post[]
}
Prisma ORM 擁有兩種關係模式:foreignKeys 和 prisma,它們指定了記錄間關係的強制執行方式。
如果您將 Prisma ORM 與關係型資料庫一起使用,則預設情況下,Prisma ORM 使用foreignKeys 關係模式,該模式在資料庫級別透過外部索引鍵強制執行記錄間的關係。外部索引鍵是表中的一列或一組列,其值基於另一個表中的主鍵。外部索引鍵允許您
- 設定約束以防止您進行破壞引用的更改
- 設定引用操作,以定義如何處理對記錄的更改
這些約束和引用操作共同保證了資料的引用完整性。
對於上述示例 schema,如果您使用 PostgreSQL 聯結器,Prisma Migrate 將預設生成以下 SQL
-- CreateTable
CREATE TABLE "Post" (
"id" SERIAL NOT NULL,
"title" TEXT NOT NULL,
"authorId" INTEGER NOT NULL,
CONSTRAINT "Post_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "User" (
"id" SERIAL NOT NULL,
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);
-- AddForeignKey
//highlight-start
ALTER TABLE "Post"
ADD CONSTRAINT "Post_authorId_fkey"
FOREIGN KEY ("authorId")
REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
//highlight-end
在這種情況下,Post 表的 authorId 列上的外部索引鍵約束引用了 User 表的 id 列,並保證帖子必須擁有一個存在的作者。如果您更新或刪除使用者,則 ON DELETE 和 ON UPDATE 引用操作指定了 CASCADE 選項,該選項也將刪除或更新屬於該使用者的所有帖子。
某些資料庫,例如 MongoDB 或 PlanetScale,不支援外部索引鍵。此外,在某些情況下,開發人員可能更傾向於不在通常支援外部索引鍵的關係型資料庫中使用外部索引鍵。對於這些情況,Prisma ORM 提供了prisma 關係模式,該模式模擬了關係型資料庫中關係的一些屬性。當您啟用 prisma 關係模式並使用 Prisma Client 時,查詢行為相同或相似,但引用操作和一些約束由 Prisma 引擎而不是資料庫處理。
在 Prisma Client 中模擬引用完整性和引用操作會帶來效能影響。在底層資料庫支援外部索引鍵的情況下,通常首選外部索引鍵。
如何在您的 Prisma schema 中設定關係模式
要設定關係模式,請在 datasource 塊中新增 relationMode 欄位
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma"
}
設定關係模式的功能作為 referentialIntegrity 預覽功能的一部分在 Prisma ORM 3.1.1 版本中引入,並在 Prisma ORM 4.8.0 及更高版本中普遍可用。relationMode 欄位在 Prisma ORM 4.5.0 版本中已重新命名,之前名為 referentialIntegrity。
對於關係型資料庫,可用選項為
foreignKeys:透過外部索引鍵處理資料庫中的關係。這是所有關係型資料庫聯結器的預設選項,如果datasource塊中未明確設定relationMode,則此選項處於活動狀態。prisma:在 Prisma Client 中模擬關係。當您使用 MySQL 聯結器與 PlanetScale 資料庫,並且在 PlanetScale 資料庫設定中未啟用原生外部索引鍵約束時,您也應該啟用此選項。
對於 MongoDB,唯一可用的選項是 prisma 關係模式。如果 datasource 塊中未明確設定 relationMode,此模式也處於活動狀態。
如果您在關係模式之間切換,Prisma ORM 將在下次使用 Prisma Migrate 或 db push 應用 schema 更改時,向資料庫新增或刪除外部索引鍵。有關更多資訊,請參閱在關係模式之間切換。
使用 foreignKeys 關係模式處理關係型資料庫中的關係
foreignKeys 關係模式透過外部索引鍵處理關係型資料庫中的關係。這是您使用關係型資料庫聯結器(PostgreSQL、MySQL、SQLite、SQL Server、CockroachDB)時的預設選項。
使用 MongoDB 聯結器時,foreignKeys 關係模式不可用。一些關係型資料庫,例如 PlanetScale,也禁止使用外部索引鍵。在這些情況下,您應該改為使用 prisma 關係模式在 Prisma ORM 中模擬關係。
引用完整性
foreignKeys 關係模式在資料庫級別透過外部索引鍵約束和引用操作維護引用完整性。
外部索引鍵約束
當您建立或更新一個與另一條記錄存在關係的記錄時,相關記錄必須存在。外部索引鍵約束在資料庫中強制執行此行為。如果記錄不存在,資料庫將返回錯誤訊息。
引用操作
當您更新或刪除一個與另一條記錄存在關係的記錄時,資料庫中會觸發引用操作。為了維護相關記錄的引用完整性,引用操作會阻止破壞引用完整性的更改,將更改級聯到相關記錄,或者將引用已更新或已刪除記錄的欄位值設定為 null 或預設值。
有關更多資訊,請參閱引用操作頁面。
內省
當您使用 db pull 命令並在啟用 foreignKeys 關係模式的情況下內省關係型資料庫時,對於存在外部索引鍵的關係,您的 Prisma schema 中將新增一個 @relation 屬性。
Prisma Migrate 和 db push
當您使用 Prisma Migrate 或 db push 並在啟用 foreignKeys 關係模式的情況下將更改應用於您的 Prisma schema 時,資料庫中將為 schema 中的所有 @relation 屬性建立外部索引鍵。
使用 prisma 關係模式在 Prisma ORM 中模擬關係
prisma 關係模式透過一些額外的資料庫查詢和邏輯,為每個 Prisma Client 查詢模擬某些外部索引鍵約束和引用操作,以維護引用完整性。
prisma 關係模式是 MongoDB 聯結器的預設選項。如果您使用的關係型資料庫不支援外部索引鍵,也應設定此模式。例如,如果您使用 PlanetScale 且沒有外部索引鍵約束,則應使用 prisma 關係模式。
在 Prisma Client 中模擬引用完整性會帶來效能影響,因為它會使用額外的資料庫查詢來維護引用完整性。在底層資料庫可以使用外部索引鍵處理引用完整性的情況下,通常首選外部索引鍵。
關係的模擬僅適用於 Prisma Client 查詢,不適用於原生查詢。
哪些外部索引鍵約束被模擬?
當您更新記錄時,Prisma ORM 將模擬外部索引鍵約束。這意味著當您更新一條與另一條記錄存在關係的記錄時,相關記錄必須存在。如果記錄不存在,Prisma Client 將返回錯誤訊息。
然而,當您建立記錄時,Prisma ORM 不會模擬任何外部索引鍵約束。您將能夠建立無效資料。
哪些引用操作被模擬?
當您更新或刪除一條帶有相關記錄的記錄時,Prisma ORM 將模擬引用操作。
下表顯示了每個資料庫聯結器可用的模擬引用操作
| 資料庫 | 級聯 | 限制 | 無動作 | 設為空 | 設為預設 |
|---|---|---|---|---|---|
| PostgreSQL | ✔️ | ✔️ | ❌‡ | ✔️ | ❌† |
| MySQL | ✔️ | ✔️ | ✔️ | ✔️ | ❌† |
| SQLite | ✔️ | ✔️ | ❌‡ | ✔️ | ❌† |
| SQL Server | ✔️ | ✔️ | ✔️ | ✔️ | ❌† |
| CockroachDB | ✔️ | ✔️ | ✔️ | ✔️ | ❌† |
| MongoDB | ✔️ | ✔️ | ✔️ | ✔️ | ❌† |
- †
prisma關係模式不支援SetDefault引用操作。 - ‡ PostgreSQL 和 SQLite 的
prisma關係模式不支援NoAction引用操作。請改為使用Restrict操作。
錯誤訊息
prisma 關係模式中由模擬約束和引用操作返回的錯誤訊息由 Prisma Client 生成,與 foreignKeys 關係模式中的錯誤訊息略有不同
Example:
// foreignKeys:
... Foreign key constraint failed on the field: `ProfileOneToOne_userId_fkey (index)`
// prisma:
... The change you are trying to make would violate the required relation 'ProfileOneToOneToUserOneToOne' between the `ProfileOneToOne` and `UserOneToOne` models.
內省
當您使用 db pull 命令並在啟用 prisma 關係模式的情況下內省資料庫時,關係將不會自動新增到您的 schema 中。您將需要手動使用 @relation 屬性新增任何關係。這隻需要做一次——下次您內省資料庫時,Prisma ORM 將保留您新增的 @relation 屬性。
Prisma Migrate 和 db push
當您使用 Prisma Migrate 或 db push 並在啟用 prisma 關係模式的情況下將更改應用於您的 Prisma schema 時,Prisma ORM 將不會在您的資料庫中使用外部索引鍵。
索引
在使用外部索引鍵約束的關係型資料庫中,資料庫通常也會隱式地為外部索引鍵列建立索引。例如,MySQL 將在外部索引鍵列上建立索引。這是為了讓外部索引鍵檢查能夠快速執行,且不需要進行全表掃描。
prisma 關係模式不使用外部索引鍵,因此當您使用 Prisma Migrate 或 db push 將更改應用於資料庫時,不會建立索引。您需要手動使用 @@index 屬性(或在適用情況下使用 @unique、@@unique 或 @@id 屬性)在您的關係標量欄位上新增索引。
索引驗證
如果您不手動新增索引,查詢可能需要進行全表掃描。這可能會很慢,並且對於按訪問行數計費的資料庫提供商來說也可能很昂貴。為了幫助避免這種情況,當您的 schema 包含用於 @relation 但未定義索引的欄位時,Prisma ORM 會發出警告。例如,以下 schema 中包含 User 和 Post 模型之間的關係
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma"
}
model User {
id Int @id
posts Post[]
}
model Post {
id Int @id
userId Int
user User @relation(fields: [userId], references: [id])
}
當您執行 prisma format 或 prisma validate 時,Prisma ORM 會顯示以下警告
With `relationMode = "prisma"`, no foreign keys are used, so relation fields will not benefit from the index usually created by the relational database under the hood. This can lead to poor performance when querying these fields. We recommend adding an index manually.
要解決此問題,請在您的 Post 模型中新增索引
model Post {
id Int @id
userId Int
user User @relation(fields: [userId], references: [id])
@@index([userId])
}
如果您使用 Prisma VS Code 擴充套件(或我們在其他編輯器中的語言伺服器),該警告會透過一個快速修復來增強,為您新增所需的索引。

在關係模式之間切換
只有在使用關係型資料庫聯結器(PostgreSQL、MySQL、SQLite、SQL Server、CockroachDB)時,才可以在關係模式之間切換。
從 foreignKeys 切換到 prisma
如果您使用關係型資料庫且未在 datasource 塊中包含 relationMode 欄位,則預設關係模式為 foreignKeys。要切換到 prisma 關係模式,請新增值為 prisma 的 relationMode 欄位,如果該欄位已存在,則將其值更新為 prisma。
當您將關係模式從 foreignKeys 切換到 prisma 後,首次使用 Prisma Migrate 或 db push 應用 schema 更改時,Prisma ORM 將在下一次遷移中刪除所有先前建立的外部索引鍵。
如果您保留相同的資料庫,則可以正常繼續工作。如果您切換到根本不支援外部索引鍵的資料庫,您現有的遷移歷史將包含建立外部索引鍵的 SQL DDL,如果您必須重新執行這些遷移,這可能會觸發錯誤。在這種情況下,我們建議您刪除 migrations 目錄。(如果您使用 PlanetScale,它不支援外部索引鍵,我們通常建議您使用 db push 而非 Prisma Migrate。)
從 prisma 切換到 foreignKeys
要從 prisma 關係模式切換到 foreignKeys 關係模式,請將 relationMode 欄位值從 prisma 更新為 foreignKeys。為此,資料庫必須支援外部索引鍵。當您在切換關係模式後首次使用 Prisma Migrate 或 db push 應用 schema 更改時,Prisma ORM 將在下一次遷移中為所有關係建立外部索引鍵。