一對一關係
本頁介紹一對一關係並解釋如何在 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 關係標量是底層資料庫中外部索引鍵的直接表示。這種一對一關係表達了以下內容
- "一個使用者可以有零個或一個個人資料"(因為
User上的profile欄位是可選的) - "一個個人資料必須始終連線到一個使用者"
在前面的例子中,Profile 模型的 user 關係欄位引用了 User 模型的 id 欄位。你也可以引用一個不同的欄位。在這種情況下,你需要用 @unique 屬性標記該欄位,以保證每個 Profile 只連線到一個 User。在下面的例子中,user 欄位引用了 User 模型中的 email 欄位,該欄位被 @unique 屬性標記
- 關係型資料庫
- 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 來定義一對一關係
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 關係。
以下示例演示瞭如何使用複合鍵(firstName 和 lastName)在 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 關係
在以下示例中,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 關係中,你可以自行決定要在關係的哪一方使用 @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?
}