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

関連モード

Prismaスキーマでは、レコード間の関連は@relation属性で定義されます。たとえば、次のスキーマでは、UserモデルとPostモデルの間に一対多関連があります。

schema.prisma
model Post {
id Int @id @default(autoincrement())
title String
author User @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade)
authorId Int
}

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

Prisma ORMには、レコード間の関連をどのように強制するかを指定する2つの関連モードforeignKeysprismaがあります。

Prisma ORMをリレーショナルデータベースで使用する場合、デフォルトではPrisma ORMはforeignKeys関連モードを使用します。これは、外部キーを使用してデータベースレベルでレコード間の関連を強制します。外部キーは、あるテーブルの主キーに基づいて値を取る、別のテーブルの列または列のグループです。外部キーを使用すると、以下のことが可能になります。

  • 参照を壊す変更を防止する制約を設定する
  • レコードへの変更がどのように処理されるかを定義する参照アクションを設定する

これらの制約と参照アクションを組み合わせることで、データの参照整合性が保証されます。

上記のスキーマの例では、PostgreSQLコネクタを使用する場合、Prisma Migrateはデフォルトで次のSQLを生成します。


-- CreateTable
CREATE TABLE "Post" (
"id" SERIAL NOT NULL,
"title" TEXT NOT NULL,
"authorId" INTEGER NOT NULL,

CONSTRAINT "Post_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "User" (
"id" SERIAL NOT NULL,

CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
//highlight-start
ALTER TABLE "Post"
ADD CONSTRAINT "Post_authorId_fkey"
FOREIGN KEY ("authorId")
REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
//highlight-end

この場合、PostテーブルのauthorId列にある外部キー制約は、Userテーブルのid列を参照し、投稿には既存の作者がなければならないことを保証します。ユーザーを更新または削除した場合、ON DELETEおよびON UPDATE参照アクションはCASCADEオプションを指定し、これによりそのユーザーに属するすべての投稿も削除または更新されます。

MongoDBやPlanetScaleなど、一部のデータベースは外部キーをサポートしていません。さらに、場合によっては、開発者が通常は外部キーをサポートしているリレーショナルデータベースで外部キーを使用しないことを好むことがあります。このような状況のために、Prisma ORMはprisma関連モードを提供しています。これは、リレーショナルデータベースにおける関連の一部のプロパティをエミュレートします。prisma関連モードが有効な状態でPrisma Clientを使用すると、クエリの動作は同一または類似していますが、参照アクションと一部の制約はデータベースではなくPrismaエンジンによって処理されます。

警告

Prisma Clientにおける参照整合性と参照アクションのエミュレーションには、パフォーマンス上の影響があります。基盤となるデータベースが外部キーをサポートしている場合は、通常、そちらの方が推奨される選択肢です。

Prismaスキーマで関連モードを設定する方法

関連モードを設定するには、datasourceブロックにrelationModeフィールドを追加します。

schema.prisma
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma"
}
情報

関連モードを設定する機能は、Prisma ORMバージョン3.1.1のreferentialIntegrityプレビュー機能の一部として導入され、Prisma ORMバージョン4.8.0以降で一般提供されています。

relationModeフィールドはPrisma ORMバージョン4.5.0で名前が変更され、以前はreferentialIntegrityという名前でした。

リレーショナルデータベースの場合、利用可能なオプションは次のとおりです。

  • foreignKeys: これは、外部キーを使用してデータベース内の関連を処理します。これはすべてのリレーショナルデータベースコネクタのデフォルトオプションであり、datasourceブロックでrelationModeが明示的に設定されていない場合にアクティブになります。
  • prisma: これは、Prisma Clientで関連をエミュレートします。PlanetScaleデータベースでMySQLコネクタを使用し、PlanetScaleデータベース設定でネイティブの外部キー制約を有効にしていない場合も、このオプションを有効にする必要があります。

MongoDBの場合、利用可能なオプションはprisma関連モードのみです。このモードは、datasourceブロックでrelationModeが明示的に設定されていない場合にもアクティブになります。

警告

関連モードを切り替えると、次回Prisma Migrateまたはdb pushでスキーマに変更を適用するときに、Prisma ORMはデータベースに外部キーを追加または削除します。詳細については、関連モード間の切り替えを参照してください。

foreignKeys関連モードでリレーショナルデータベースの関連を処理する

