關係
關係是 Prisma schema 中兩個模型之間的*連線*。例如,User 和 Post 之間存在一對多關係,因為一個使用者可以擁有多篇部落格文章。
以下 Prisma schema 定義了 User 和 Post 模型之間的一對多關係。定義關係所涉及的欄位已突出顯示
- 關係型資料庫
- MongoDB
model User {
id Int @id @default(autoincrement())
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
author User @relation(fields: [authorId], references: [id])
authorId Int // relation scalar field (used in the `@relation` attribute above)
title String
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
posts Post[]
}
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
author User @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId // relation scalar field (used in the `@relation` attribute above)
title String
}
在 Prisma ORM 層面,User / Post 關係由以下部分組成:
- 兩個關係欄位:
author和posts。關係欄位在 Prisma ORM 層面定義模型之間的連線,並且**不存在於資料庫中**。這些欄位用於生成 Prisma Client。 - 標量
authorId欄位,它由@relation屬性引用。此欄位**存在於資料庫中**——它是連線Post和User的外部索引鍵。
在 Prisma ORM 層面,兩個模型之間的連線**總是**透過關係**兩端**的關係欄位來表示。
資料庫中的關係
關係型資料庫
以下實體關係圖定義了**關係型資料庫**中 User 和 Post 表之間相同的一對多關係

在 SQL 中,您使用*外部索引鍵*在兩個表之間建立關係。外部索引鍵儲存在關係**一側**。我們的示例由以下部分組成:
Post表中名為authorId的外部索引鍵列。User表中名為id的主鍵列。Post表中的authorId列引用User表中的id列。
在 Prisma schema 中,外部索引鍵/主鍵關係由 author 欄位上的 @relation 屬性表示
author User @relation(fields: [authorId], references: [id])
注意:Prisma schema 中的關係表示資料庫中表之間存在的關聯。如果關係不存在於資料庫中,則它也不存在於 Prisma schema 中。
MongoDB
對於 MongoDB,Prisma ORM 當前使用規範化資料模型設計,這意味著文件之間透過 ID 互相引用,方式與關係型資料庫類似。
以下文件表示一個 User(在 User 集合中)
{ "_id": { "$oid": "60d5922d00581b8f0062e3a8" }, "name": "Ella" }
以下 Post 文件列表(在 Post 集合中)中的每個文件都有一個 authorId 欄位,該欄位引用同一個使用者
[
{
"_id": { "$oid": "60d5922e00581b8f0062e3a9" },
"title": "How to make sushi",
"authorId": { "$oid": "60d5922d00581b8f0062e3a8" }
},
{
"_id": { "$oid": "60d5922e00581b8f0062e3aa" },
"title": "How to re-install Windows",
"authorId": { "$oid": "60d5922d00581b8f0062e3a8" }
}
]
此資料結構表示一對多關係,因為多個 Post 文件引用同一個 User 文件。
ID 和關係標量欄位上的 @db.ObjectId
如果模型的 ID 是 ObjectId(由 String 欄位表示),則必須將 @db.ObjectId 新增到模型的 ID 以及關係另一側的關係標量欄位。
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
posts Post[]
}
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
author User @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId // relation scalar field (used in the `@relation` attribute above)
title String
}
Prisma Client 中的關係
Prisma Client 是從 Prisma schema 生成的。以下示例演示了當您使用 Prisma Client 獲取、建立和更新記錄時,關係如何體現。
建立記錄和巢狀記錄
以下查詢建立了一個 User 記錄和兩個連線的 Post 記錄
const userAndPosts = await prisma.user.create({
data: {
posts: {
create: [
{ title: 'Prisma Day 2020' }, // Populates authorId with user's id
{ title: 'How to write a Prisma schema' }, // Populates authorId with user's id
],
},
},
})
在底層資料庫中,此查詢
- 建立一個具有自動生成
id(例如,20)的User - 建立兩個新的
Post記錄,並將兩個記錄的authorId設定為20
檢索記錄幷包含相關記錄
以下查詢透過 id 檢索 User,幷包含任何相關的 Post 記錄
const getAuthor = await prisma.user.findUnique({
where: {
id: "20",
},
include: {
posts: true, // All posts where authorId == 20
},
});
在底層資料庫中,此查詢
- 檢索
id為20的User記錄 - 檢索所有
authorId為20的Post記錄
將現有記錄與另一個現有記錄關聯
以下查詢將現有 Post 記錄與現有 User 記錄關聯
const updateAuthor = await prisma.user.update({
where: {
id: 20,
},
data: {
posts: {
connect: {
id: 4,
},
},
},
})
在底層資料庫中,此查詢使用巢狀的 connect 查詢將 id 為 4 的帖子連結到 id 為 20 的使用者。該查詢透過以下步驟完成此操作:
- 查詢首先查詢
id為20的使用者。 - 然後,查詢將
authorID外部索引鍵設定為20。這將id為4的帖子連結到id為20的使用者。
在此查詢中,authorID 的當前值無關緊要。無論其當前值如何,查詢都會將 authorID 更改為 20。
關係型別
Prisma ORM 中有三種不同型別(或基數)的關係:
以下 Prisma schema 包含每種型別的關係
- 一對一:
User↔Profile - 一對多:
User↔Post - 多對多:
Post↔Category
- 關係型資料庫
- MongoDB
model User {
id Int @id @default(autoincrement())
posts Post[]
profile Profile?
}
model Profile {
id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [id])
userId Int @unique // relation scalar field (used in the `@relation` attribute above)
}
model Post {
id Int @id @default(autoincrement())
author User @relation(fields: [authorId], references: [id])
authorId Int // relation scalar field (used in the `@relation` attribute above)
categories Category[]
}
model Category {
id Int @id @default(autoincrement())
posts Post[]
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
posts Post[]
profile Profile?
}
model Profile {
id String @id @default(auto()) @map("_id") @db.ObjectId
user User @relation(fields: [userId], references: [id])
userId String @unique @db.ObjectId // relation scalar field (used in the `@relation` attribute above)
}
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
author User @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId // relation scalar field (used in the `@relation` attribute above)
categories Category[] @relation(fields: [categoryIds], references: [id])
categoryIds String[] @db.ObjectId
}
model Category {
id String @id @default(auto()) @map("_id") @db.ObjectId
posts Post[] @relation(fields: [postIds], references: [id])
postIds String[] @db.ObjectId
}
請注意,關係型資料庫和 MongoDB 之間的語法略有不同——特別是對於多對多關係。
對於關係型資料庫,以下實體關係圖表示與示例 Prisma schema 對應的資料庫

