自关联
关联字段也可以引用其自身模型,在这种情况下,此关联被称为自关联。自关联可以是任意基数,例如一对一、一对多和多对多。
请注意,自关联始终需要 @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"
,另有两位用户 "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
}