使用 EventSubscriber 在 mikroorm 中注册 Database History

Use EventSubscriber to register Database History in mikroorm

我对 LifcycleHooks 和 EventSubscribers 的概念还很陌生。我正在尝试填充一个历史 table 来记录对任何其他 table 所做的更改。我一直在尝试为此使用 EventSubscriber: 我的想法是,在我的 eventSubscriber 的 onFlush 事件触发器上,我从变更集中提取所有已更改的值和字段,并创建一个历史对象 table 并尝试保留它,但我看到以下错误:

This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason: ValidationError: You cannot call em.flush() from inside lifecycle hook handlers

我的订阅者是这样的:

import { HistoryLog } from 'src/entities/history-log.entity;
export class EntityChangeSubscriber implements EventSubscriber<AnyEntity>  {

  async afterCreate(args: EventArgs<AnyEntity>): Promise<void> {
    console.log('===========1111 AfterCreateHook');
    console.log(args.entity);
  }
  async afterUpdate(args: EventArgs<AnyEntity>): Promise<void> {
    console.log('===========2222 AfterUpdateHook');
    console.log(args.entity);
  }

  async onFlush(args: FlushEventArgs): Promise<void> {
    console.log('===========3333 onFlushHook');
    console.log(args);
    const changeSets = args.uow.getChangeSets();
    const entities = changeSets.map((cs) => cs.entity);
    console.log('Affected entities', entities);
  }

  async afterFlush(args: FlushEventArgs): Promise<void> {
    console.log('===========4444 AfterFlushHook');

    const changeSets = args.uow.getChangeSets();
    console.log('change sets', changeSets);
    changeSets?.map(async (cs) => {
      if (cs.persisted) {
        console.log('print changeset');
        let nextValues = cs.payload ? cs.payload : {};
        let tableName = cs.name;
        let operation = cs.type;
        let rowId = cs.getPrimaryKey()?.toString();
        let modifiedFields = Object.keys(cs.payload);
        let previousValues = cs.originalEntity ? cs.originalEntity : {};
       for (let key in previousValues) {
          if (
            !previousValues.hasOwnProperty(key) ||
            !modifiedFields.includes(key)
          ) {
            delete previousValues[key];
          }
        }
       const historyLog=new HistoryLog({
          operation,
          tableName,
          rowId,
          previousValues,
          nextValues
        });
        console.log(historyLog);
     
        let historyLog1= await args.em.persistAndFlush(historyLog);
        console.log('historyLog1>>> ',historyLog1);
        return historyLog1;
      }
    });
 }
}

我的 mikro-orm-postgres.config.ts 注册了订阅者,我可以看到正在加载的变更集 subscribers: [new EntityChangeSubscriber()]

我该如何实施?有没有一种方法可以 return 将 EventSubscriber 的结果发送到服务 class 并在那里执行持久操作?

您不应从任何挂钩或事件处理程序内部刷新。使用刷新事件是正确的,但您应该使用 onFlush 而不是 afterFlush 并将新添加的实体附加到当前工作单元。这正是文档中示例显示的内容。

https://mikro-orm.io/docs/lifecycle-hooks/#using-onflush-event

如果您想并行发出查询(不在同一事务中),您可以分叉 EM 来绕过验证错误,或者使用 em.nativeInsert() 而不是 UoW 来创建新记录.