參考動作升級路徑
Prisma ORM 2.x 版本在某些 Prisma Client 函式中會阻止刪除關聯的記錄,且不允許您在 Prisma Schema 中設定參考動作來變更此行為。
Prisma ORM 3.x 及更高版本讓您可以透過在模型的關聯上明確設定參考動作,來控制刪除或更新記錄時應發生的情況。升級後,Prisma Client 將不再強制執行任何參考動作,而寫入資料庫外鍵的任何動作將定義刪除或更新記錄時的行為。
Prisma Migrate 3.x 在將外鍵約束寫入資料庫時,將使用先前由 Prisma Client 執行的動作作為新的預設值。
Prisma ORM 2.x 行為
當在必要關聯上使用 Prisma Client 調用 delete()
或 deleteAll()
方法時,會執行運行時檢查,如果記錄正在參考相關物件,則會阻止刪除記錄。無論外鍵如何定義,這都會阻止級聯行為。
在未升級的情況下,Prisma ORM 2 中的行為完全不允許設定參考動作。 請參閱 Prisma ORM 2.x 預設參考動作
如果您實際上需要使用資料庫中配置的級聯行為,您可以使用 raw
SQL 查詢來 刪除多個參考記錄。這是因為 Prisma Client 將不會對原始查詢執行運行時檢查。
Prisma ORM 2.x 預設參考動作
以下是使用 Prisma Migrate 2.x 版本時,寫入資料庫外鍵的預設參考動作
子句 | 可選關聯 | 強制關聯 |
---|---|---|
onDelete | SetNull | Cascade |
onUpdate | Cascade | Cascade |
除了資料庫參考動作之外,Prisma Client 2.x 版本還強制執行以下動作
子句 | 可選關聯 | 強制關聯 |
---|---|---|
onDelete | SetNull | Restrict |
onUpdate | Cascade | Cascade |
升級路徑
升級時您可以採取幾種路徑,這些路徑會根據所需的結果產生不同的結果。
如果您目前使用遷移工作流程,您可以運行 prisma db pull
來檢查預設值如何在您的 schema 中反映。然後,您可以根據需要手動更新您的資料庫。
您也可以決定跳過檢查預設值,並運行遷移以使用新的預設值更新您的資料庫。
使用內省
如果您 內省您的資料庫,則在資料庫層級配置的參考動作將反映在您的 Prisma Schema 中。如果您一直使用 Prisma Migrate 或 prisma db push
來管理資料庫 schema,則這些很可能是 <=2.25.0 的預設值。
當您運行內省時,Prisma ORM 會將資料庫中的所有外鍵與 schema 進行比較,如果 SQL 陳述式 ON DELETE
和 ON UPDATE
不符合預設值,它們將在 schema 檔案中明確設定。
內省後,您可以檢閱 schema 中非預設的子句。最重要的檢閱子句是 onDelete
,在 2.25.0 及更早版本中,預設為 Cascade
。
如果您正在使用 delete()
或 deleteAll()
方法,現在將執行級聯刪除,因為 Prisma Client 中先前阻止運行時級聯刪除的安全網已被移除。請務必檢查您的程式碼並進行相應的調整。
請確保您對 schema 中每個 onDelete: Cascade
的情況感到滿意。如果不是,請執行以下操作之一
- 修改您的 Prisma schema 並
db push
或dev migrate
以變更資料庫 或 - 如果您在工作流程中僅使用
prisma db pull
,則手動更新底層資料庫
以下範例將導致級聯刪除,這表示如果 User
被刪除,則他們的所有 Post
也將被刪除。
部落格 schema 範例
model Post {
id Int @id @default(autoincrement())
title String
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
authorId Int
}
model User {
id Int @id @default(autoincrement())
posts Post[]
}
使用遷移
當運行 遷移(或 prisma db push
命令)時,新的預設值將應用於您的資料庫。
與您第一次運行 prisma db pull
時不同,新的參考動作子句和屬性將不會由 Prisma VSCode 擴充功能自動新增到您的 Prisma schema 中。如果您希望使用新的預設值以外的任何值,則必須手動新增它們。
在您的 Prisma schema 中明確定義參考動作是可選的。如果您沒有為關聯明確定義參考動作,Prisma ORM 將使用新的預設值。
請注意,可以根據具體情況新增參考動作。這表示您可以將它們新增到單一關聯,並將其餘關聯設定為預設值,而無需手動指定任何內容。
檢查錯誤
在升級到 3.0.1 版本(或 2.26.0 及更高版本且啟用 referentialActions
功能標誌的版本)之前,Prisma ORM 會在使用 delete()
或 deleteMany()
時阻止刪除記錄,以保留參考完整性。Prisma Client 會拋出帶有錯誤代碼 P2014
的自訂運行時錯誤。
升級之後,Prisma ORM 不再執行運行時檢查。您可以改為指定自訂參考動作,以保留關聯之間的參考完整性。
當您使用 NoAction
或 Restrict
來阻止刪除記錄時,在 3.0.1 及更高版本(或 2.26.0 且啟用 referentialActions
功能標誌的版本)中,錯誤訊息將與之前的版本不同。這是因為它們現在由資料庫觸發,而不是 Prisma Client。預期的新錯誤代碼是 P2003
,因此您應該檢查您的程式碼以進行相應的調整。
捕捉錯誤範例
以下範例使用下面的部落格 schema,其中 Post
和 User
之間存在一對多關聯,並在 author
欄位上設定了 Restrict
參考動作。
這表示如果使用者有貼文,則該使用者(及其貼文)無法被刪除。
model Post {
id Int @id @default(autoincrement())
title String
author User @relation(fields: [authorId], references: [id], onDelete: Restrict)
authorId String
}
model User {
id Int @id @default(autoincrement())
posts Post[]
}
在升級之前,當您嘗試刪除有貼文的使用者時,您會收到的錯誤代碼是 P2014
,其訊息為
"您嘗試進行的變更將違反 '{model_a_name}' 和 '{model_b_name}' 模型之間必要的關聯 '{relation_name}'。"
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
try {
await prisma.user.delete({
where: {
id: 'some-long-id',
},
})
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
if (error.code === 'P2014') {
console.log(error.message)
}
}
}
}
main()
.then(async () => {
await prisma.$disconnect()
})
.catch(async (e) => {
console.error(e)
await prisma.$disconnect()
process.exit(1)
})
為了確保您在程式碼中檢查正確的錯誤,請修改您的檢查以尋找 P2003
,這將傳遞訊息
"外鍵約束在欄位:{field_name} 上失敗"
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
try {
await prisma.user.delete({
where: {
id: 'some-long-id'
}
})
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
if (error.code === 'P2014') {
if (error.code === 'P2003') {
console.log(error.message)
}
}
}
}
main()
.then(async () => {
await prisma.$disconnect()
})
.catch(async (e) => {
console.error(e)
await prisma.$disconnect()
process.exit(1)
})