You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express+Knex+Objection中BaseService通用方法编写问题求解

问题原因
  • 泛型无约束:BaseService的泛型Models没有绑定Objection模型类型,TS无法识别传入参数上的query()方法,类型校验和运行时都会出问题
  • 语法错误:find()方法未声明async,直接在方法内使用await会触发语法错误
  • API调用错误:代码里的findAll()是Sequelize的ORM方法,Objection原生不存在该API,直接调用会报方法不存在的错误
  • 拼写错误:多处将UserModel拼为UserMoodel,会直接导致引用失败
  • 模型配置缺失:Objection模型必须声明静态tableName属性,否则无法正常执行查询
可落地的封装方案

1. 修正基类BaseService

添加Objection内置的ModelClass泛型约束,补全正确的通用方法逻辑:

// base.service.ts
import { Model, ModelClass } from 'objection';

class BaseService<M extends Model> {
  // 存储传入的模型类
  protected model: ModelClass<M>;

  constructor(model: ModelClass<M>) {
    this.model = model;
  }

  // 通用查询全量方法
  public async find(): Promise<M[]> {
    // Objection直接调用query()默认构造select * from 表名的查询,等价于全量查询
    return this.model.query();
  }

  // 可按需扩展其他通用CRUD方法
  public async findById(id: number | string): Promise<M | undefined> {
    return this.model.query().findById(id);
  }

  public async create(data: Partial<M>): Promise<M> {
    return this.model.query().insert(data);
  }

  public async updateById(id: number | string, data: Partial<M>): Promise<number> {
    return this.model.query().patchAndFetchById(id, data).then(res => res ? 1 : 0);
  }

  public async deleteById(id: number | string): Promise<number> {
    return this.model.query().deleteById(id);
  }
}

export default BaseService;

2. 修正User模型

修正拼写,补全Objection要求的必填配置:

// user.model.ts
import { Model } from 'objection';

export class UserModel extends Model {
  // 必填:绑定对应的数据表名
  static tableName = 'users';

  // 按需定义字段、关联关系、校验规则
  id!: number;
  username!: string;
  email!: string;
}

3. 修正UserService

继承时传入正确的模型实例类型作为泛型,直接复用基类通用方法,无需重复编写基础查询逻辑:

// user.service.ts
import BaseService from './base.service';
import { UserModel } from './user.model';

class UserService extends BaseService<UserModel> {
  constructor() {
    super(UserModel);
  }

  // 业务方法直接复用基类find
  async getUsers() {
    return this.find();
  }
}

export default UserService;
使用说明
  • 后续新增其他模型的Service时,只需要继承BaseService并传入对应模型类,即可直接复用所有通用CRUD方法,无需重复编写相同逻辑
  • 如果需要自定义返回类型转换,可以在基类扩展通用的类型转换方法,不要在每个子类里重复实现查询逻辑
  • 所有异步方法必须添加async关键字,否则await语法无法正常生效

内容的提问来源于stack exchange,提问作者mayur badodiya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 02:48:29