Hasura Relay端点下非树状关联对象的GraphQL插入方案问询
解决方案:Hasura中一次性插入关联的a、b、c对象(单事务)
问题原因分析
- 嵌套插入报错:c表的
b_id是NOT NULL约束,无论是a→b→c还是a→c→b的嵌套插入顺序,都无法在插入c时拿到已生成的b的ID(Hasura嵌套插入的执行逻辑无法满足这种循环依赖的字段填充),直接触发非空约束违规。 - 插入c后无法自动更新b的c_id:Hasura默认仅处理正向外键关联的自动填充(比如b关联a时自动设置
a_id),但一对一关系的反向字段(b的c_id)不会自动同步,必须显式执行更新操作。
推荐处理方案
方案1:单事务多Mutation(无需修改数据库)
利用Hasura支持单请求多Mutation的特性,所有操作会在同一个事务中完成,任一环节失败则全部回滚,彻底解决分步操作的性能损耗问题。
示例GraphQL Mutation:
mutation InsertABC { # 插入a及关联的b,获取a和b的ID insert_a: insert_a_one(object: { bs: {data: {}} }) { id bs { id } } # 用返回的a、b ID插入c insert_c: insert_c_one(object: { a_id: $insert_a.id b_id: $insert_a.bs[0].id }) { id } # 更新b的c_id字段 update_b: update_b_by_pk( pk_columns: {id: $insert_a.bs[0].id} _set: {c_id: $insert_c.id} ) { id } }
方案2:PostgreSQL触发器自动同步(简化Mutation)
通过在数据库中创建触发器,让插入c的操作自动同步更新对应b的c_id字段,省去手动更新步骤,进一步简化Mutation逻辑。
第一步:创建触发器函数和触发器
在PostgreSQL中执行以下SQL:
-- 定义触发器函数:插入c后自动更新对应b的c_id CREATE OR REPLACE FUNCTION sync_b_c_id_after_c_insert() RETURNS TRIGGER AS $$ BEGIN UPDATE b SET c_id = NEW.id WHERE b.id = NEW.b_id; RETURN NEW; END; $$ LANGUAGE plpgsql; -- 给c表绑定触发器 CREATE TRIGGER trigger_sync_b_c_id AFTER INSERT ON c FOR EACH ROW EXECUTE FUNCTION sync_b_c_id_after_c_insert();
第二步:简化后的GraphQL Mutation
mutation InsertABC { # 插入a及关联的b,获取a和b的ID insert_a: insert_a_one(object: { bs: {data: {}} }) { id bs { id } } # 插入c,触发器自动同步更新对应b的c_id insert_c: insert_c_one(object: { a_id: $insert_a.id b_id: $insert_a.bs[0].id }) { id } }
两种方案均能实现单事务内完成关联对象插入,避免分步操作的性能问题。若不希望修改数据库结构,优先选择方案1;若允许调整数据库配置,方案2的Mutation逻辑更简洁。
内容的提问来源于stack exchange,提问作者Jay Lee
相关产品推荐
相关产品推荐

