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

暗黙的な多対多リレーションから明示的な多対多リレーションへの変換

問題点

多対多リレーションシップは、リレーショナルデータベースの重要な側面であり、1つのテーブルの複数のレコードを別のテーブルの複数のレコードに関連付けることができます。Prismaは、多対多リレーションシップをモデル化するための2つのアプローチを提供します:暗黙的および明示的

ユーザーは、モデル間の暗黙的な多対多リレーションシップから明示的なものに移行する必要がある状況に遭遇することがあります。暗黙的なリレーションを明示的なものに変換すると、リレーションをより詳細に制御し、タイムスタンプやその他のフィールドなど、リレーションに固有の追加データを保存できます。このガイドでは、その変換を行う方法をステップごとに説明します。

解決策

これは、Prismaで暗黙的な多対多リレーションを明示的なものに変換するプロセスをガイドします。

postsおよびauthorフィールドを介した暗黙的な多対多リレーションシップを持つこれらのモデルを検討してください。

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

model Post {
id Int @id @default(autoincrement())
title String
authors User[]
}

上記のモデルでは、Userは複数の投稿を持つことができ、Postは複数の著者を持つことができます。

暗黙的なリレーションを明示的なリレーションに変換するには、リレーションテーブルを作成する必要があります。リレーションテーブルには、多対多リレーションに関係する両方のテーブルを参照する外部キーが含まれます。この例では、UserPostという新しいモデルを作成します。更新されたschema.prismaファイルは次のようになります。

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

model Post {
id Int @id @default(autoincrement())
title String
authors User[]
userPosts UserPost[]
}

model UserPost {
id Int @id @default(autoincrement())
userId Int
postId Int
user User @relation(fields: [userId], references: [id])
post Post @relation(fields: [postId], references: [id])
createdAt DateTime @default(now())

@@unique([userId, postId])
}

Prisma Migrateを使用している場合は、このコマンドを呼び出すことができます。

npx prisma migrate dev --name "added explicit relation"

移行により、UserPostテーブルが作成され、UserモデルとPostモデルの多対一リレーションがUserPostモデルで作成されます。

既存のデータを暗黙的なリレーションテーブルから新しく作成されたリレーションテーブルに移行する

既存のデータを暗黙的なリレーションテーブルから新しい明示的なリレーションテーブルに移行するには、カスタム移行スクリプトを作成する必要があります。Prisma Clientを使用してデータベースを操作し、暗黙的なリレーションテーブルからデータを読み取り、新しいリレーションテーブルに書き込むことができます。

上記のUserモデルとPostモデルを考慮すると、データを移行するために使用できるスクリプトの例を次に示します。

import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

// A `main` function so that you can use async/await
async function main() {
try {
// Fetch all users with their related posts
const users = await prisma.user.findMany({
include: { posts: true },
});

// Iterate over users and their posts, then insert records into the UserPost table
for (const user of users) {
for (const post of user.posts) {
await prisma.userPost.create({
data: {
userId: user.id,
postId: post.id,
},
});
}
}

console.log("Data migration completed.");
} catch (e) {
console.error(e);
}
}

main()
.catch((e) => {
throw e;
})
.finally(async () => {
await prisma.$disconnect();
});

データがリレーションテーブルに移行されたら、以下に示すように、暗黙的なリレーション列(UserモデルのpostsPostモデルのauthor)を削除できます。

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

model Post {
id Int @id @default(autoincrement())
title String
authors User[]
userPosts UserPost[]
}

スキーマファイルを変更した後、このコマンドを呼び出すことができます。

npx prisma migrate dev --name "removed implicit relation"

上記のコマンドを実行すると、暗黙的なテーブル_PostToUserが削除されます。

これで、Prismaで暗黙的な多対多リレーションを明示的なものに正常に変換できました。