0

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

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()]

我该如何实施?有没有办法可以将 EventSubscriber 的结果返回到服务类并在那里进行持久化操作?

4

1 回答 1

1

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

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

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

于 2021-10-12T09:15:29.030 回答