自我關聯
關聯欄位也可以參考自身的模型,在這種情況下,該關聯稱為「自我關聯」。自我關聯可以是任何基數,1 對 1、1 對多和多對多。
請注意,自我關聯始終需要 @relation
屬性。
一對一自我關聯
以下範例示範了一對一自我關聯
- 關聯式資料庫
- MongoDB
model User {
id Int @id @default(autoincrement())
name String?
successorId Int? @unique
successor User? @relation("BlogOwnerHistory", fields: [successorId], references: [id])
predecessor User? @relation("BlogOwnerHistory")
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String?
successorId String? @unique @db.ObjectId
successor User? @relation("BlogOwnerHistory", fields: [successorId], references: [id])
predecessor User? @relation("BlogOwnerHistory")
}
此關聯表達以下內容
- 「一位使用者可以有一個或零個前任」(例如,Sarah 是 Mary 作為部落格擁有者的前任)
- 「一位使用者可以有一個或零個後任」(例如,Mary 是 Sarah 作為部落格擁有者的後任)
注意:一對一自我關聯不能在雙方都設為必要。一方或雙方都必須是選填,否則將無法建立第一個
User
記錄。
若要建立一對一自我關聯
- 關聯的雙方都必須定義一個共享相同名稱的
@relation
屬性 - 在此例中為 BlogOwnerHistory。 - 一個關聯欄位必須是完整註解的。在本範例中,
successor
欄位定義了field
和references
參數。 - 一個關聯欄位必須由外鍵支援。
successor
欄位由successorId
外鍵支援,該外鍵參考id
欄位中的值。successorId
純量關聯欄位也需要@unique
屬性以保證一對一關聯。
注意:一對一自我關聯需要雙方,即使雙方在關係中是對等的。例如,若要建立「最好的朋友」關係模型,您需要建立兩個關聯欄位:
bestfriend1
和bestfriend2
。
關聯的任一方都可以由外鍵支援。在先前的範例中(如下重複所示),successor
由 successorId
支援
- 關聯式資料庫
- MongoDB
model User {
id Int @id @default(autoincrement())
name String?
successorId Int? @unique
successor User? @relation("BlogOwnerHistory", fields: [successorId], references: [id])
predecessor User? @relation("BlogOwnerHistory")
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String?
successorId String? @unique @db.ObjectId
successor User? @relation("BlogOwnerHistory", fields: [successorId], references: [id])
predecessor User? @relation("BlogOwnerHistory")
}
或者,您可以重寫此程式碼,使 predecessor
由 predecessorId
支援
- 關聯式資料庫
- MongoDB
model User {
id Int @id @default(autoincrement())
name String?
successor User? @relation("BlogOwnerHistory")
predecessorId Int? @unique
predecessor User? @relation("BlogOwnerHistory", fields: [predecessorId], references: [id])
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String?
successor User? @relation("BlogOwnerHistory")
predecessorId String? @unique @db.ObjectId
predecessor User? @relation("BlogOwnerHistory", fields: [predecessorId], references: [id])
}
無論哪一方由外鍵支援,Prisma Client 都會顯示 predecessor
和 successor
欄位。
const x = await prisma.user.create({
data: {
name: "Bob McBob",
successor: {
connect: {
id: 2,
},
},
predecessor: {
connect: {
id: 4,
},
},
},
});
資料庫中的一對一自我關聯
關聯式資料庫
僅在關聯式資料庫中,一對一自我關聯由以下 SQL 表示
CREATE TABLE "User" (
id SERIAL PRIMARY KEY,
"name" TEXT,
"successorId" INTEGER
);
ALTER TABLE "User" ADD CONSTRAINT fk_successor_user FOREIGN KEY ("successorId") REFERENCES "User" (id);
ALTER TABLE "User" ADD CONSTRAINT successor_unique UNIQUE ("successorId");
MongoDB
對於 MongoDB,Prisma ORM 目前使用標準化的資料模型設計,這表示文件彼此透過 ID 參考,方式與關聯式資料庫類似。
以下 MongoDB 文件表示兩個使用者之間的一對一自我關聯
{ "_id": { "$oid": "60d97df70080618f000e3ca9" }, "name": "Elsa the Elder" }
{
"_id": { "$oid": "60d97df70080618f000e3caa" },
"name": "Elsa",
"successorId": { "$oid": "60d97df70080618f000e3ca9" }
}
一對多自我關聯
一對多自我關聯如下所示
- 關聯式資料庫
- MongoDB
model User {
id Int @id @default(autoincrement())
name String?
teacherId Int?
teacher User? @relation("TeacherStudents", fields: [teacherId], references: [id])
students User[] @relation("TeacherStudents")
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String?
teacherId String? @db.ObjectId
teacher User? @relation("TeacherStudents", fields: [teacherId], references: [id])
students User[] @relation("TeacherStudents")
}
此關聯表達以下內容
- 「一位使用者有零個或一個老師」
- 「一位使用者可以有零個或多個學生」
請注意,您也可以透過將 teacher
欄位設為必要,來要求每位使用者都必須有老師。
資料庫中的一對多自我關聯
關聯式資料庫
在關聯式資料庫中,一對多自我關聯由以下 SQL 表示
CREATE TABLE "User" (
id SERIAL PRIMARY KEY,
"name" TEXT,
"teacherId" INTEGER
);
ALTER TABLE "User" ADD CONSTRAINT fk_teacherid_user FOREIGN KEY ("teacherId") REFERENCES "User" (id);
請注意 teacherId
上缺少 UNIQUE
限制 - 多位學生可以有相同的老師。
MongoDB
對於 MongoDB,Prisma ORM 目前使用標準化的資料模型設計,這表示文件彼此透過 ID 參考,方式與關聯式資料庫類似。
以下 MongoDB 文件表示三個使用者之間的一對多自我關聯 - 一位老師和兩位具有相同 teacherId
的學生
{
"_id": { "$oid": "60d9b9e600fe3d470079d6f9" },
"name": "Ms. Roberts"
}
{
"_id": { "$oid": "60d9b9e600fe3d470079d6fa" },
"name": "Student 8",
"teacherId": { "$oid": "60d9b9e600fe3d470079d6f9" }
}
{
"_id": { "$oid": "60d9b9e600fe3d470079d6fb" },
"name": "Student 9",
"teacherId": { "$oid": "60d9b9e600fe3d470079d6f9" }
}
多對多自我關聯
多對多自我關聯如下所示
- 關聯式資料庫
- MongoDB
model User {
id Int @id @default(autoincrement())
name String?
followedBy User[] @relation("UserFollows")
following User[] @relation("UserFollows")
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String?
followedBy User[] @relation("UserFollows", fields: [followedByIDs], references: [id])
followedByIDs String[] @db.ObjectId
following User[] @relation("UserFollows", fields: [followingIDs], references: [id])
followingIDs String[] @db.ObjectId
}
此關聯表達以下內容
- 「一位使用者可以被零個或多個使用者追蹤」
- 「一位使用者可以追蹤零個或多個使用者」
請注意,對於關聯式資料庫,此多對多關聯是隱含的。這表示 Prisma ORM 在底層資料庫中為其維護一個關聯表。
如果您需要關聯持有其他欄位,您也可以建立明確的多對多自我關聯。先前顯示的自我關聯的明確版本如下所示。
model User {
id Int @id @default(autoincrement())
name String?
followedBy Follows[] @relation("followedBy")
following Follows[] @relation("following")
}
model Follows {
followedBy User @relation("followedBy", fields: [followedById], references: [id])
followedById Int
following User @relation("following", fields: [followingId], references: [id])
followingId Int
@@id([followingId, followedById])
}
資料庫中的多對多自我關聯
關聯式資料庫
在關聯式資料庫中,多對多自我關聯(隱含)由以下 SQL 表示
CREATE TABLE "User" (
id integer DEFAULT nextval('"User_id_seq"'::regclass) PRIMARY KEY,
name text
);
CREATE TABLE "_UserFollows" (
"A" integer NOT NULL REFERENCES "User"(id) ON DELETE CASCADE ON UPDATE CASCADE,
"B" integer NOT NULL REFERENCES "User"(id) ON DELETE CASCADE ON UPDATE CASCADE
);
MongoDB
對於 MongoDB,Prisma ORM 目前使用標準化的資料模型設計,這表示文件彼此透過 ID 參考,方式與關聯式資料庫類似。
以下 MongoDB 文件表示五個使用者之間的多對多自我關聯 - 兩位使用者追蹤 "Bob"
,以及兩位追蹤他的人
{
"_id": { "$oid": "60d9866f00a3e930009a6cdd" },
"name": "Bob",
"followedByIDs": [
{ "$oid": "60d9866f00a3e930009a6cde" },
{ "$oid": "60d9867000a3e930009a6cdf" }
],
"followingIDs": [
{ "$oid": "60d9867000a3e930009a6ce0" },
{ "$oid": "60d9867000a3e930009a6ce1" }
]
}
{
"_id": { "$oid": "60d9866f00a3e930009a6cde" },
"name": "Follower1",
"followingIDs": [{ "$oid": "60d9866f00a3e930009a6cdd" }]
}
{
"_id": { "$oid": "60d9867000a3e930009a6cdf" },
"name": "Follower2",
"followingIDs": [{ "$oid": "60d9866f00a3e930009a6cdd" }]
}
{
"_id": { "$oid": "60d9867000a3e930009a6ce0" },
"name": "CoolPerson1",
"followedByIDs": [{ "$oid": "60d9866f00a3e930009a6cdd" }]
}
{
"_id": { "$oid": "60d9867000a3e930009a6ce1" },
"name": "CoolPerson2",
"followedByIDs": [{ "$oid": "60d9866f00a3e930009a6cdd" }]
}
在同一個模型上定義多個自我關聯
您也可以在同一個模型上一次定義多個自我關聯。以先前章節中的所有關聯為例,您可以如下定義 User
模型。
- 關聯式資料庫
- MongoDB
model User {
id Int @id @default(autoincrement())
name String?
teacherId Int?
teacher User? @relation("TeacherStudents", fields: [teacherId], references: [id])
students User[] @relation("TeacherStudents")
followedBy User[] @relation("UserFollows")
following User[] @relation("UserFollows")
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String?
teacherId String? @db.ObjectId
teacher User? @relation("TeacherStudents", fields: [teacherId], references: [id])
students User[] @relation("TeacherStudents")
followedBy User[] @relation("UserFollows", fields: [followedByIDs])
followedByIDs String[] @db.ObjectId
following User[] @relation("UserFollows", fields: [followingIDs])
followingIDs String[] @db.ObjectId
}