GraphQL注册出现Cannot return null for non-nullable field User.createdAt错误如何排查
问题根因分析
- 字段名映射不匹配:你通过
getKnexQuery()调用原生Knex执行插入后,返回的数据库原始字段是蛇形命名的created_at、updated_at,但你的User实体中暴露给GraphQL的字段是驼峰命名的createdAt、updatedAt。原生Knex查询不会触发Mikro-ORM的蛇形/驼峰字段自动转换逻辑,导致返回的user对象中不存在createdAt属性,GraphQL解析非空字段时拿到null就触发报错。 - 实体实例化流程缺失:你没有走Mikro-ORM的实体创建流程,User类中
createdAt = new Date()的默认赋值逻辑不会生效,进一步导致字段无值。 - 校验逻辑遗漏(次要问题):代码中调用
validateRegister拿到校验错误后没有做判断拦截,即使参数不合法也会继续执行后续插入逻辑。
解决方案
方案1:手动映射字段(适合需要保留原生Knex查询的场景)
修改Mutation中try块的代码,将返回的蛇形字段手动转为驼峰:
try{ const result = await (em as EntityManager).createQueryBuilder(User).getKnexQuery().insert({ username: options.username, password: hashedPassword, email: options.email, created_at: new Date(), updated_at: new Date() }).returning("*"); // 手动映射字段名 user = { ...result[0], createdAt: result[0].created_at, updatedAt: result[0].updated_at }; }
方案2:改用Mikro-ORM标准API(更推荐,无需手动处理映射)
替换原生Knex插入逻辑,使用Mikro-ORM的create+persistAndFlush方法,自动处理字段映射和默认值赋值:
try{ user = em.create(User, { username: options.username, password: hashedPassword, email: options.email }); await em.persistAndFlush(user); }
补充修复项
- 补上校验逻辑拦截,避免无效请求:
const errors = validateRegister(options); // 新增校验拦截 if (errors) { return { errors }; } const hashedPassword = await argon2.hash(options.password)
- 统一实体字段的非空约束:你当前User实体中
createdAt的@Property装饰器设置了nullable: true,但对应的@Field没有设置nullable,两边约束不一致会埋下隐患,可修改为保持两边一致:
// 要么设为可空 @Field(() => String, { nullable: true }) @Property({type: "date", default: "Now()", nullable: true}) createdAt = new Date(); // 要么设为非空(更推荐,符合业务逻辑) @Field(() => String) @Property({type: "date", default: "Now()"}) createdAt = new Date();
内容的提问来源于stack exchange,提问作者Simon Balfe
相关产品推荐
相关产品推荐

