一对一关系
本页介绍一对一关系,并解释如何在 Prisma schema 中使用它们。
概览
一对一(1-1)关系是指在关系的两端,最多可以连接 **一个** 记录的关系。在下面的示例中,User
和 Profile
之间存在一对一关系
- 关系型数据库
- MongoDB
model User {
id Int @id @default(autoincrement())
profile Profile?
}
model Profile {
id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [id])
userId Int @unique // relation scalar field (used in the `@relation` attribute above)
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
profile Profile?
}
model Profile {
id String @id @default(auto()) @map("_id") @db.ObjectId
user User @relation(fields: [userId], references: [id])
userId String @unique @db.ObjectId // relation scalar field (used in the `@relation` attribute above)
}
userId
关系标量是底层数据库中外键的直接表示。这个一对一关系表达了以下含义:
- "一个用户可以有零个或一个 profile"(因为
User
模型中的profile
字段是可选的) - "一个 profile 必须始终连接到一个用户"
在前面的示例中,Profile
模型中的 user
关系字段引用了 User
模型中的 id
字段。您也可以引用其他字段。在这种情况下,您需要使用 @unique
属性标记该字段,以确保每个 Profile
只连接到一个 User
。在下面的示例中,user
字段引用了 User
模型中被标记为 @unique
属性的 email
字段:
- 关系型数据库
- MongoDB
model User {
id Int @id @default(autoincrement())
email String @unique // <-- add unique attribute
profile Profile?
}
model Profile {
id Int @id @default(autoincrement())
user User @relation(fields: [userEmail], references: [email])
userEmail String @unique // relation scalar field (used in the `@relation` attribute above)
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique // <-- add unique attribute
profile Profile?
}
model Profile {
id String @id @default(auto()) @map("_id") @db.ObjectId
user User @relation(fields: [userEmail], references: [email])
userEmail String @unique @db.ObjectId // relation scalar field (used in the `@relation` attribute above)
}
在 MySQL 中,您可以在被引用端仅通过索引创建外键,而无需唯一约束。在 Prisma ORM 4.0.0 及更高版本中,如果您内省这种类型的关系,将触发验证错误。要解决此问题,您需要在被引用字段上添加 @unique
约束。
关系型数据库中的多字段关系
仅在关系型数据库中,您还可以使用多字段 ID 来定义 1-1 关系
model User {
firstName String
lastName String
profile Profile?
@@id([firstName, lastName])
}
model Profile {
id Int @id @default(autoincrement())
user User @relation(fields: [userFirstName, userLastName], references: [firstName, lastName])
userFirstName String // relation scalar field (used in the `@relation` attribute above)
userLastName String // relation scalar field (used in the `@relation` attribute above)
@@unique([userFirstName, userLastName])
}
数据库中的 1-1 关系
关系型数据库
以下示例演示了如何在 SQL 中创建 1-1 关系
CREATE TABLE "User" (
id SERIAL PRIMARY KEY
);
CREATE TABLE "Profile" (
id SERIAL PRIMARY KEY,
"userId" INTEGER NOT NULL UNIQUE,
FOREIGN KEY ("userId") REFERENCES "User"(id)
);
请注意,外键 userId
上有一个 UNIQUE
约束。如果缺少此 UNIQUE
约束,则该关系将被视为1-n 关系。
以下示例演示了如何在 SQL 中使用复合键(firstName
和 lastName
)创建 1-1 关系
CREATE TABLE "User" (
firstName TEXT,
lastName TEXT,
PRIMARY KEY ("firstName","lastName")
);
CREATE TABLE "Profile" (
id SERIAL PRIMARY KEY,
"userFirstName" TEXT NOT NULL,
"userLastName" TEXT NOT NULL,
UNIQUE ("userFirstName", "userLastName")
FOREIGN KEY ("userFirstName", "userLastName") REFERENCES "User"("firstName", "lastName")
);
MongoDB
对于 MongoDB,Prisma ORM 当前使用规范化的数据模型设计,这意味着文档通过 ID 相互引用,类似于关系型数据库的方式。
以下 MongoDB 文档表示一个 User
{ "_id": { "$oid": "60d58e130011041800d209e1" }, "name": "Bob" }
以下 MongoDB 文档表示一个 Profile
- 请注意 userId
字段,它引用了 User
文档的 $oid
{
"_id": { "$oid": "60d58e140011041800d209e2" },
"bio": "I'm Bob, and I like drawing.",
"userId": { "$oid": "60d58e130011041800d209e1" }
}
必需和可选的 1-1 关系字段
在一对一关系中,关系中**没有**关系标量(表示数据库中外键的字段)的那一侧**必须**是可选的
model User {
id Int @id @default(autoincrement())
profile Profile? // No relation scalar - must be optional
}
此限制是在 2.12.0 版本中引入的。
但是,您可以选择关系中**有**关系标量的那一侧是可选的还是强制的。
强制的 1-1 关系
在下面的示例中,profile
和 profileId
是强制的。这意味着您不能在不连接或创建 Profile
的情况下创建 User
model User {
id Int @id @default(autoincrement())
profile Profile @relation(fields: [profileId], references: [id]) // references `id` of `Profile`
profileId Int @unique // relation scalar field (used in the `@relation` attribute above)
}
model Profile {
id Int @id @default(autoincrement())
user User?
}
可选的 1-1 关系
在下面的示例中,profile
和 profileId
是可选的。这意味着您可以在不连接或创建 Profile
的情况下创建用户
model User {
id Int @id @default(autoincrement())
profile Profile? @relation(fields: [profileId], references: [id]) // references `id` of `Profile`
profileId Int? @unique // relation scalar field (used in the `@relation` attribute above)
}
model Profile {
id Int @id @default(autoincrement())
user User?
}
选择 1-1 关系中哪一侧存储外键
在 **1-1 关系**中,您可以自行决定关系中哪一侧要使用 @relation
属性进行注解(从而持有外键)。
在下面的示例中,Profile
模型上的关系字段使用了 @relation
属性进行注解。userId
是底层数据库中外键的直接表示
- 关系型数据库
- MongoDB
model User {
id Int @id @default(autoincrement())
profile Profile?
}
model Profile {
id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [id])
userId Int @unique // relation scalar field (used in the `@relation` attribute above)
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
profile Profile?
}
model Profile {
id String @id @default(auto()) @map("_id") @db.ObjectId
user User @relation(fields: [userId], references: [id])
userId String @unique @db.ObjectId
}
您也可以在关系的另一侧使用 @relation
属性进行注解。以下示例注解了 User
模型上的关系字段。profileId
是底层数据库中外键的直接表示
- 关系型数据库
- MongoDB
model User {
id Int @id @default(autoincrement())
profile Profile? @relation(fields: [profileId], references: [id])
profileId Int? @unique // relation scalar field (used in the `@relation` attribute above)
}
model Profile {
id Int @id @default(autoincrement())
user User?
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
profile Profile? @relation(fields: [profileId], references: [id])
profileId String? @unique @db.ObjectId // relation scalar field (used in the `@relation` attribute above)
}
model Profile {
id String @id @default(auto()) @map("_id") @db.ObjectId
user User?
}