Skip to content

RDB で複数のオブジェクトの関係を定義する

リレーショナル・データベースでは、名前の通り、複数のものの「関係(リレーション)」を定義することができます。今回は以下のような疑似アプリを考えてみましょう。

  • ユーザーがいる
  • ポスト (投稿) がある
  • ユーザーは、ポストを作成できる

基礎的なスキーマを定義する

まずは、誰が作ったかの情報を持たせる必要があります。

model User {
id Int @id @default(autoincrement())
name String
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
creatorId Int
content String
}

次に、「ポストの creator_id (creatorId) は存在するユーザーの id でなければならない」という制約を追加してみましょう。

model User {
id Int @id @default(autoincrement())
name String
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
creatorId Int
creator User @relation(fields: [creatorId], references: [id])
content String
}

これで、次の効果が得られました:

  • post から作成者をたどるための情報が creator_id (creatorId) に保存される
  • postcreator_id (creatorId) カラムに「creatoridに存在する値でなくてはならない」という制約が追加される

データを取得する

では、データを取得してみましょう。id = 1 のユーザーの情報をポストと一緒に取ってくることを想定します。

const user = await prisma.user.findUnique({
where: { id: 1 },
include: {
posts: true,
},
});

ユーザーを削除する

このままでは、ポストを作成したユーザーが削除できなくなってしまいます。

なぜでしょうか。考えてみましょう。

正解は、 posts.creator_id に制約

  • creatoridに存在する値でなくてはならない

があるからです。ポストを作成したユーザーを削除すると、そのポストの creator_id が存在しない値を指すようになってしまいます。

これを解決するには複数の方法があり、

  1. そもそも矛盾が生じるような削除をさせない (デフォルト)
  2. 削除されたユーザーを指していた posts.creator_idNULL にする
  3. 作成者が削除されたような posts をすべて削除する

などがあります。今回は 3 の、ユーザーが削除されたらそのユーザーの作った posts もすべて削除するようにしてみましょう。

といってもプログラムの方の変更は必要なく、スキーマを少し変更するだけで達成できます。

model User {
id Int @id @default(autoincrement())
name String
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
creatorId Int
creator User @relation(fields: [creatorId], references: [id], onDelete: Cascade)
content String
}