我无法理解如何从GraphQL Union检索信息。我有这样的地方:
const Profile = StudentProfile | TeacherProfile
然后在我的解析器中有
Profile: {
__resolveType(obj, context, info) {
if (obj.studentId) {
return 'StudentProfile'
} else if (obj.salaryGrade) {
return 'TeacherProfile'
}
},
},
这不会引发任何错误,但是当我运行这样的查询时:
query {
listUsers {
id
firstName
lastName
email
password
profile {
__typename
... on StudentProfile {
studentId
}
... on TeacherProfile {
salaryGrade
}
}
}
}
这将返回所有内容,但配置文件仅返回null
。我正在使用Sequelize来处理数据库工作,但是我对Union的理解是,它只需查找要查询的ID的相关类型并在查询中返回适当的详细信息即可。
如果我弄错了,如何使该查询起作用?
编辑:
我的列表用户解析器:
const listUsers = async (root, { filter }, { models }) => {
const Op = Sequelize.Op
return models.User.findAll(
filter
? {
where: {
[Op.or]: [
{
email: filter,
},
{
firstName: filter,
},
{
lastName: filter,
},
],
},
}
: {},
)
}
用户模型关系(非常简单,与配置文件没有关系)
User.associate = function(models) {
User.belongsTo(models.UserType)
User.belongsTo(models.UserRole)
}
和我的一般用户解析器:
User: {
async type(type) {
return type.getUserType()
},
async role(role) {
return role.getUserRole()
},
},
答案 0 :(得分:1)
最简单的方法是利用单个表(即single table inheritance)。
student_id
和salary_grade
列,即使这些列将作为架构中单独类型的字段公开。__typename
(稍后会详细介绍)会很有帮助。__resolveType
方法,该方法根据您添加的“类型”字段返回适当的类型名称。但是,如果您将此字段命名为__typename
,并使用要公开的GraphQL类型的名称填充它,则实际上可以跳过此步骤!find
方法查询表或与其建立关联。例如,您可以添加诸如User.belongsTo(Profile)
之类的关系,然后延迟加载它:User.findAll({ include: [Profile] })
。此方法的最大缺点是您丢失了数据库级和模型级验证。也许salary_grade
对于TeacherProfile
永远不能为null,但是您不能通过约束来强制执行此操作,也不能将属性的allowNull
属性设置为false
。充其量,您只能依靠GraphQL的类型系统来执行验证,但这并不理想。
您可以更进一步,并为每个单独的“类型”创建其他Sequelize模型。这些模型仍将指向同一张表,但仅包含特定于您要为每种类型公开的字段的属性。这样,您至少可以在模型级别强制实施“必需”属性。然后,例如,您使用Profile
模型来查询所有个人资料,但是在插入或更新教师个人资料时使用TeacherProfile
。这样效果很好,请注意,在构造这样的模型时不能使用sync
方法-您需要手动处理迁移。无论如何,您都不应该在生产中使用sync
,因此这不是一笔很大的交易,但绝对是要注意的事情。