一对多关系
本页介绍一对多关系,并解释如何在 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
字段不会在底层数据库模式中“显现”。在关系的另一侧,带有标注的关系字段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 及更高版本中,如果您内省(introspect)这种类型的关系,将会触发验证错误。要解决此问题,您需要在引用的字段上添加 @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-n 关系的主要区别在于,在一对一关系中,外键上必须定义 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 关系总是包含两个关系字段
- 一个列表关系字段,其未使用
@relation
进行标注 - 带有标注的关系字段(包括其关系标量)
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
}