NestJS集成Objection.js使用withGraphFetched时报$relation属性读取错误
错误原因
这个报错的核心原因是关联映射中对应的模型类加载结果为undefined,Objection尝试读取其静态属性$relation时触发异常,具体有两个触发点:
- 循环依赖导致模型未初始化:
ResourceGroupModel和AttributeModel互相导入作为关联模型,TypeScript默认的CommonJS模块加载机制下,循环导入会让其中一个模块在初始化阶段拿到未完成的导出对象,直接赋值给modelClass就会变成undefined。 - 模型路径配置错误:
AttributeModel中使用了.js后缀的字符串路径加载关联模型,在TypeScript开发环境(如ts-node运行)下,源码目录下只有.ts文件,对应路径找不到.js文件,导致模型加载失败。
修复方案
步骤1:修改关联映射为延迟加载模式
Objection官方支持modelClass传入函数实现延迟加载,等两个模块都初始化完成后才会执行函数返回模型类,从根源解决循环依赖问题,同时弃用易出错的字符串路径配置:
修正resource-group.model.ts
// 原有导入保持不变 export class ResourceGroupModel extends BaseModel { static tableName = 'resource_group'; // 原有字段定义保持不变 static relationMappings = { attributes: { modelClass: () => AttributeModel, // 改为函数返回,延迟加载 relation: Model.ManyToManyRelation, join: { from: 'resource_group.id', through: { from: 'resourcegroup_attribute.resource_group_id', to: 'resourcegroup_attribute.attribute_id' }, to: 'attribute.id', }, }, } }
修正attribute.model.ts
import { BaseModel } from './base.model'; import { Model } from 'objection'; import { ResourceGroupModel } from './resource-group.model'; // 新增导入 export class AttributeModel extends BaseModel { static tableName = 'attribute' // 原有字段定义保持不变 static relationMappings = { resourceGroups: { modelClass: () => ResourceGroupModel, // 替换原有字符串路径 relation: Model.ManyToManyRelation, join: { from: 'attribute.id', through: { from: 'resourcegroup_attribute.attribute_id', to: 'resourcegroup_attribute.resource_group_id', }, to: 'resource_group.id', }, }, } }
步骤2:修正图查询写法
withGraphFetched官方推荐传入字符串形式的关联名,避免数组写法的兼容问题:
test() { return this.model .query() .withGraphFetched('attributes') // 改为字符串写法 .where({id: 25}); }
可选检查项
- 确认你使用的Objection版本 >= 2.0,支持函数形式的
modelClass配置。 - 确认BaseModel已经正确绑定knex实例,启动代码中存在
Model.knex(knexInstance)的逻辑。 - 如果使用
@willsoto/nestjs-objection集成包,确认在对应模块中通过ObjectionModule.forFeature([ResourceGroupModel, AttributeModel])注册了两个模型。
内容的提问来源于stack exchange,提问作者TheHiggsBroson
相关产品推荐
相关产品推荐

