Apollo 和 Prisma Graphql 显式模型关系不可查询
Posted
技术标签:
【中文标题】Apollo 和 Prisma Graphql 显式模型关系不可查询【英文标题】:Apollo and Prisma Graphql explicit model relationship not queryable 【发布时间】:2021-10-14 07:02:26 【问题描述】:我已经开始测试 prisma 2 和 graphql 以用于一个新的应用程序。我遇到了一个关于能够查询关系的显式多对多表的问题。
这是我的阿波罗模式:
scalar DateTime
type Query
user(id: String!): User
users: [User]
spaces: [Space]
roles: [Role]
type Mutation
createUser(id: String!, email: String!): User!
createSpace(name: String!): Space!
type User
id: ID!
email: String!
spaces: [UserSpace!]
createdAt: DateTime!
updatedAt: DateTime!
type Space
id: ID!
name: String!
users: [UserSpace!]
createdAt: DateTime!
updatedAt: DateTime!
type Role
id: ID!
name: String!
description: String!
users: UserSpace
createdAt: DateTime!
updatedAt: DateTime!
type UserSpace
id: ID!
user: User!
space: Space!
role: Role!
createdAt: DateTime!
updatedAt: DateTime!
这是我的棱镜架构:
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
// npx prisma migrate dev
// npx prisma generate
datasource db
provider = "postgresql"
url = env("DATABASE_URL")
generator client
provider = "prisma-client-js"
model User
id String @id
email String @unique
spaces UserSpace[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
model Space
id Int @default(autoincrement()) @id
name String @unique
users UserSpace[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
model Role
id Int @default(autoincrement()) @id
name String @unique
description String
users UserSpace[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
model UserSpace
id Int @default(autoincrement()) @id
user User @relation(fields: [userId], references: [id])
userId String
space Space @relation(fields: [spaceId], references: [id])
spaceId Int
role Role @relation(fields: [roleId], references: [id])
roleId Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
这是我的突变解析器:
const prisma = require(".prisma/client");
async function createUser(parent, args, context, info)
return await context.prisma.user.create(
data:
...args,
,
);
async function createSpace(parent, args, context, info)
const isAuthenticated = context.authentication.isAuthenticated;
let role = null;
if(!isAuthenticated)
throw new Error("Not Authenticated");
try
role = await context.prisma.role.findUnique(
where:
name: "Space Administrator",
,
);
catch(err)
throw new Error(err);
return await context.prisma.space.create(
data:
...args,
users:
create:
role:
connect: id: role.id ,
,
user:
connect: id: context.authentication.auth0Id ,
,
,
,
,
);
module.exports =
createUser,
createSpace,
这是我的用户解析器(我知道这是问题所在,但我不知道如何解决问题):
function spaces(parent, args, context, info)
return context.prisma.user.findUnique( where: id: parent.id ).spaces();
module.exports =
spaces,
基本上,当我创建空间时,用户被添加为空间管理员,然后应该能够使用以下内容进行查询:
query
users
id
email
spaces
id
role
name
space
name
createdAt
但是,当我运行查询时,出现以下错误:
"message": "Cannot return null for non-nullable field UserSpace.role.",
在 prisma 2 中,我如何使用户的解析器使用显式的多对多表以及它如何在其中具有第三个关系?我是 prisma 和 graphql 的新手,所以如果还有其他突出的内容,我也想提供意见。
【问题讨论】:
【参考方案1】:您是否向用户 arg 提供了价值?像这样:users(id: "string_value")
。因为是id
是必需的。
【讨论】:
是的 id 有一个值,但似乎用户解析器找不到正确的信息,因此它总是返回 null。我相信这是因为多对多具有第三种角色关系的性质。 我不明白你的评论?你是说用三个关系做一个关系表是不可能的? 我不是在说关于 Prisma 的任何事情,但是当您不提供所需的值时,这些显而易见的事情就会发生,因为它们都捆绑在一起。这就是我所说的 graphql 的工作原理。【参考方案2】:我使用单词 type
来指代 GraphQL 架构中的对象模型,使用 model
来指代 Prisma 架构中的数据模型。
问题
我看到你有一个User
类型的解析器,它在你的User
类型中有一个User.spaces
字段的解析器函数。您在User.spaces
解析器中定义的查询将从数据库中返回相关的userSpace
记录。
但是,这些 userSpace
记录默认不解析 role
字段,因为它是一个关系字段。这就是 prisma 的工作原理(默认情况下不解析关系字段,除非明确说明)。
解决方案
为UserSpace
类型创建解析器,并为UserSpace.role
字段显式定义解析器函数。这就是它的样子
// UserSpace resolver module
function role(parent, args, context, info)
return context.prisma.userSpace.findUnique( where: id: parent.id ).role();
module.exports =
role,
虽然还有其他一些方法可以解决这个问题,但推荐使用我展示的方法(以及特定的语法),因为在底层它允许 prisma 对solve the n+1 query problem 执行某些优化。但是,如果你不知道那是什么,你也不必担心。
【讨论】:
这更有意义,这正是我想要的。我希望 prisma 能够在明确的多对多关系上更新他们的文档,因为这些关系很可能在框架中更常见于自省。 澄清一下,这种行为并不局限于明确的多对多关系。默认情况下,查询期间不返回任何关系字段(和相应的对象)(包括隐式关系)。您可以通过使用include
或select
关键字并指定关系字段来更改此行为。但是,为这些关系字段中的每一个创建手动解析器(就像我展示的那样)是最佳实践,并且可以避免潜在的错误/极端情况问题。以上是关于Apollo 和 Prisma Graphql 显式模型关系不可查询的主要内容,如果未能解决你的问题,请参考以下文章
使用 Apollo + GraphQL 将 Prisma 1 升级到 Prisma 2
Apollo 和 Prisma Graphql 显式模型关系不可查询
Prisma、GraphQL 和 Apollo 中具有突变的数据关系和连接类型