中介層
已棄用:中介層已在 4.16.0 版本中棄用。
我們建議使用 Prisma Client 擴充功能 query
元件類型 作為中介層的替代方案。Prisma Client 擴充功能首次在 4.7.0 版本中以預覽形式推出,並在 4.16.0 版本中正式發布。
Prisma Client 擴充功能讓您可以建立獨立的 Prisma Client 實例,並將每個用戶端綁定到特定的篩選器或使用者。例如,您可以將用戶端綁定到特定使用者以提供使用者隔離。Prisma Client 擴充功能也提供端對端類型安全。
中介層充當查詢層級的生命週期掛鉤,讓您可以在查詢執行之前或之後執行動作。使用 prisma.$use
方法來新增中介層,如下所示
const prisma = new PrismaClient()
// Middleware 1
prisma.$use(async (params, next) => {
// Manipulate params here
const result = await next(params)
// See results here
return result
})
// Middleware 2
prisma.$use(async (params, next) => {
// Manipulate params here
const result = await next(params)
// See results here
return result
})
// Queries here
當使用 批次交易 時,請勿在中介層中多次調用 next
。這會導致您跳出交易並導致意外結果。
params
代表中介層中可用的參數,例如查詢的名稱,而 next
代表 堆疊中的下一個中介層或原始 Prisma Client 查詢。
中介層的可能用例包括
- 設定或覆寫欄位值 - 例如,設定部落格文章評論的上下文語言
- 驗證輸入資料 - 例如,透過外部服務檢查使用者輸入中是否包含不當語言
- 攔截
delete
查詢並將其變更為update
,以執行 軟刪除 - 記錄執行查詢所花費的時間
中介層還有許多其他用例 - 此列表旨在為中介層旨在解決的問題類型提供靈感。
範例
以下範例情境展示如何在實務中使用中介層
中介層範例:軟刪除
以下範例使用中介層執行軟刪除。軟刪除表示透過變更欄位(例如將 deleted 設為 true)將記錄標記為已刪除,而不是實際從資料庫中移除。使用軟刪除的原因包括
中介層範例:記錄
以下範例記錄 Prisma Client 查詢執行所花費的時間
中介層範例:工作階段資料
以下範例將每個 Post 的 language 欄位設定為上下文語言(例如,取自工作階段狀態)
在哪裡新增中介層
在請求處理程式的上下文之外新增 Prisma Client 中介層,否則每個請求都會將中介層的新實例新增到堆疊中。以下範例示範如何在 Express 應用程式的上下文中新增 Prisma Client 中介層
import express from 'express'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
prisma.$use(async (params, next) => {
// Manipulate params here
const result = await next(params)
// See results here
return result
})
const app = express()
app.get('/feed', async (req, res) => {
// NO MIDDLEWARE HERE
const posts = await prisma.post.findMany({
where: { published: true },
include: { author: true },
})
res.json(posts)
})
執行順序與中介層堆疊
如果您有多個中介層,則每個獨立查詢的執行順序為
- 每個中介層中
await next(params)
之前的所有邏輯,依遞減順序 - 每個中介層中
await next(params)
之後的所有邏輯,依遞增順序
根據您在堆疊中的位置,await next(params)
要么
- 執行下一個中介層(在範例中的中介層 #1 和 #2 中)或
- 執行原始 Prisma Client 查詢(在中介層 #3 中)
const prisma = new PrismaClient()
// Middleware 1
prisma.$use(async (params, next) => {
console.log(params.args.data.title)
console.log('1')
const result = await next(params)
console.log('6')
return result
})
// Middleware 2
prisma.$use(async (params, next) => {
console.log('2')
const result = await next(params)
console.log('5')
return result
})
// Middleware 3
prisma.$use(async (params, next) => {
console.log('3')
const result = await next(params)
console.log('4')
return result
})
const create = await prisma.post.create({
data: {
title: 'Welcome to Prisma Day 2020',
},
})
const create2 = await prisma.post.create({
data: {
title: 'How to Prisma!',
},
})
輸出
Welcome to Prisma Day 2020
1
2
3
4
5
6
How to Prisma!
1
2
3
4
5
6
效能與適當的用例
中介層會為每個查詢執行,這表示過度使用可能會對效能產生負面影響。為了避免增加效能開銷
-
在您的中介層中儘早檢查
params.model
和params.action
屬性,以避免不必要地執行邏輯prisma.$use(async (params, next) => {
if (params.model == 'Post' && params.action == 'delete') {
// Logic only runs for delete action and Post model
}
return next(params)
}) -
考量中介層是否是您情境的適當解決方案。例如
- 如果您需要填充欄位,您可以使用
@default
屬性嗎? - 如果您需要設定
DateTime
欄位的值,您可以使用now()
函數或@updatedAt
屬性嗎? - 如果您需要執行更複雜的驗證,您可以在資料庫本身中使用
CHECK
約束嗎?
- 如果您需要填充欄位,您可以使用