TypeORM afterUpdate监听器为何未捕获PostgreSQL中@UpdateDateColumn更新?
问题原因分析
TypeORM中@UpdateDateColumn的更新逻辑是在生成SQL UPDATE语句时自动追加字段赋值,并不会修改你传入的EmployeeEntity对象的updatedAt属性。而afterUpdate事件里的updatedColumns集合,只包含那些通过修改实体对象属性触发更新的字段,这类自动维护的系统字段不会被纳入变更追踪,所以你看不到它的记录。
简单说:你修改的name是实体属性变更,会被追踪;但updatedAt是TypeORM偷偷在SQL里加的更新,实体对象本身没改,所以不在updatedColumns里。
解决方案
方案一:在afterUpdate中手动补充updatedAt的变更记录
既然你知道每次更新都会触发updatedAt的自动更新,直接在事件处理逻辑里手动添加这条记录即可:
afterUpdate(event: UpdateEvent<EmployeeEntity>){ const { updatedColumns, databaseEntity, entity } = event; // 先处理原本的更新列 updatedColumns.forEach(({ propertyName }) => { const oldVal = databaseEntity[propertyName as keyof EmployeeEntity]; const newVal = entity?.[propertyName as keyof EmployeeEntity]; // 执行你的记录逻辑... }); // 手动补充updatedAt的变更 const oldUpdatedAt = databaseEntity.updatedAt; // 获取新值的两种方式: // 1. 如果数据库驱动返回更新后的行(如PostgreSQL的RETURNING),从queryResult提取 const newUpdatedAt = event.queryResult?.raw[0]?.updated_at; // 2. 直接用当前时间(TypeORM默认用当前时间戳更新,二者基本一致) // const newUpdatedAt = new Date(); if (oldUpdatedAt && newUpdatedAt) { // 记录updatedAt的新旧值逻辑 console.log(`updatedAt: 旧值 ${oldUpdatedAt}, 新值 ${newUpdatedAt}`); } }
方案二:监听SQL执行事件,解析UPDATE语句
如果需要更通用的追踪方式,可以监听queryRunner的query事件,解析生成的SQL语句来提取updated_at的变更:
// 在订阅者构造函数中注入Connection并添加监听 constructor(private readonly connection: Connection) { this.connection.queryRunnerManager.create().on('query', (query) => { if (query.sql.includes('UPDATE `employee`') && query.sql.includes('updated_at')) { // 根据数据库类型解析SQL中的updated_at赋值(如MySQL的CURRENT_TIMESTAMP、PostgreSQL的NOW()) // 结合databaseEntity的旧值完成记录 } }); }
这种方式复杂度较高,适合需要追踪所有SQL层面变更的场景。
注意事项
- 不要手动给
updatedAt赋值来触发追踪,这违背了@UpdateDateColumn的设计初衷,还可能导致时间不一致的问题。 - 不同数据库驱动对
queryResult.raw的返回格式可能不同,需要根据你使用的数据库(MySQL/PostgreSQL等)调整新值的获取方式。
内容的提问来源于stack exchange,提问作者JSDeveloper_CAR
相关产品推荐
相关产品推荐

