一對多關係
本頁介紹了一對多關係,並解釋瞭如何在 Prisma schema 中使用它們。
概述
一對多(1-n)關係指的是關係的一側的一個記錄可以連線到另一側的零個或多個記錄。在以下示例中,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
}
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
}
注意
posts欄位不會在底層資料庫 schema 中“顯現”。在關係的另一側,帶註解的關係欄位author及其關係標量authorId代表了在底層資料庫中儲存外部索引鍵的關係側。
這個一對多關係表達了以下含義
- "一個使用者可以有零個或多個帖子"
- "一個帖子必須始終有一個作者"
在前面的例子中,Post 模型的 author 關係欄位引用了 User 模型的 id 欄位。你也可以引用不同的欄位。在這種情況下,你需要用 @unique 屬性標記該欄位,以確保每個 Post 只連線到一個 User。在下面的例子中,author 欄位引用了 User 模型中的一個 email 欄位,該欄位被標記為 @unique 屬性
- 關係型資料庫
- MongoDB
model User {
id Int @id @default(autoincrement())
email String @unique // <-- add unique attribute
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
authorEmail String
author User @relation(fields: [authorEmail], references: [email])
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique // <-- add unique attribute
posts Post[]
}
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
authorEmail String
author User @relation(fields: [authorEmail], references: [email])
}
在 MySQL 中,你可以只在被引用的一側建立帶索引的外部索引鍵,而不建立唯一約束。在 Prisma ORM 4.0.0 及更高版本中,如果你內省這種型別的關係,它將觸發一個驗證錯誤。要解決此問題,你需要向被引用欄位新增 @unique 約束。
關係型資料庫中的多欄位關係
僅在關係型資料庫中,你也可以使用多欄位 ID/複合鍵來定義此關係
model User {
firstName String
lastName String
post Post[]
@@id([firstName, lastName])
}
model Post {
id Int @id @default(autoincrement())
author User @relation(fields: [authorFirstName, authorLastName], references: [firstName, lastName])
authorFirstName String // relation scalar field (used in the `@relation` attribute above)
authorLastName String // relation scalar field (used in the `@relation` attribute above)
}
資料庫中的 1-n 關係
關係型資料庫
以下示例演示瞭如何在 SQL 中建立 1-n 關係
CREATE TABLE "User" (
id SERIAL PRIMARY KEY
);
CREATE TABLE "Post" (
id SERIAL PRIMARY KEY,
"authorId" integer NOT NULL,
FOREIGN KEY ("authorId") REFERENCES "User"(id)
);
由於 authorId 列(外部索引鍵)上沒有 UNIQUE 約束,你可以建立多個指向同一個 User 記錄的 Post 記錄。這使得該關係成為一對多而非一對一。
以下示例演示瞭如何在 SQL 中使用複合鍵(firstName 和 lastName)建立 1-n 關係
CREATE TABLE "User" (
firstName TEXT,
lastName TEXT,
PRIMARY KEY ("firstName","lastName")
);
CREATE TABLE "Post" (
id SERIAL PRIMARY KEY,
"authorFirstName" TEXT NOT NULL,
"authorLastName" TEXT NOT NULL,
FOREIGN KEY ("authorFirstName", "authorLastName") REFERENCES "User"("firstName", "lastName")
);
一對一關係和一對多關係比較
在關係型資料庫中,1-1 關係和 1-n 關係的主要區別在於,在 1-1 關係中,外部索引鍵必須定義 UNIQUE 約束。
MongoDB
對於 MongoDB,Prisma ORM 目前使用規範化資料模型設計,這意味著文件透過 ID 相互引用,方式類似於關係型資料庫。
以下 MongoDB 文件表示一個 User
{ "_id": { "$oid": "60d5922d00581b8f0062e3a8" }, "name": "Ella" }
以下每個 Post MongoDB 文件都有一個 authorId 欄位,該欄位引用相同的使用者
[
{
"_id": { "$oid": "60d5922e00581b8f0062e3a9" },
"title": "How to make sushi",
"authorId": { "$oid": "60d5922d00581b8f0062e3a8" }
},
{
"_id": { "$oid": "60d5922e00581b8f0062e3aa" },
"title": "How to re-install Windows",
"authorId": { "$oid": "60d5922d00581b8f0062e3a8" }
}
]
一對一關係和一對多關係比較
在 MongoDB 中,1-1 關係和 1-n 關係之間的唯一區別是資料庫中引用另一個文件的文件數量——沒有約束。
一對多關係中的必填和可選關係欄位
一個 1-n 關係總是包含兩個關係欄位
1-n 關係的帶註解關係欄位和關係標量可以**兩者都**是可選的,或者**兩者都**是強制性的。在關係的另一側,列表**始終是強制性的**。
可選的一對多關係
在以下示例中,你可以建立一個 Post 而不分配 User
- 關係型資料庫
- 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?
}
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
}
強制性一對多關係
在以下示例中,建立 Post 時必須分配一個 User
- 關係型資料庫
- 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
}
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
}