SQLの一対一外部キーをPrismaリレーションに変換する
UNIQUE外部キー制約がPrismaの一対一リレーションフィールドにどのように変換されるかを学びます。@relationを使用したオプショナルおよび必須の一対一リレーションを解説します。
Relations
詳細な説明
一対一リレーション
SQLにおける一対一リレーションシップは、UNIQUE制約付きの外部キーであり、各親が最大1つの関連する子を持つことを保証します。Prismaは両側の単数リレーションフィールドでこれをモデル化します。
SQLの例
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
CREATE TABLE profiles (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL UNIQUE,
bio TEXT,
avatar_url VARCHAR(2048),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
生成されるPrismaスキーマ
model User {
id Int @id @default(autoincrement())
name String
profile Profile?
@@map("users")
}
model Profile {
id Int @id @default(autoincrement())
userId Int @unique @map("user_id")
bio String? @db.Text
avatarUrl String? @db.VarChar(2048) @map("avatar_url")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("profiles")
}
仕組み
- 外部キーカラム
user_idにUNIQUE制約がある — これが1:1リレーションシップを示します。 - Prismaでは、子model(
Profile)がfieldsとreferencesを持つ@relationを保持します。 - 親model(
User)はオプショナルな逆参照Profile?を持ちます(プロファイルがまだ存在しない可能性があるためオプショナル)。 - Prismaの
userIdに対する@unique属性が一対一制約を強制します。
必須 vs オプショナル
// オプショナル:ユーザーはプロファイルを持っていない場合がある
model User {
profile Profile?
}
// 必須:すべてのユーザーがプロファイルを持つ必要がある
model User {
profile Profile
}
親側でリレーションがオプショナルかどうかはビジネスロジックに依存します。SQLスキーマだけではこれを表現できません — 子側のNOT NULL FKは「すべてのプロファイルにユーザーが必要」を意味しますが、「すべてのユーザーにプロファイルが必要」を意味するわけではありません。
埋め込みとの比較
別の1:1テーブルの代替として、すべてのフィールドを親テーブルに配置する方法があります:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
bio TEXT,
avatar_url VARCHAR(2048)
);
以下の場合に別テーブルを使用してください:
- 関連データが大きく、アクセス頻度が低い
- 独立した権限制御が必要
- 関連データが独自のライフサイクルを持つ(例:独自のcreated_at/updated_at)
コンバーターはUNIQUE外部キーを検出すると1:1リレーションを生成し、双方向のリレーションフィールドを自動的に追加します。
自己参照型の一対一
より一般的でないパターンとして、自己参照1:1があります:
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
mentor_id INTEGER UNIQUE,
FOREIGN KEY (mentor_id) REFERENCES employees(id)
);
model Employee {
id Int @id @default(autoincrement())
name String
mentorId Int? @unique @map("mentor_id")
mentor Employee? @relation("EmployeeMentor", fields: [mentorId], references: [id])
mentee Employee? @relation("EmployeeMentor")
@@map("employees")
}
ユースケース
usersテーブルとUNIQUE外部キーでリンクされた別のprofilesテーブルがある場合に、コンバーターが正しい@unique制約とカスケード動作で両方のmodelにPrismaの一対一リレーションフィールドを生成します。