自我关系
关系字段还可以引用其自己的模型,在这种情况下,该关系称为自关系。自关系可以是任何基数:1-1、1-n 和 m-n。
¥A relation field can also reference its own model, in this case the relation is called a self-relation. Self-relations can be of any cardinality, 1-1, 1-n and m-n.
请注意,自关系始终需要 @relation
属性。
¥Note that self-relations always require the @relation
attribute.
一对一的自我关系
¥One-to-one self-relations
以下示例模拟了一对一的自关系:
¥The following example models a one-to-one self-relation:
- Relational databases
- 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")
}
该关系表达如下:
¥This relation expresses the following:
-
"一个用户可以有一个或零个前任"(例如,莎拉是玛丽的前任博客所有者)
¥"a user can have one or zero predecessors" (for example, Sarah is Mary's predecessor as blog owner)
-
"一个用户可以有一个或零个继任者"(例如,玛丽是莎拉的博客所有者的继任者)
¥"a user can have one or zero successors" (for example, Mary is Sarah's successor as blog owner)
注意:双方不能建立一对一的自我关系。其中一侧或两侧必须是可选的,否则无法创建第一个
User
记录。¥Note: One-to-one self-relations cannot be made required on both sides. One or both sides must be optional, otherwise it becomes impossible to create the first
User
record.
创建一对一的自我关系:
¥To create a one-to-one self-relation:
-
关系双方必须定义共享相同名称的
@relation
属性 - 在本例中为 BlogOwnerHistory。¥Both sides of the relation must define a
@relation
attribute that share the same name - in this case, BlogOwnerHistory. -
一个关系字段必须是 完全注释。在此示例中,
successor
字段定义了field
和references
参数。¥One relation field must be a fully annotated. In this example, the
successor
field defines both thefield
andreferences
arguments. -
一个关系字段必须由外键支持。
successor
字段由successorId
外键支持,该外键引用id
字段中的值。successorId
标量关系字段还需要@unique
属性来保证一对一关系。¥One relation field must be backed by a foreign key. The
successor
field is backed by thesuccessorId
foreign key, which references a value in theid
field. ThesuccessorId
scalar relation field also requires a@unique
attribute to guarantee a one-to-one relation.
注意:一对一的自关系需要双方,即使双方在关系中是平等的。例如,要对 '最好的朋友' 关系建模,你需要创建两个关系字段:
bestfriend1
和bestfriend2
。¥Note: One-to-one self relations require two sides even if both sides are equal in the relationship. For example, to model a 'best friends' relation, you would need to create two relation fields:
bestfriend1
and abestfriend2
.
关系的任何一方都可以由外键支持。在前面的示例(如下重复)中,successor
由 successorId
支持:
¥Either side of the relation can be backed by a foreign key. In the previous example, repeated below, successor
is backed by successorId
:
- Relational databases
- 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
支持:
¥Alternatively, you could rewrite this so that predecessor
is backed by predecessorId
:
- Relational databases
- 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 客户端都会显示 predecessor
和 successor
字段:
¥No matter which side is backed by a foreign key, Prisma Client surfaces both the predecessor
and successor
fields:
const x = await prisma.user.create({
data: {
name: "Bob McBob",
successor: {
connect: {
id: 2,
},
},
predecessor: {
connect: {
id: 4,
},
},
},
});
数据库中的一对一自关系
¥One-to-one self relations in the database
关系数据库
¥Relational databases
仅在关系数据库中,一对一的自关系由以下 SQL 表示:
¥In relational databases only, a one-to-one self-relation is represented by the following 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 相互引用。
¥For MongoDB, Prisma ORM currently uses a normalized data model design, which means that documents reference each other by ID in a similar way to relational databases.
以下 MongoDB 文档表示两个用户之间的一对一自关系:
¥The following MongoDB documents represent a one-to-one self-relation between two users:
{ "_id": { "$oid": "60d97df70080618f000e3ca9" }, "name": "Elsa the Elder" }
{
"_id": { "$oid": "60d97df70080618f000e3caa" },
"name": "Elsa",
"successorId": { "$oid": "60d97df70080618f000e3ca9" }
}
一对多的自关系
¥One-to-many self relations
一对多的自关系如下所示:
¥A one-to-many self-relation looks as follows:
- Relational databases
- 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")
}
该关系表达如下:
¥This relation expresses the following:
-
"一个用户有零个或一个教师"
¥"a user has zero or one teachers "
-
"一个用户可以有零个或多个学生"
¥"a user can have zero or more students"
请注意,你还可以通过将 teacher
字段设置为 required 来要求每个用户都有一名教师。
¥Note that you can also require each user to have a teacher by making the teacher
field required.
数据库中一对多的自关系
¥One-to-many self-relations in the database
关系数据库
¥Relational databases
在关系数据库中,一对多的自关系由以下 SQL 表示:
¥In relational databases, a one-to-many self-relation is represented by the following 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
约束 - 多个学生可以有同一个老师。
¥Notice the lack of UNIQUE
constraint on teacherId
- multiple students can have the same teacher.
MongoDB
对于 MongoDB,Prisma ORM 目前使用 规范化数据模型设计,这意味着文档以与关系数据库类似的方式通过 ID 相互引用。
¥For MongoDB, Prisma ORM currently uses a normalized data model design, which means that documents reference each other by ID in a similar way to relational databases.
以下 MongoDB 文档代表三个用户之间的一对多自关系 - 一名教师和两名学生具有相同的 teacherId
:
¥The following MongoDB documents represent a one-to-many self-relation between three users - one teacher and two students with the same 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" }
}
多对多自关系
¥Many-to-many self relations
多对多的自关系如下所示:
¥A many-to-many self-relation looks as follows:
- Relational databases
- 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
}
该关系表达如下:
¥This relation expresses the following:
-
"一个用户可以被零个或多个用户关注"
¥"a user can be followed by zero or more users"
-
"用户可以关注零个或多个用户"
¥"a user can follow zero or more users"
请注意,对于关系数据库,此多对多关系是 implicit。这意味着 Prisma ORM 在底层数据库中为其维护一个 关系表。
¥Note that for relational databases, this many-to-many-relation is implicit. This means Prisma ORM maintains a relation table for it in the underlying database.
如果你需要该关系来保存其他字段,你也可以创建 explicit 多对多自关系。前面显示的自关系的显式版本如下:
¥If you need the relation to hold other fields, you can create an explicit many-to-many self relation as well. The explicit version of the self relation shown previously is as follows:
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])
}
数据库中多对多的自关系
¥Many-to-many self-relations in the database
关系数据库
¥Relational databases
在关系数据库中,多对多的自关系(隐式)由以下 SQL 表示:
¥In relational databases, a many-to-many self-relation (implicit) is represented by the following 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 相互引用。
¥For MongoDB, Prisma ORM currently uses a normalized data model design, which means that documents reference each other by ID in a similar way to relational databases.
以下 MongoDB 文档代表五个用户之间的多对多自关系 - 关注 "Bob"
的两个用户,以及关注他的两个用户:
¥The following MongoDB documents represent a many-to-many self-relation between five users - two users that follow "Bob"
, and two users that follow him:
{
"_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" }]
}
在同一模型上定义多个自关系
¥Defining multiple self-relations on the same model
你还可以同时在同一模型上定义多个自关系。以前面部分中的所有关系为例,你可以定义一个 User
模型,如下所示:
¥You can also define multiple self-relations on the same model at once. Taking all relations from the previous sections as example, you could define a User
model as follows:
- Relational databases
- 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
}