Prismaでリレーションを定義する
はじめに
Prismaでリレーションを定義する際のメモになります
基本的にはPrismaのドキュメントを意訳したものになります
概要
Prismaにおける下記のリレーションの定義方法についてのメモ
- 1対1(One to One)のリレーション
- 1対多(One to Many)のリレーション
- 多対多(Many to Many)のリレーション
1対1(One to One)のリレーション
model User {
id Int @id @default(autoincrement())
email String
profile Profile?
}
model Profile {
id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [id]) // fields: [userId] = Profile.userId, references: [User.id]
userId Int // relation scalar field (used in the `@relation` attribute above)
}
- Userテーブル側
- profile Profile? としてProfileモデルへの接続を定義する(Profileはオプショナル型)
- Profileテーブル側
- user User @relation(fields: [userId], references: [id]) としてUserモデルへの接続を定義
- 上記の fields は自身のモデル(Profile)の項目、references にはProfileからみた参照先のモデル(User)の項目をいれる
- 実際に参照を持つ項目として userId Int を定義する
ポイントは、
接続する側のモデル/接続される側のモデル の 両方のモデルにリレーションを定義する 必要があります
id以外への項目にリレーションを定義する場合
id以外の項目にリレーションを定義する場合、
ProfileモデルからみたUserモデルが一意になるように、参照先の項目に @unique をつけます
model User {
id Int @id @default(autoincrement())
email String @unique // <-- add unique attribute
profile Profile?
}
model Profile {
id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [email])
userId Int @unique // relation scalar field (used in the `@relation` attribute above)
}
1対多(One to Many)のリレーション
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
}
基本的には1対1(One to One)のリレーションと同じ考え方になります
1Userあたり複数のPostを持つことになるため、
Userモデル側のリレーションは posts Post[] として配列の型で定義します
多対多(Many to Many)のリレーション
多対多(Many to Many)のリレーション定義は、
①明示的(explicit)な定義
②暗黙的(implicit)な定義
の2通りの定義方法があります
明示的なリレーション定義
明示的なリレーション定義では、
接続したいモデルA(Post)とモデルB(Category)の間に、
中間モデル(CategoriesOnPosts) を指定します
型は1対多の時同様に、配列の型で定義します
model Post {
id Int @id @default(autoincrement())
title String
categories CategoriesOnPosts[]
}
model Category {
id Int @id @default(autoincrement())
name String
posts CategoriesOnPosts[]
}
model CategoriesOnPosts {
post Post @relation(fields: [postId], references: [id])
postId Int // relation scalar field (used in the `@relation` attribute above)
category Category @relation(fields: [categoryId], references: [id])
categoryId Int // relation scalar field (used in the `@relation` attribute above)
assignedAt DateTime @default(now())
assignedBy String
@@id([postId, categoryId])
}
上記に中間モデル(CategoriesOnPosts)の中で、
モデルA(Post)とモデルB(Category)への接続を定義します
また、
@@id([postId, categoryId])
として、それぞれを参照する項目を @@id に指定します
※マルチフィールドリレーション
暗黙的なリレーション定義
暗黙的なリレーション定義では、中間モデルの記載がない分
明示的なリレーション定義よりもシンプルな記載となります
model Post {
id Int @id @default(autoincrement())
categories Category[]
}
model Category {
id Int @id @default(autoincrement())
posts Post[]
}
暗黙的なリレーション定義では、モデルの記載がシンプルになる分、
下記のようないくつかのルールを意識する必要があります
- リレーション テーブルにConventions for relation tablesを使用すること
- リレーションに明示的に名前をつけて管理したい時以外は、 @relation は不要
- @relation を使う場合は、 references, fields, onUpdate or onDelete の属性は使えない
- マルチフィールドリレーション及び @id の変わりに @unique を使用することはできない
Rules for defining an implicit m-n relation
Implicit m-n relations:
Use a specific convention for relation tables
Do not require the @relation attribute unless you need to disambiguate relations with a name, e.g. @relation("MyRelation") or @relation(name: "MyRelation").
If you do use the @relation attribute, you cannot use the references, fields, onUpdate or onDelete >arguments. This is because these take a fixed value for implicit m-n relations and cannot be changed.
Require both models to have a single @id. Be aware that:
You cannot use a multi-field ID
You cannot use a @unique in place of an @id
上記のうち、1つ目のConventions for relation tablesについては、
npx prisma migrate
を使用を使用しない場合(手動でSQLを生成する場合)は意識する必要がありそうです
まとめ
- リレーション定義は接続する側のモデル・接続される側のモデルの両方に記載する
- n対多のリレーションを定義する際は モデル名[]とする
- 多対多のリレーション定義は明示的指定と暗黙的指定の2種類がある
参考
Prisma 公式ドキュメント
One-to-one relations
One-to-many relations
Many-to-many relations
Prismaの使い方を学ぶ
PrismaでMany-to-manyのテーブルを定義する
Discussion