如何全局配置Sequelize:findById抛错、findAll返回空数组?
解决Sequelize全局配置差异化查询行为的问题
我明白你想要的效果:调用Model.findById(id)时没找到数据就抛出EmptyResultError,但Model.findAll()即使无结果也返回空数组。之前全局设置rejectOnEmpty: true导致findAll也报错,这是因为这个配置会作用于所有支持该选项的查询方法,而findAll默认的rejectOnEmpty是false,全局配置直接覆盖了它的默认行为。
下面是两种可行的全局配置方案,能让所有模型统一实现你要的效果:
方案一:通过基础模型继承(推荐)
创建一个自定义的基础模型,重写findById和findAll方法,让所有业务模型都继承这个基础模型。这种方式最灵活,也容易维护。
const { Sequelize, Model, EmptyResultError } = require('sequelize'); // 初始化Sequelize实例,不要在define里设置rejectOnEmpty const sequelize = new Sequelize(null, null, null, { dialect: 'sqlite', storage: 'tmp/db.sqlite' }); // 定义全局基础模型 class BaseModel extends Model { // 重写findById(本质是findByPk的别名),无结果则抛错 static async findById(id, options = {}) { const record = await super.findByPk(id, options); if (!record) { throw new EmptyResultError(); } return record; } // 重写findAll,强制设置rejectOnEmpty为false,确保空结果返回[] static async findAll(options = {}) { return super.findAll({ ...options, rejectOnEmpty: false }); } } // 初始化基础模型 BaseModel.init({}, { sequelize, modelName: 'BaseModel' }); // 示例:业务模型继承BaseModel class User extends BaseModel { static init(attributes, options) { return super.init(attributes, { ...options, modelName: 'User' }); } } // 初始化User模型的字段 User.init({ username: Sequelize.STRING, email: Sequelize.STRING }, { sequelize });
这样,所有继承BaseModel的模型都会自动遵循规则:findById无数据抛错,findAll空结果返回数组。
方案二:利用全局模型钩子(备选)
如果不想用继承,也可以通过全局的模型钩子来实现,但需要在afterFind钩子里判断查询类型:
const { Sequelize, EmptyResultError } = require('sequelize'); const sequelize = new Sequelize(null, null, null, { dialect: 'sqlite', storage: 'tmp/db.sqlite', define: { // 全局添加afterFind钩子 hooks: { afterFind: (results, options) => { // 判断是否是findByPk/findById查询,且无结果 if (options.rejectOnEmpty !== false && options.where && options.where[sequelize.Model.primaryKeyAttribute]) { if (!results) { throw new EmptyResultError(); } } // findAll查询不管结果是否为空,都返回原结果(空数组) } } } });
不过这种方式不如继承直观,而且需要依赖查询选项的判断,可能存在边缘情况,所以更推荐方案一。
关键说明
rejectOnEmpty选项原本是为findByPk、findOne这类期望返回单条数据的方法设计的,findAll默认不会触发这个选项。全局设置rejectOnEmpty: true会打破这个默认逻辑,所以需要针对性重写或配置。findById在Sequelize中其实是findByPk的别名,所以重写findById时调用super.findByPk即可。
内容的提问来源于stack exchange,提问作者markbrown4
相关产品推荐
相关产品推荐

