跳到主要內容

建模和查詢多對多關係

問題

在關係型資料庫中建模和查詢多對多關係可能具有挑戰性。本文將展示兩種使用 Prisma ORM 處理此問題的方法。第一個示例使用隱式多對多關係,第二個示例使用顯式多對多關係。

解決方案

隱式關係

這是一種多對多關係型別,Prisma ORM 在內部處理關係表。隱式多對多關係的一個基本示例如下:

model Post {
id Int @id @default(autoincrement())
title String
tags Tag[]
}

model Tag {
id Int @id @default(autoincrement())
name String @unique
posts Post[]
}

要建立帖子及其標籤,可以使用 Prisma Client 編寫如下程式碼:

await prisma.post.create({
data: {
title: 'Types of relations',
tags: { create: [{ name: 'dev' }, { name: 'prisma' }] },
},
})

在上面的示例中,我們可以直接查詢帖子及其標籤,如下所示:

await prisma.post.findMany({
include: { tags: true },
})

獲得的回應將是:

[
{
"id": 1,
"title": "Types of relations",
"tags": [
{
"id": 1,
"name": "dev"
},
{
"id": 2,
"name": "prisma"
}
]
}
]

另一個用例是,如果你想新增新標籤以及將現有標籤連線到帖子。例如,使用者為其帖子建立了新標籤,並且也選擇了要新增的現有標籤。在這種情況下,我們可以透過以下方式執行此操作:

await prisma.post.update({
where: { id: 1 },
data: {
title: 'Prisma is awesome!',
tags: { set: [{ id: 1 }, { id: 2 }], create: { name: 'typescript' } },
},
})

顯式關係

顯式關係主要在需要將額外欄位儲存在關係表中,或者當你內省已經設定了多對多關係的現有資料庫時需要建立。這與上面使用的 schema 相同,但具有顯式關係表:

model Post {
id Int @id @default(autoincrement())
title String
tags PostTags[]
}

model PostTags {
id Int @id @default(autoincrement())
post Post? @relation(fields: [postId], references: [id])
tag Tag? @relation(fields: [tagId], references: [id])
postId Int?
tagId Int?

@@index([postId, tagId])
}

model Tag {
id Int @id @default(autoincrement())
name String @unique
posts PostTags[]
}

向帖子新增標籤將是建立到關係表 (PostTags) 以及標籤表 (Tag) 中:

await prisma.post.create({
data: {
title: 'Types of relations',
tags: {
create: [
{ tag: { create: { name: 'dev' } } },
{ tag: { create: { name: 'prisma' } } },
],
},
},
})

此外,查詢帖子及其標籤將需要一個額外的 include,如下所示:

await prisma.post.findMany({
include: { tags: { include: { tag: true } } },
})

這將提供以下輸出:

[
{
"id": 1,
"title": "Types of relations",
"tags": [
{
"id": 1,
"postId": 1,
"tagId": 1,
"tag": {
"id": 1,
"name": "prisma"
}
},
{
"id": 2,
"postId": 1,
"tagId": 2,
"tag": {
"id": 2,
"name": "dev"
}
}
]
}
]

有時,在 UI 中顯示關係表的資料並不理想。在這種情況下,最好在伺服器上獲取資料後進行對映,並將該響應傳送到前端。

const result = posts.map((post) => {
return { ...post, tags: post.tags.map((tag) => tag.tag) }
})

這將提供與隱式關係獲得的輸出相似的輸出。

[
{
"id": 1,
"title": "Types of relations",
"tags": [
{
"id": 1,
"name": "prisma"
},
{
"id": 2,
"name": "dev"
}
]
}
]

本文展示瞭如何實現隱式和顯式多對多關係,並使用 Prisma Client 查詢它們。

© . This site is unofficial and not affiliated with Prisma Data, Inc.