跳至主要内容

一对一关系

本页介绍了一对一关系,并解释了如何在您的 Prisma 架构中使用它们。

概述

一对一 (1-1) 关系是指关系的两边最多只能连接 **一条** 记录的关系。在下面的示例中,UserProfile 之间存在一对一关系。

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

userId 关系标量是底层数据库中外键的直接表示。这种一对一关系表达了以下内容

  • "一个用户可以没有配置文件或只有一个配置文件"(因为 profile 字段是 User 上的 可选 的)。
  • "一个配置文件必须始终连接到一个用户"

在前面的示例中,Profile 模型的 user 关系字段引用了 User 模型的 id 字段。您也可以引用其他字段。在这种情况下,您需要用 @unique 属性标记该字段,以保证只有一个 User 连接到每个 Profile。在下面的示例中,user 字段引用了 User 模型中用 @unique 属性标记的 email 字段。

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)
}
警告

在 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 关系

以下示例演示了如何使用复合键 (firstNamelastName) 在 SQL 中创建 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 关系

在下面的示例中,profileprofileId 是必需的。这意味着您不能在不连接或创建 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 关系

在下面的示例中,profileprofileId 是可选的。这意味着您可以在不连接或创建 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 是底层数据库中外键的直接表示。

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

您也可以用 @relation 属性注释关系的另一边。下面的示例注释了 User 模型上的关系字段。profileId 是底层数据库中外键的直接表示。

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