メインコンテンツにスキップ

多対一のリレーション

このページでは、多対一のリレーションを紹介し、Prismaスキーマでそれらを使用する方法について説明します。

概要

多対一(1対n)リレーションとは、リレーションの一方の側の1つのレコードが、もう一方の側のゼロ以上のレコードに接続できるリレーションを指します。次の例では、UserモデルとPostモデルの間に多対一のリレーションが1つあります。

model User {
id Int @id @default(autoincrement())
posts Post[]
}

model Post {
id Int @id @default(autoincrement())
author User @relation(fields: [authorId], references: [id])
authorId Int
}

注記 postsフィールドは、基盤となるデータベーススキーマには「現れません」。リレーションの反対側では、アノテーション付きリレーションフィールド authorとそのリレーションスカラーauthorIdは、基盤となるデータベースに外部キーを格納するリレーションの側を表します。

この多対一のリレーションは、以下を表します。

  • 「ユーザーはゼロ以上の投稿を持つことができる」
  • 「投稿は常に著者を持たなければならない」

前の例では、Postモデルのauthorリレーションフィールドは、Userモデルのidフィールドを参照しています。別のフィールドを参照することもできます。この場合、各Postに接続されているUserが1つだけであることを保証するために、フィールドに@unique属性をマークする必要があります。次の例では、authorフィールドは、Userモデルのemailフィールドを参照しており、@unique属性でマークされています。

model User {
id Int @id @default(autoincrement())
email String @unique // <-- add unique attribute
posts Post[]
}

model Post {
id Int @id @default(autoincrement())
authorEmail String
author User @relation(fields: [authorEmail], references: [email])
}
警告

MySQLでは、参照側のインデックスのみを持つ外部キーを作成でき、ユニーク制約は必要ありません。Prisma ORMバージョン4.0.0以降では、このタイプのリレーションをイントロスペクトすると、バリデーションエラーが発生します。これを修正するには、参照フィールドに@unique制約を追加する必要があります。

リレーショナルデータベースにおける複数フィールドリレーション

リレーショナルデータベースのみでは、複数フィールドID/複合キーを使用してこのリレーションを定義することもできます。

model User {
firstName String
lastName String
post Post[]

@@id([firstName, lastName])
}

model Post {
id Int @id @default(autoincrement())
author User @relation(fields: [authorFirstName, authorLastName], references: [firstName, lastName])
authorFirstName String // relation scalar field (used in the `@relation` attribute above)
authorLastName String // relation scalar field (used in the `@relation` attribute above)
}

データベースにおける1対nリレーション

リレーショナルデータベース

次の例は、SQLで1対nリレーションを作成する方法を示しています。

CREATE TABLE "User" (
id SERIAL PRIMARY KEY
);
CREATE TABLE "Post" (
id SERIAL PRIMARY KEY,
"authorId" integer NOT NULL,
FOREIGN KEY ("authorId") REFERENCES "User"(id)
);

authorIdカラム(外部キー)にUNIQUE制約がないため、同じUserレコードを指す複数のPostレコードを作成できます。これにより、リレーションは一対一ではなく、多対一になります。

次の例は、複合キー(firstNamelastName)を使用してSQLで1対nリレーションを作成する方法を示しています。

CREATE TABLE "User" (
firstName TEXT,
lastName TEXT,
PRIMARY KEY ("firstName","lastName")
);
CREATE TABLE "Post" (
id SERIAL PRIMARY KEY,
"authorFirstName" TEXT NOT NULL,
"authorLastName" TEXT NOT NULL,
FOREIGN KEY ("authorFirstName", "authorLastName") REFERENCES "User"("firstName", "lastName")
);

一対一および多対一リレーションの比較

リレーショナルデータベースでは、1対1リレーションと1対nリレーションの主な違いは、1対1リレーションでは、外部キーにUNIQUE制約が定義されている必要があることです。

MongoDB

MongoDBの場合、Prisma ORMは現在、正規化されたデータモデル設計を使用しています。これは、ドキュメントがリレーショナルデータベースと同様の方法でIDによって相互参照することを意味します。

次のMongoDBドキュメントは、Userを表しています。

{ "_id": { "$oid": "60d5922d00581b8f0062e3a8" }, "name": "Ella" }

次の各Post MongoDBドキュメントには、同じユーザーを参照するauthorIdフィールドがあります。

[
{
"_id": { "$oid": "60d5922e00581b8f0062e3a9" },
"title": "How to make sushi",
"authorId": { "$oid": "60d5922d00581b8f0062e3a8" }
},
{
"_id": { "$oid": "60d5922e00581b8f0062e3aa" },
"title": "How to re-install Windows",
"authorId": { "$oid": "60d5922d00581b8f0062e3a8" }
}
]

一対一および多対一リレーションの比較

MongoDBでは、1対1と1対nの違いは、データベース内の別のドキュメントを参照しているドキュメントの数だけです。制約はありません。

多対一リレーションにおける必須およびオプションのリレーションフィールド

1対nリレーションには、常に2つのリレーションフィールドがあります。

1対nリレーションのアノテーション付きリレーションフィールドとリレーションスカラーは、両方ともオプションであるか、両方とも必須であるかのいずれかです。リレーションの反対側では、リストは常に必須です。

オプションの多対一リレーション

次の例では、Userを割り当てることなくPostを作成できます。

model User {
id Int @id @default(autoincrement())
posts Post[]
}

model Post {
id Int @id @default(autoincrement())
author User? @relation(fields: [authorId], references: [id])
authorId Int?
}

必須の多対一リレーション

次の例では、Postを作成するときにUserを割り当てる必要があります。

model User {
id Int @id @default(autoincrement())
posts Post[]
}

model Post {
id Int @id @default(autoincrement())
author User @relation(fields: [authorId], references: [id])
authorId Int
}