關聯模式
在 Prisma 結構描述中,記錄之間的關聯是使用 @relation
屬性定義的。例如,在以下結構描述中,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
關聯模式,該模式使用外鍵在資料庫層級強制執行記錄之間的關聯。外鍵是一個表格中的一欄或一組欄,它們的值基於另一個表格中的主鍵。外鍵允許您
- 設定約束,以防止您進行會破壞參考的變更
- 設定 參考動作,以定義如何處理記錄的變更
這些約束和參考動作共同保證資料的參考完整性。
對於上述範例結構描述,如果您使用 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 結構描述中設定關聯模式
若要設定關聯模式,請在 datasource
區塊中新增 relationMode
欄位
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma"
}
設定關聯模式的功能是在 Prisma ORM 3.1.1 版中作為 referentialIntegrity
預覽功能的一部分引入的,並且在 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
將變更套用至結構描述時,在您的資料庫中新增或移除外鍵。請參閱 在關聯模式之間切換 以取得更多資訊。
使用 foreignKeys
關聯模式處理關聯式資料庫中的關聯
foreignKeys
關聯模式使用外鍵處理關聯式資料庫中的關聯。當您使用關聯式資料庫連接器 (PostgreSQL、MySQL、SQLite、SQL Server、CockroachDB) 時,這是預設選項。
當您使用 MongoDB 連接器時,foreignKeys
關聯模式不可用。某些關聯式資料庫(例如 PlanetScale)也禁止使用外鍵。在這些情況下,您應該改為使用 prisma
關聯模式在 Prisma ORM 中模擬關聯。
參考完整性
foreignKeys
關聯模式使用外鍵約束和參考動作在資料庫層級維護參考完整性。
外鍵約束
當您建立或更新與另一個記錄有關係的記錄時,相關記錄需要存在。外鍵約束在資料庫中強制執行此行為。如果記錄不存在,資料庫將傳回錯誤訊息。
參考動作
當您更新或刪除與另一個記錄有關係的記錄時,參考動作會在資料庫中觸發。為了在相關記錄中維護參考完整性,參考動作會防止會破壞參考完整性的變更、將變更串聯到相關記錄,或將參考更新或刪除記錄的欄位值設定為 null
或預設值。
如需更多資訊,請參閱參考動作頁面。
內省
當您在啟用 foreignKeys
關聯模式的情況下,使用 db pull
命令內省關聯式資料庫時,對於存在外鍵的關聯,@relation
屬性將會新增至您的 Prisma 結構描述。
Prisma Migrate 和 db push
當您在啟用 foreignKeys
關聯模式的情況下,使用 Prisma Migrate 或 db push
將變更套用至您的 Prisma 結構描述時,將會在您的資料庫中為結構描述中的所有 @relation
屬性建立外鍵。
使用 prisma
關聯模式在 Prisma ORM 中模擬關聯
prisma
關聯模式會為每個 Prisma Client 查詢模擬一些外鍵約束和參考動作,以使用一些額外的資料庫查詢和邏輯來維護參考完整性。
prisma
關聯模式是 MongoDB 連接器的預設選項。如果您使用的關聯式資料庫不支援外鍵,也應該設定此模式。例如,如果您使用 PlanetScale 且沒有外鍵約束,則應該使用 prisma
關聯模式。
在 Prisma Client 中模擬參考完整性會產生效能影響,因為它使用額外的資料庫查詢來維護參考完整性。在底層資料庫可以使用外鍵處理參考完整性的情況下,通常是較佳的選擇。
關聯模擬僅適用於 Prisma Client 查詢,不適用於原始查詢。
模擬哪些外鍵約束?
當您更新記錄時,Prisma ORM 將模擬外鍵約束。這表示當您更新與另一個記錄有關係的記錄時,相關記錄需要存在。如果記錄不存在,Prisma Client 將傳回錯誤訊息。
但是,當您建立記錄時,Prisma ORM 不會模擬任何外鍵約束。您將能夠建立無效資料。
模擬哪些參考動作?
當您更新或刪除具有相關記錄的記錄時,Prisma ORM 將模擬參考動作。
下表顯示每個資料庫連接器可用的模擬參考動作
資料庫 | Cascade | Restrict | NoAction | SetNull | SetDefault |
---|---|---|---|---|---|
PostgreSQL | ✔️ | ✔️ | ❌‡ | ✔️ | ❌† |
MySQL | ✔️ | ✔️ | ✔️ | ✔️ | ❌† |
SQLite | ✔️ | ✔️ | ❌‡ | ✔️ | ❌† |
SQL Server | ✔️ | ✔️ | ✔️ | ✔️ | ❌† |
CockroachDB | ✔️ | ✔️ | ✔️ | ✔️ | ❌† |
MongoDB | ✔️ | ✔️ | ✔️ | ✔️ | ❌† |
- †
SetDefault
參考動作在prisma
關聯模式中不受支援。 - ‡
NoAction
參考動作在 PostgreSQL 和 SQLite 的prisma
關聯模式中不受支援。請改用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.
內省
當您在啟用 prisma
關聯模式的情況下,使用 db pull
命令內省資料庫時,關聯將不會自動新增至您的結構描述。您將需要使用 @relation
屬性手動新增任何關聯。這只需要執行一次 – 下次您內省資料庫時,Prisma ORM 將保留您新增的 @relation
屬性。
Prisma Migrate 和 db push
當您在啟用 prisma
關聯模式的情況下,使用 Prisma Migrate 或 db push
將變更套用至您的 Prisma 結構描述時,Prisma ORM 將不會在您的資料庫中使用外鍵。
索引
在使用外鍵約束的關聯式資料庫中,資料庫通常也會為外鍵欄隱含地建立索引。例如,MySQL 將在外鍵欄上建立索引。這是為了讓外鍵檢查能夠快速執行,而不需要表格掃描。
prisma
關聯模式不使用外鍵,因此當您使用 Prisma Migrate 或 db push
將變更套用至資料庫時,不會建立索引。您需要改為使用 @@index
屬性 (或 @unique
、@@unique
或 @@id
屬性,如果適用) 在您的關聯純量欄位上手動新增索引。
索引驗證
如果您未手動新增索引,查詢可能需要完整表格掃描。這可能會很慢,並且對於按存取列計費的資料庫供應商來說也很昂貴。為了協助避免這種情況,當您的結構描述包含在未定義索引的 @relation
中使用的欄位時,Prisma ORM 會向您發出警告。例如,以下結構描述具有 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
關聯模式,請新增 relationMode
欄位並將值設為 prisma
,或者如果 relationMode
欄位已存在,則將其值更新為 prisma
。
當您將關聯模式從 foreignKeys
切換到 prisma
時,在您第一次使用 Prisma Migrate 或 db push
將變更套用至結構描述之後,Prisma ORM 將在下一個移轉中移除所有先前建立的外鍵。
如果您保留相同的資料庫,則可以繼續像平常一樣工作。如果您切換到完全不支援外鍵的資料庫,您現有的移轉歷史記錄包含建立外鍵的 SQL DDL,如果您必須重新執行這些移轉,可能會觸發錯誤。在這種情況下,我們建議您刪除 migrations
目錄。(如果您使用 PlanetScale,它不支援外鍵,我們通常建議您使用 db push
而不是 Prisma Migrate。)
從 prisma
切換到 foreignKeys
若要從 prisma
關聯模式切換到 foreignKeys
關聯模式,請將 relationMode
欄位值從 prisma
更新為 foreignKeys
。為此,資料庫必須支援外鍵。當您在切換關聯模式後第一次使用 Prisma Migrate 或 db push
將變更套用至結構描述時,Prisma ORM 將在下一個移轉中為所有關聯建立外鍵。