JavaScriptを有効にしてください

【Prisma】関連付けの書き方

 ·  ☕ 3 分で読めます  ·  🐙 subaru

prismaの関連付けをまとめていきたいと思います。

one to one

一つのテーブルに一つの子テーブルを紐づける場合に使用します。
ここでは、Userにプロフィール情報を持たせたい場合を想定しています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
model User {
  id               String            @id @default(cuid())
  name             String
  email            String            @unique
  emailVerified    DateTime?
  profile          Profile?
}

model Profile {
  id     Int    @id @default(autoincrement())
  weight Int
  userId String @unique
  user   User   @relation(fields: [userId], references: [id])
}

親テーブルには子モデルを型としたカラムを追加します。
下記Userテーブルで言うところのprofile Profile?です。
Profileの末尾についている?は、null許容の?ですね。

1
2
3
4
5
6
7
model User {
  id               String            @id @default(cuid())
  name             String
  email            String            @unique
  emailVerified    DateTime?
  profile          Profile?
}

子テーブルには、親テーブルのkeyと親モデルを型としたカラムを用意します。
カラム名は任意ですが、モデル名Idとするのが一般的です。
one to oneの場合、モデル名Idは一意になるのが自然なので、@uniqueをつけています。
また、関連付けを定義するために、@relationをつけています。
fieldsには親Idの対象を、referencesには自分のidを入れます。

1
2
3
4
5
6
model Profile {
  id     Int    @id @default(autoincrement())
  weight Int
  userId String @unique
  user   User   @relation(fields: [userId], references: [id])
}

one to many

1対多のパターンです。
親が子を何人も作り出せる形ですね。
ユーザーが複数投稿できる場合を考えてみます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
model User {
  id               String            @id @default(cuid())
  name             String
  email            String            @unique
  emailVerified    DateTime?
  posts            Post[]
}


model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  author    User    @relation(fields: [authorId], references: [id])
  authorId  String
}

親テーブルにはArray型の子モデルが入るカラムを用意します。カラム名は任意ですが、わかりやすくするため、camel caseかつ複数形にするのが一般的です。

1
2
3
4
5
6
7
model User {
  id               String            @id @default(cuid())
  name             String
  email            String            @unique
  emailVerified    DateTime?
  posts            Post[]
}

次に子テーブルです。
親は一つなので、単数系の親モデルを型とするカラムと、親keyカラムを用意して終了です。

1
2
3
4
5
6
7
8
model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  author    User    @relation(fields: [authorId], references: [id])
  authorId  String
}

many to many

多対多の関連付けの場合です。
多対多の関連付けは、一つの中間テーブルを二つのテーブルが共有するイメージです。
ここでは、お酒がカテゴライズされるケースを想定しています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
model Alcohol {
  id                  Int                   @id @default(autoincrement())
  name                String
  description         String
  percentage          Int
  favoritedBy         FavoriteAlcohol[]
  alcoholGlasses      AlcoholPouredGlass[]
  categoriesOnAlcohol CategoriesOnAlcohol[]
}

model CategoriesOnAlcohol {
  id         Int      @id @default(autoincrement())
  alcoholId  Int
  categoryId Int
  alcohol    Alcohol  @relation(fields: [alcoholId], references: [id])
  category   Category @relation(fields: [categoryId], references: [id])
}

model Category {
  id                  Int                   @id @default(autoincrement())
  name                String
  categoriesOnAlcohol CategoriesOnAlcohol[]
}

まず関連付けたいテーブルに、中間テーブルを複数持てるカラムを用意します。
混乱しやすい書き方なのですが、これは一つのカラムで複数のデータを管理しているわけではありません。
複数持てるということを明示しているだけです。
Alcoholテーブルでいう、categoriesOnAlcohol CategoriesOnAlcohol[]のところです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
model Alcohol {
  id                  Int                   @id @default(autoincrement())
  name                String
  description         String
  percentage          Int
  categoriesOnAlcohol CategoriesOnAlcohol[]
}

model Category {
  id                  Int                   @id @default(autoincrement())
  name                String
  categoriesOnAlcohol CategoriesOnAlcohol[]
}

中間テーブルには、リレーション対象のモデルを一つづつ定義します。
one to manyで説明した、many側のテーブルに書いた要素を二つにした感じです。
中間テーブルに持たせる内容は、主に可変要素なので納得ですね。

1
2
3
4
5
6
7
model CategoriesOnAlcohol {
  id         Int      @id @default(autoincrement())
  alcoholId  Int
  categoryId Int
  alcohol    Alcohol  @relation(fields: [alcoholId], references: [id])
  category   Category @relation(fields: [categoryId], references: [id])
}

後述

schemaドリブンの場合、schemaにテーブル定義を書いてからprisma generateをするので今回のように定義すれば良いですが、普通はmigration ファイルで管理するでしょう。その方がログが残り、migration upとdownしやすくなるので便利だからです。

共有

octpsubaru
著者
subaru
Web Developer