foreignKeys関連モードは、外部キーを使用してリレーショナルデータベースの関連を処理します。これは、リレーショナルデータベースコネクタ(PostgreSQL、MySQL、SQLite、SQL Server、CockroachDB)を使用する場合のデフォルトオプションです。

foreignKeys関連モードは、MongoDBコネクタを使用する場合は利用できません。PlanetScaleなど、一部のリレーショナルデータベースも外部キーの使用を禁止しています。これらの場合、代わりにprisma関連モードでPrisma ORMの関連をエミュレートする必要があります。

参照整合性

foreignKeys関連モードは、外部キー制約と参照アクションを使用して、データベースレベルで参照整合性を維持します。

外部キー制約

別のレコードとの関連を持つレコードを作成または更新する場合、関連するレコードが存在する必要があります。外部キー制約は、データベースでこの動作を強制します。レコードが存在しない場合、データベースはエラーメッセージを返します。

参照アクション

別のレコードとの関連を持つレコードを更新または削除する場合、参照アクションがデータベースでトリガーされます。関連レコードの参照整合性を維持するために、参照アクションは参照整合性を損なう変更を防ぎ、関連レコードへの変更をカスケードしたり、更新または削除されたレコードを参照するフィールドの値をnullまたはデフォルト値に設定したりします。

詳細については、参照アクションのページを参照してください。

イントロスペクション

foreignKeys関連モードが有効な状態でdb pullコマンドを使用してリレーショナルデータベースをイントロスペクトすると、外部キーが存在する関連に対して@relation属性がPrismaスキーマに追加されます。

Prisma Migrateとdb push

foreignKeys関連モードが有効な状態でPrisma Migrateまたはdb pushを使用してPrismaスキーマに変更を適用すると、スキーマ内のすべての@relation属性に対してデータベースに外部キーが作成されます。

prisma関連モードでPrisma ORMの関連をエミュレートする

prisma関連モードは、各Prisma Clientクエリに対して一部の外部キー制約と参照アクションをエミュレートし、追加のデータベースクエリとロジックを使用して参照整合性を維持します。

prisma関連モードはMongoDBコネクタのデフォルトオプションです。外部キーをサポートしないリレーショナルデータベースを使用する場合も設定する必要があります。たとえば、外部キー制約なしでPlanetScaleを使用する場合は、prisma関連モードを使用する必要があります。

警告

Prisma Clientでの参照整合性のエミュレーションには、参照整合性を維持するために追加のデータベースクエリを使用するため、パフォーマンス上の影響があります。基盤となるデータベースが外部キーで参照整合性を処理できる場合は、通常そちらが推奨されます。

関連のエミュレーションはPrisma Clientクエリでのみ利用可能であり、生のクエリには適用されません。

どの外部キー制約がエミュレートされますか?

レコードを更新する場合、Prisma ORMは外部キー制約をエミュレートします。これは、別のレコードとの関連を持つレコードを更新する場合、関連するレコードが存在する必要があることを意味します。レコードが存在しない場合、Prisma Clientはエラーメッセージを返します。

ただし、レコードを作成する場合、Prisma ORMは外部キー制約をエミュレートしません。無効なデータを作成できる可能性があります。

どの参照アクションがエミュレートされますか?

関連するレコードを持つレコードを更新または削除する場合、Prisma ORMは参照アクションをエミュレートします。

次の表は、各データベースコネクタで利用可能なエミュレートされた参照アクションを示しています。

データベースカスケード制限NoActionSetNullSetDefault
PostgreSQL✔️✔️✔️
MySQL✔️✔️✔️✔️
SQLite✔️✔️✔️
SQL Server✔️✔️✔️✔️
CockroachDB✔️✔️✔️✔️
MongoDB✔️✔️✔️✔️
  • SetDefault参照アクションはprisma関連モードではサポートされていません。
  • NoAction参照アクションは、PostgreSQLおよびSQLiteのprisma関連モードではサポートされていません。代わりに、Restrictアクションを使用してください。

エラーメッセージ

prisma関連モードでエミュレートされた制約と参照アクションによって返されるエラーメッセージはPrisma Clientによって生成され、foreignKeys関連モードのエラーメッセージとは若干異なります。

Example:
// foreignKeys:
... Foreign key constraint failed on the field: `ProfileOneToOne_userId_fkey (index)`
// prisma:
... The change you are trying to make would violate the required relation 'ProfileOneToOneToUserOneToOne' between the `ProfileOneToOne` and `UserOneToOne` models.

