跳到主要内容

自关联

关系字段也可以引用它自己的模型,在这种情况下,该关系被称为自关联。自关联可以是任何基数,1-1、1-n 和 m-n。

请注意,自关联始终需要@relation 属性。

一对一自关联

以下示例模拟一对一自关联

model User {
id Int @id @default(autoincrement())
name String?
successorId Int? @unique
successor User? @relation("BlogOwnerHistory", fields: [successorId], references: [id])
predecessor User? @relation("BlogOwnerHistory")
}

此关系表示以下内容

  • "用户可以有一个或零个前任"(例如,莎拉是玛丽作为博客所有者的前任)
  • "用户可以有一个或零个继任者"(例如,玛丽是莎拉作为博客所有者的继任者)

注意:一对一自关联不能在两侧都强制要求。一侧或两侧必须是可选的,否则将无法创建第一个User 记录。

要创建一对一自关联

  • 关系的双侧必须定义一个具有相同名称的@relation 属性 - 在这种情况下,为BlogOwnerHistory
  • 一个关系字段必须是完全注释的。在此示例中,successor 字段定义了fieldreferences 参数。
  • 一个关系字段必须由外键支持。successor 字段由successorId 外键支持,该外键引用id 字段中的值。successorId 标量关系字段还需要一个@unique 属性以确保一对一关系。

注意:一对一自关联需要两个方面,即使关系的两个方面相等。例如,要模拟“最好的朋友”关系,您需要创建两个关系字段:bestfriend1bestfriend2

关系的任何一侧都可以由外键支持。在之前的示例中,下面重复,successorsuccessorId 支持

model User {
id Int @id @default(autoincrement())
name String?
successorId Int? @unique
successor User? @relation("BlogOwnerHistory", fields: [successorId], references: [id])
predecessor User? @relation("BlogOwnerHistory")
}

或者,您可以重新编写它,以便predecessorpredecessorId 支持

model User {
id Int @id @default(autoincrement())
name String?
successor User? @relation("BlogOwnerHistory")
predecessorId Int? @unique
predecessor User? @relation("BlogOwnerHistory", fields: [predecessorId], references: [id])
}

无论哪一侧由外键支持,Prisma 客户端都会显示predecessorsuccessor 字段

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" }
}

一对多自关联

一对多自关联如下所示

model User {
id Int @id @default(autoincrement())
name String?
teacherId Int?
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" }
}

多对多自关联

多对多自关联如下所示

model User {
id Int @id @default(autoincrement())
name String?
followedBy User[] @relation("UserFollows")
following User[] @relation("UserFollows")
}

此关系表示以下内容

  • "用户可以被零个或多个用户关注"
  • "用户可以关注零个或多个用户"

请注意,对于关系数据库,此多对多关系是隐式的。这意味着 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 模型定义为如下所示

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")
}