如何用Nexus/Prisma正确定义显式多对多关系?方案对比
关于Nexus中Prisma显式多对多关系解析器的方案对比
我是Prisma、Nexus及GraphQL的新手,在Nexus中定义Prisma显式多对多关系的字段解析器时遇到了不小的困难,最终找到了两种可行的实现方案,后来又补充了第三种。想知道哪种方案更优、原因是什么,以及哪里能找到相关性能和优劣的文档。
相关模型定义(schema.prisma)
model User { id Int @id @default(autoincrement()) email String @unique password String groups UsersOnGroups[] recipes Recipe[] lists List[] } model Group { id Int @id @default(autoincrement()) name String users UsersOnGroups[] recipes Recipe[] lists List[] } model UsersOnGroups { user User @relation(fields: [userId], references: [id]) userId Int group Group @relation(fields: [groupId], references: [id]) groupId Int @@id([userId, groupId]) }
仅展示User模型,Group模型实现逻辑基本一致,为简洁起见省略了部分字段。
三种实现方案
方案一:直接查询中间表
export const User = objectType({ name: 'User', definition(t) { t.nonNull.int('id') t.string('email') t.nonNull.list.nonNull.field('groups', { type: Group, resolve: async (parent, _args, context) => { const groups = await context.prisma.usersOnGroups.findMany({ where: { userId: parent.id, }, include: { group: true, }, }) return groups.map((groupRelation) => groupRelation.group) }, }) }, })
方案二:反向查询Group模型
export const User = objectType({ name: 'User', definition(t) { t.nonNull.int('id') t.string('email') t.nonNull.list.nonNull.field('groups', { type: Group, resolve: (parent, _args, context) => { return context.prisma.group.findMany({ where: { users: { every: { userId: parent.id, }, }, }, }) }, }) }, })
补充方案:通过User模型关联查询中间表
t.nonNull.list.nonNull.field('groups', { type: Group, resolve: async (parent, _args, context: Context) => { const groups = await context.prisma.user .findUnique({ where: { id: parent.id, }, }) .groups({ include: { group: true, }, }) return groups?.map((groupRelation) => groupRelation.group) ?? [] }, })
方案优劣对比与结论
各方案分析
- 方案一:逻辑直观,直接操作中间表关联Group,生成的SQL是单表JOIN查询,利用中间表的索引能保证高效查询。缺点是需要手动处理结果映射,代码稍显繁琐。
- 方案二:语义不直观,反向查询Group的写法不符合"查询用户所属组"的业务逻辑;
every条件生成的SQL可能存在性能隐患,当Group数据量大时,过滤效率远低于直接从中间表查询。 - 补充方案:贴合Prisma关联查询的设计理念,代码更简洁;生成的SQL与方案一类似,性能相当,同时规避了手动映射的繁琐,是更符合Prisma最佳实践的写法。
最优选择
优先使用补充方案,其次是方案一;方案二因语义不直观和潜在性能问题,不推荐使用。
相关文档参考
你可以在Prisma官方文档的这些板块找到对应内容:
- 显式多对多关系章节:讲解模型设计和基础查询方式;
- 性能优化板块:包含索引优化、查询效率分析的内容;
- 关联查询指南:对比不同关联查询写法的差异及生成的SQL逻辑。
内容的提问来源于stack exchange,提问作者theiereman
相关产品推荐
相关产品推荐