對於 MongoDB,Prisma ORM 使用規範化資料模型設計,這意味著文件之間透過 ID 互相引用,方式與關係型資料庫類似。有關更多詳細資訊,請參閱MongoDB 部分。
隱式和顯式多對多關係
關係型資料庫中的多對多關係可以透過兩種方式建模
隱式多對多關係要求兩個模型都具有單個 @id。請注意以下事項:
- 您不能使用多欄位 ID
- 您不能使用
@unique代替@id
要使用這些功能中的任何一個,您必須設定顯式多對多關係。
隱式多對多關係仍然在底層資料庫中體現為關係表。但是,Prisma ORM 管理此關係表。
如果您使用隱式多對多關係而不是顯式關係,它會使Prisma Client API 更簡單(例如,您在巢狀寫入中的巢狀級別會減少一級)。
如果您不使用 Prisma Migrate,而是從內省獲取資料模型,您仍然可以遵循 Prisma ORM 的關係表約定來使用隱式多對多關係。
關係欄位
關係欄位是 Prisma 模型上的欄位,其型別*不是* 標量型別。相反,它們的型別是另一個模型。
每個關係必須正好有兩個關係欄位,每個模型上一個。在一對一和一對多關係的情況下,需要一個額外的*關係標量欄位*,它透過 @relation 屬性中的兩個關係欄位之一進行連結。此關係標量欄位是底層資料庫中*外部索引鍵*的直接表示。
- 關係型資料庫
- MongoDB
model User {
id Int @id @default(autoincrement())
email String @unique
role Role @default(USER)
posts Post[] // relation field (defined only at the Prisma ORM level)
}
model Post {
id Int @id @default(autoincrement())
title String
author User @relation(fields: [authorId], references: [id]) // relation field (uses the relation scalar field `authorId` below)
authorId Int // relation scalar field (used in the `@relation` attribute above)
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique
role Role @default(USER)
posts Post[] // relation field (defined only at the Prisma ORM level)
}
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
author User @relation(fields: [authorId], references: [id]) // relation field (uses the relation scalar field `authorId` below)
authorId String @db.ObjectId // relation scalar field (used in the `@relation` attribute above)
}
posts 和 author 都是關係欄位,因為它們的型別不是標量型別,而是其他模型。
另請注意,帶註解的關係欄位 author 需要在 @relation 屬性中連結 Post 模型上的關係標量欄位 authorId。關係標量欄位表示底層資料庫中的外部索引鍵。
兩個關係欄位(即 posts 和 author)都純粹在 Prisma ORM 層面定義,它們不會在資料庫中體現。
帶註解的關係欄位
需要關係的一側用 @relation 屬性*註解*的關係被稱為*帶註解的關係欄位*。這包括:
- 一對一關係
- 一對多關係
- 僅適用於 MongoDB 的多對多關係
用 @relation 屬性註解的關係側表示**在底層資料庫中儲存外部索引鍵**的一側。代表外部索引鍵的“實際”欄位在該關係側也需要,它被稱為*關係標量欄位*,並在 @relation 屬性內部被引用。
- 關係型資料庫
- MongoDB
author User @relation(fields: [authorId], references: [id])
authorId Int
author User @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId
當標量欄位在 @relation 屬性的 fields 中使用時,它*成為*關係標量欄位。
關係標量欄位
關係標量欄位命名約定
因為關係標量欄位始終*屬於*一個關係欄位,所以以下命名約定很常見:
- 關係欄位:
author - 關係標量欄位:
authorId(關係欄位名 +Id)
@relation 屬性
@relation 屬性只能應用於關係欄位,不能應用於標量欄位。
在以下情況下需要 @relation 屬性:
- 您定義一對一或一對多關係時,它在關係的*一側*是必需的(帶有相應的關係標量欄位)
- 您需要消除關係歧義時(例如,當兩個模型之間存在兩個關係時)
- 您定義自關係時
- 您定義適用於 MongoDB 的多對多關係時
- 您需要控制關係表在底層資料庫中的表示方式時(例如,為關係表使用特定名稱)
注意:關係型資料庫中的隱式多對多關係不需要
@relation屬性。
消除關係歧義
當您在相同的兩個模型之間定義兩個關係時,您需要在 @relation 屬性中新增 name 引數來消除它們的歧義。例如,考慮以下模型,以說明為什麼需要這樣做:
- 關係型資料庫
- MongoDB
// NOTE: This schema is intentionally incorrect. See below for a working solution.
model User {
id Int @id @default(autoincrement())
name String?
writtenPosts Post[]
pinnedPost Post?
}
model Post {
id Int @id @default(autoincrement())
title String?
author User @relation(fields: [authorId], references: [id])
authorId Int
pinnedBy User? @relation(fields: [pinnedById], references: [id])
pinnedById Int?
}
// NOTE: This schema is intentionally incorrect. See below for a working solution.
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String?
writtenPosts Post[]
pinnedPost Post?
}
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String?
author User @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId
pinnedBy User? @relation(fields: [pinnedById], references: [id])
pinnedById String? @db.ObjectId
}
在這種情況下,關係是模糊的,有四種不同的解釋方式:
User.writtenPosts↔Post.author+Post.authorIdUser.writtenPosts↔Post.pinnedBy+Post.pinnedByIdUser.pinnedPost↔Post.author+Post.authorIdUser.pinnedPost↔Post.pinnedBy+Post.pinnedById
為了消除這些關係的歧義,您需要使用 @relation 屬性註解關係欄位並提供 name 引數。您可以設定任何 name(空字串 "" 除外),但它在關係的兩側必須相同。
- 關係型資料庫
- MongoDB
model User {
id Int @id @default(autoincrement())
name String?
writtenPosts Post[] @relation("WrittenPosts")
pinnedPost Post? @relation("PinnedPost")
}
model Post {
id Int @id @default(autoincrement())
title String?
author User @relation("WrittenPosts", fields: [authorId], references: [id])
authorId Int
pinnedBy User? @relation("PinnedPost", fields: [pinnedById], references: [id])
pinnedById Int? @unique
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String?
writtenPosts Post[] @relation("WrittenPosts")
pinnedPost Post? @relation("PinnedPost")
}
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String?
author User @relation("WrittenPosts", fields: [authorId], references: [id])
authorId String @db.ObjectId
pinnedBy User? @relation("PinnedPost", fields: [pinnedById], references: [id])
pinnedById String? @unique @db.ObjectId
}