Apollo Server 4+Prisma 5 用户与评论双向查询Resolver配置问题
问题描述
使用Apollo Server 4 + Prisma 5搭建电商项目,需要实现用户与评论的双向查询:
- 查询用户时能获取其关联的评论
- 评论作为顶层查询时能返回关联用户
数据库中Comment通过user_id外键关联User,是一对多/多对一关系。
当前问题:
- 查询用户时
comments字段返回null,不想在ORM层用include做关联查询,希望通过Resolver的parent参数实现子字段懒加载 - 运行时报错:
Error: Comment.userComments defined in resolvers, but not in schema
相关代码如下:
Prisma模型
model User { id String @id @default(uuid()) username String @unique email String @unique password String first_name String last_name String? created_at DateTime @default(now()) updated_at DateTime @updatedAt deleted Boolean @default(false) comments Comment[] ratings Rating[] orders Order[] UserAddress UserAddress[] } model Comment { id String @id @default(uuid()) user User @relation(fields: [user_id], references: [id]) user_id String // Change type to String product Product @relation(fields: [product_id], references: [id]) product_id String content String created_at DateTime @default(now()) updated_at DateTime @updatedAt deleted Boolean @default(false) }
GraphQL Schema
type Query { "Get a user by their email" userByEmail(email: String): User! } "This type represents a user in the system" type User { "Unique identifier for the user" id: ID! "Username for login" username: String! "User's email address" email: String! "User's first name" first_name: String! "User's last name (optional)" last_name: String! "List of comments authored by the user (optional)" comments: [Comment] "List of ratings created by the user (optional)" ratings: [Rating] "List of orders placed by the user (optional)" orders: [Order] "List of user's addresses" addresses: [Address] } type Comment { "Unique identifier for the comment" id: ID! "Content of the comment" content: String! "User who authored the comment" user: User "Product this comment is associated with" product: Product }
当前Resolver代码
import { getUserByEmail, getCommentsByUserId } from '../../dataAccessLayer/orm/user'; import { User } from '../../generated/types'; export const resolvers = { Query: { userByEmail: async (_parent: unknown, { email }: { email: string }) => { console.log('parent', email); const user = await getUserByEmail(email); // Already includes comments return user; }, }, Comment: { userComments: (parent: User) => { console.log('parent', parent); const userId = parent.id; return getCommentsByUserId(userId); }, }, };
ORM查询代码
import prisma from '../prismaClient'; export async function getUserByEmail(email: string) { return await prisma.user.findUnique({ where: { email, }, }); } export async function getCommentsByUserId(id: string) { return await prisma.comment.findMany({ where: { user_id: id, }, include: { user: true, // Include user relation }, }); }
解决方案
1. 修正Resolver的字段映射错误
报错原因是Resolver里定义了Comment.userComments,但你的GraphQL Schema中Comment类型并没有这个字段——实际是User类型有comments字段,Comment类型有user字段。调整Resolver结构如下:
import { getUserByEmail, getCommentsByUserId, getUserById } from '../../dataAccessLayer/orm/user'; import { Comment, User } from '../../generated/types'; import prisma from '../prismaClient'; export const resolvers = { Query: { userByEmail: async (_parent: unknown, { email }: { email: string }) => { // 仅查询用户基础数据,不提前关联评论 return await getUserByEmail(email); }, // 补充顶层评论查询,满足"评论作为顶层查询"的需求 commentById: async (_parent: unknown, { id }: { id: string }) => { return await prisma.comment.findUnique({ where: { id } }); }, }, // 实现User类型的comments字段Resolver,懒加载评论 User: { comments: async (parent: User) => { // parent是上层查询返回的User对象,直接用其id查询关联评论 return await getCommentsByUserId(parent.id); }, }, // 实现Comment类型的user字段Resolver,懒加载关联用户 Comment: { user: async (parent: Comment) => { // parent是上层查询返回的Comment对象,用其user_id查询关联用户 return await getUserById(parent.user_id); }, }, };
2. 补充ORM层的查询函数
需要添加通过ID查询用户的函数,用于评论关联用户的查询:
import prisma from '../prismaClient'; export async function getUserByEmail(email: string) { return await prisma.user.findUnique({ where: { email }, }); } export async function getUserById(id: string) { return await prisma.user.findUnique({ where: { id }, }); } export async function getCommentsByUserId(id: string) { // 无需include user,因为Comment的user字段会由Resolver懒加载 return await prisma.comment.findMany({ where: { user_id: id }, }); }
3. 验证查询效果
现在可以执行以下查询验证功能:
- 查询用户及其评论:
query { userByEmail(email: "user@example.com") { id username comments { id content } } }
- 查询评论及其关联用户:
query { commentById(id: "comment-id-123") { id content user { id username } } }
核心原理
- 顶层查询仅返回基础数据,不做预关联查询
- 子字段的Resolver通过
parent参数获取上层对象的关联ID,按需发起数据库查询,实现懒加载,符合GraphQL按需获取数据的最佳实践 - 避免了ORM层提前
include带来的性能浪费,只查询客户端实际需要的数据
内容的提问来源于stack exchange,提问作者CodeConnoisseur
相关产品推荐
相关产品推荐

