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

NestJS TypeORM Subscriber的afterUpdate事件无法返回更新列

解决TypeORM afterUpdate事件中updatedColumns为空的问题

为什么updatedColumns是空数组?

TypeORM的updatedColumns字段仅在通过实体管理器(EntityManager)或仓库(Repository)的save()方法更新实体实例时才会填充。如果使用QueryBuilder执行更新操作,TypeORM无法自动跟踪变更的列,因此updatedColumns会返回空数组。此外,若save()传入的实体与数据库中现有数据完全一致,updatedColumns也会是空数组。

获取更新列的可行方案

方案1:使用save()方法时直接读取updatedColumns

如果你的更新操作是通过repository.save(entity)或manager.save(entity)执行的,可直接从updatedColumns提取列名:

// 在订阅器的afterUpdate方法中
const updatedColumnNames = event.updatedColumns.map(col => col.propertyName);
console.log('更新的列:', updatedColumnNames);

注意:确保更新的实体确实有字段值发生变化,否则updatedColumns仍会为空。

方案2:QueryBuilder更新时手动记录字段

使用QueryBuilder时,需要在执行更新时主动记录变更的字段,并通过queryRunner的data属性传递给订阅器:

// 执行更新的代码
const updateFields = ['username', 'email'];
const queryRunner = connection.createQueryRunner();

await queryRunner.connect();
await queryRunner.startTransaction();

try {
  await queryRunner.manager
    .createQueryBuilder()
    .update(User)
    .set({ username: 'newUser', email: 'new@example.com' })
    .where('id = :id', { id: 1 })
    .execute();
  
  // 将更新字段存入queryRunner的data中
  queryRunner.data.updatedFields = updateFields;
  
  await queryRunner.commitTransaction();
} catch (err) {
  await queryRunner.rollbackTransaction();
} finally {
  await queryRunner.release();
}

然后在订阅器的afterUpdate事件中读取:

// 订阅器中
const updatedColumnNames = event.queryRunner.data.updatedFields as string[];
console.log('更新的列:', updatedColumnNames);

方案3:对比entity与databaseEntity找出差异

无论使用哪种更新方式,都可以通过对比更新后的实体(event.entity)和数据库中原始实体(event.databaseEntity)的字段值,找出变更的列:

// 在订阅器的afterUpdate方法中
const updatedColumnNames: string[] = [];

if (!event.entity || !event.databaseEntity) {
  return;
}

event.metadata.columns.forEach(column => {
  const propName = column.propertyName;
  const newValue = event.entity[propName];
  const oldValue = event.databaseEntity[propName];

  // 针对不同类型做比较,比如日期类型转字符串
  const isEqual = (() => {
    if (newValue instanceof Date && oldValue instanceof Date) {
      return newValue.toISOString() === oldValue.toISOString();
    }
    // 嵌套对象或数组需要深比较,可引入lodash的isEqual等工具
    return newValue === oldValue;
  })();

  if (!isEqual) {
    updatedColumnNames.push(propName);
  }
});

console.log('更新的列:', updatedColumnNames);

注意:这种方法需要处理特殊类型(如日期、嵌套对象)的比较逻辑,避免误判。


内容的提问来源于stack exchange,提问作者Abhimanyu Patil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 20:43:13