跳到主要内容

将隐式多对多关系转换为显式多对多关系

问题

多对多关系是关系数据库的重要方面,它允许一个表中的多条记录与另一个表中的多条记录相关联。Prisma 提供了两种建模多对多关系的方法:隐式和显式。

用户有时会遇到需要将模型之间的隐式多对多关系转换为显式关系的情况。将隐式关系转换为显式关系可以让你对该关系拥有更多控制权,并可以存储与该关系相关的额外数据,例如时间戳或任何其他字段。本指南提供了关于如何进行这种转换的分步说明。

解决方案

这将指导你完成在 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 模型中的 posts 和 Post 模型中的 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[]
}

在 schema 文件中进行更改后,你可以调用此命令

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

运行上述命令将删除隐式表 _PostToUser

现在你已成功地在 Prisma 中将隐式多对多关系转换为显式关系。