Objection.js封装动态模型报错id列空/未定义如何解决
错误原因
- Objection.js 的模型核心配置依赖类静态属性读取,你之前的写法把表名存在了实例属性
this.name上,静态方法static get tableName()访问的this指向类本身而非实例,根本拿不到你传入的表名参数,最终tableName返回值不符合预期,框架读取默认主键id时匹配不到正确的表结构,直接抛出错误。 - 用法逻辑错误:Objection 中
new 模型类()得到的是单条数据库记录的实例,并非表操作的入口对象。表查询、关联配置等能力全部定义在类的静态方法/属性上,必须基于配置正确的模型类调用,不能通过实例传递配置。
修复实现
按照动态子类继承的思路实现通用模型封装,不需要为每张表单独创建文件,也不会破坏Objection的原生逻辑:
- 编写基础父类
models/Main.js,仅做全局knex绑定:
const { Model } = require('objection'); const knex = require('../utils/db'); Model.knex(knex); class Main extends Model {} module.exports = Main;
- 新增模型统一入口
models/index.js,通过工厂方法动态生成每个表对应的模型子类:
const Main = require('./Main'); /** * 动态生成表模型 * @param {string} tableName 表名 * @param {object} customConfig 自定义配置(主键、关联关系等) * @returns {typeof Main} 模型类 */ function createModel(tableName, customConfig = {}) { class DynamicModel extends Main { static get tableName() { return tableName; } static get idColumn() { return customConfig.idColumn || 'id'; } static get relationMappings() { return customConfig.relationMappings || {}; } } // 配置类名方便调试 Object.defineProperty(DynamicModel, 'name', { value: tableName.replace(/(^|_|-)([a-z])/g, (_, __, s) => s.toUpperCase()) }); return DynamicModel; } // 初始化所有业务表模型 module.exports = { admin: createModel('admins'), catalog: createModel('catalog'), products: createModel('products'), contacts: createModel('contacts'), inquiry: createModel('inquiry'), menus: createModel('menus'), news: createModel('news'), refreshTokenAdmin: createModel('refresh-token-admin'), rooms: createModel('rooms'), sizes: createModel('sizes'), itemSizes: createModel('item_sizes'), slider: createModel('slider'), users: createModel('users') };
- 调整控制器中的模型引用方式,直接使用生成好的模型类调用查询方法,不要实例化模型类:
const models = require('./models'); class Controllers { // 示例:查询产品列表 async getProductList() { // 直接通过模型类调用query方法,为Objection标准用法 const productList = await models.products.query().where({ is_deleted: 0 }); return productList; } } module.exports = new Controllers();
如果后续某张表需要自定义关联关系、校验规则、特殊主键,直接在调用
createModel时传入第二个配置参数即可,不需要单独新建文件。
内容的提问来源于stack exchange,提问作者jkalandarov
相关产品推荐
相关产品推荐

