SQLの中間テーブルをPrismaの多対多リレーションに変換する

複合主キーを持つSQLの中間テーブルがPrismaの暗黙的または明示的な多対多リレーションにどのように変換されるかを学びます。両方のパターンとそれぞれの選択基準を解説します。

Relations

詳細な説明

多対多リレーション

SQLは中間(結合)テーブルで2つの外部キーを持つことで多対多リレーションシップをモデル化します。Prismaは暗黙的な多対多(中間modelなし)と明示的な多対多(中間modelあり)の両方をサポートしています。

SQLの例

CREATE TABLE articles (
  id SERIAL PRIMARY KEY,
  title VARCHAR(255) NOT NULL
);

CREATE TABLE tags (
  id SERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL UNIQUE
);

CREATE TABLE article_tags (
  article_id INTEGER NOT NULL,
  tag_id INTEGER NOT NULL,
  PRIMARY KEY (article_id, tag_id),
  FOREIGN KEY (article_id) REFERENCES articles(id) ON DELETE CASCADE,
  FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
);

暗黙的な多対多(シンプルな中間テーブル)

model Article {
  id    Int    @id @default(autoincrement())
  title String
  tags  Tag[]

  @@map("articles")
}

model Tag {
  id       Int       @id @default(autoincrement())
  name     String    @unique
  articles Article[]

  @@map("tags")
}

Prismaが中間テーブルを自動管理します。コンバーターは、中間テーブルに2つの外部キーカラムと複合主キーのみがあり、追加データカラムがない場合にこのパターンを使用します。

明示的な多対多(追加データ付き中間テーブル)

CREATE TABLE enrollments (
  student_id INTEGER NOT NULL,
  course_id INTEGER NOT NULL,
  enrolled_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  grade CHAR(2),
  PRIMARY KEY (student_id, course_id),
  FOREIGN KEY (student_id) REFERENCES students(id),
  FOREIGN KEY (course_id) REFERENCES courses(id)
);
model Student {
  id          Int          @id @default(autoincrement())
  enrollments Enrollment[]

  @@map("students")
}

model Course {
  id          Int          @id @default(autoincrement())
  enrollments Enrollment[]

  @@map("courses")
}

model Enrollment {
  studentId  Int      @map("student_id")
  courseId    Int      @map("course_id")
  enrolledAt DateTime @default(now()) @map("enrolled_at")
  grade      String?  @db.Char(2)
  student    Student  @relation(fields: [studentId], references: [id])
  course     Course   @relation(fields: [courseId], references: [id])

  @@id([studentId, courseId])
  @@map("enrollments")
}

暗黙的 vs 明示的の選択

基準 暗黙的 明示的
中間テーブルにFKカラムのみ はい いいえ
リレーションに追加フィールド 不可 対応
Prismaが中間テーブルを管理 自動的に 自分で管理
中間テーブルを直接クエリ 不可 はい

コンバーターの検出ロジック

  1. テーブルが正確に2つの外部キーカラムで複合PKを構成:暗黙的候補
  2. テーブルに追加の非FKカラム(タイムスタンプ、メタデータ)がある場合:明示的リレーション
  3. いずれかのFKが同じテーブルを参照する場合(自己参照M:N):常に明示的

マイグレーションの注意

SQLからPrismaの暗黙的M:Nに変換する場合、Prismaは中間テーブルが_ArticleToTag(アルファベット順、アンダースコアプレフィックス)という名前であることを期待します。コンバーターはリネームを処理するか、マイグレーションステップを生成します。

ユースケース

シンプルなタグ割り当て用の中間テーブルと、追加メタデータ付きの受講登録テーブルの両方がある場合に、コンバーターが中間テーブルの構造に基づいてPrismaの暗黙的多対多または明示的中間modelのどちらを使用するかを判断します。

試してみる — SQL to Prisma Schema

フルツールを開く