我正在使用 Apollo Server 4 和 Prisma 5 构建一个简单的 ecomm 项目。目前,我正在尝试设置我的解析器,以便能够双向查询用户及其评论...并且还将评论作为顶层查询并返回其关联的用户。在数据库中,
Comment
表与 user_id
表具有关联的 User
FK 关系。 User
表没有评论 ID,因此是一 -> 多和多 -> 一关系。
当我尝试查询用户时,注释是
null
,除非我为其编写单独的解析器,然后使用 Prisma orm 来 include
关系。我不想遵循这一点,因为在使用 gql 时它似乎是一种反模式。我想要完成的是在我的 SDL 的顶级 userByEmail()
中有一个 Query{}
解析器...然后在我的解析器中有一个 Comment: {}
第二级对象,然后让相应的 User
成为 parent
参数传入解析器...这比 db 更依赖于 gql。
相关 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)
}
相关 schema.graphql 类型:
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
}
解析器.ts
import { getUserByEmail, getCommentsByUserId } from '../../dataAccessLayer/orm/user';
import { User } from '../../generated/types';
// Use intersection type to combine Resolvers and Query
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
},
});
}
当我运行我的项目时,我收到此错误:
Error: Comment.userComments defined in resolvers, but not in schema
[0] at addResolversToSchema
如何使用 Apollo 推荐方法正确查询子字段,即使用
(parent, args, context, info)
参数,其中 parent
应该是尝试获取评论时最初查询的相关用户?这样我就不会在 orm 级别将数据库查询拼接在一起。
谢谢!
查看 apollo 服务器文档中的示例,了解 如何实现解析器
在架构中,您已经将
comments
属性包含到 User
类型
type User {
id: ID!
username: String!
"List of comments authored by the user (optional)"
comments: [Comment]
# ... other fields
}
您还定义了
userByEmail
来获取顶级类型中的用户 Query
type Query {
userByEmail(email: String): User!
}
接下来,您需要为此架构实现解析器。对于类型
Query
,您需要为方法 userByEmail
实现解析器。你已经完成了这部分
import { getUserByEmail } from '../../dataAccessLayer/orm/user';
import { User } from '../../generated/types';
// Use intersection type to combine Resolvers and Query
export const resolvers = {
Query: {
userByEmail: async (_, { email }: { email: string }) => {
console.log('parent', email);
const user = await getUserByEmail(email); // Already includes comments
return user;
},
},
};
您需要做的下一件事是为 comments 属性定义 resovler,这将是您想要的:用户评论。
import { getUserByEmail, getCommentsByUserId } from '../../dataAccessLayer/orm/user';
import { User } from '../../generated/types';
// Use intersection type to combine Resolvers and Query
export const resolvers = {
Query: {
userByEmail: async (_, { email }: { email: string }) => {
const user = await getUserByEmail(email); // Already includes comments
return user;
},
},
// User. not Comment.
User: {
// The parent entity for comments field is user
comments: async (parent: User, _: any) {
if (parent.comments !== undefined) {
// you mentioned that user fetched with userByEmail already
// includes comments, so you might not even need to refetch it
return parent.comments
}
const comments = await getCommentsByUserId(user.id)
return comments;
},
}
};
这是与我们的架构兼容的查询示例
query userWithComments($email: String!) {
userByEmail(email: $email) {
id
username
# some other fields
comments {
id
content
}
}
}