イントロスペクション

prisma関連モードが有効な状態でdb pullコマンドを使用してデータベースをイントロスペクトすると、関連はスキーマに自動的に追加されません。代わりに、@relation属性を使用して関連を手動で追加する必要があります。これは一度だけ行う必要があります — 次回データベースをイントロスペクトするときは、Prisma ORMが追加された@relation属性を保持します。

Prisma Migrateとdb push

prisma関連モードが有効な状態でPrisma Migrateまたはdb pushを使用してPrismaスキーマに変更を適用すると、Prisma ORMはデータベースで外部キーを使用しません。

インデックス

外部キー制約を使用するリレーショナルデータベースでは、データベースは通常、外部キー列のインデックスも暗黙的に作成します。たとえば、MySQLはすべての外部キー列にインデックスを作成します。これは、外部キーチェックを高速に実行し、テーブルスキャンを必要としないようにするためです。

prisma関連モードは外部キーを使用しないため、Prisma Migrateまたはdb pushを使用してデータベースに変更を適用してもインデックスは作成されません。代わりに、@@index属性(または該当する場合は@unique@@unique@@id属性)を使用して、関連のスカラーフィールドに手動でインデックスを追加する必要があります。

インデックス検証

インデックスを手動で追加しない場合、クエリはフルテーブルスキャンを必要とする可能性があります。これは低速であり、アクセスされた行ごとに課金されるデータベースプロバイダーでは高価になる可能性があります。これを避けるために、Prisma ORMは、スキーマに@relationで使用されているがインデックスが定義されていないフィールドが含まれている場合に警告します。たとえば、UserモデルとPostモデルの間に関連がある次のスキーマを考えてみましょう。

schema.prisma
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma"
}

model User {
id Int @id
posts Post[]
}

model Post {
id Int @id
userId Int
user User @relation(fields: [userId], references: [id])
}

prisma formatまたはprisma validateを実行すると、Prisma ORMは次の警告を表示します。

With `relationMode = "prisma"`, no foreign keys are used, so relation fields will not benefit from the index usually created by the relational database under the hood. This can lead to poor performance when querying these fields. We recommend adding an index manually.

これを解決するには、Postモデルにインデックスを追加します。

schema.prisma
model Post {
id Int @id
userId Int
user User @relation(fields: [userId], references: [id])

@@index([userId])
}

Prisma VS Code拡張機能(または他のエディタの言語サーバー)を使用すると、警告は必要なインデックスを追加するクイックフィックスで強化されます。

The Quick Fix pop-up for adding an index on a relation scalar field in VS Code

関連モード間の切り替え

関連モード間の切り替えは、リレーショナルデータベースコネクタ(PostgreSQL、MySQL、SQLite、SQL Server、CockroachDB)を使用している場合にのみ可能です。

foreignKeysからprismaへの切り替え

リレーショナルデータベースを使用しており、datasourceブロックにrelationModeフィールドが含まれていない場合のデフォルトの関連モードはforeignKeysです。prisma関連モードに切り替えるには、relationModeフィールドにprismaの値を設定して追加するか、既存の場合はprismaに更新します。

関連モードをforeignKeysからprismaに切り替えると、Prisma Migrateまたはdb pushでスキーマに変更を初めて適用した後、Prisma ORMは次のマイグレーションで以前に作成されたすべての外部キーを削除します。

同じデータベースを使い続ける場合は、通常通り作業を続行できます。外部キーをまったくサポートしないデータベースに切り替える場合、既存のマイグレーション履歴には外部キーを作成するSQL DDLが含まれており、これらのマイグレーションを再実行する必要がある場合にエラーを引き起こす可能性があります。この場合、migrationsディレクトリを削除することをお勧めします。(外部キーをサポートしないPlanetScaleを使用する場合は、通常、Prisma Migrateではなくdb pushを使用することをお勧めします。)

prismaからforeignKeysへの切り替え

prisma関連モードからforeignKeys関連モードに切り替えるには、relationModeフィールドの値をprismaからforeignKeysに更新します。これを行うには、データベースが外部キーをサポートしている必要があります。関連モードを切り替えた後、初めてPrisma Migrateまたはdb pushでスキーマに変更を適用すると、Prisma ORMは次のマイグレーションですべての関連に対して外部キーを作成します。

© . All rights reserved.