存储库级别的实体侦听器 - 如何影响级联实体

Entity listeners at repository level - how to also affect cascated entities

我通过覆盖 SimpleJpaRepository 向我的项目添加了一个监听器层,所以它看起来像这样:

@Override
@Transactional
public <S extends E> S save(S entity) {
    if (entityInformation.isNew(entity)) {
        persister.beforeCreateListenersFor(entity.getClass()).execute(entity);
        entityManager.persist(entity);
        persister.afterCreateListenersFor(entity.getClass()).execute(entity);
        return entity;
    } else {
        S merged;
        persister.beforeUpdateListenersFor(entity.getClass()).execute(entity);
        merged = entityManager.merge(entity);
        persister.afterUpdateListenersFor(entity.getClass()).execute(entity);
        return merged;
    }
}

@Override
public void delete(E entity) {
    Assert.notNull(entity, "Entity must not be null.");
    if (entity instanceof LogicRemovable) {
        ((LogicRemovable) entity).setLogicRemoved(true);
        save(entity);
    } else {
        persister.beforeDeleteListenersFor(entity.getClass()).execute(entity);
        entityManager.remove(entityManager.contains(entity) ? entity : entityManager.merge(entity));
        persister.afterDeleteListenersFor(entity.getClass()).execute(entity);
    }
}

其中 persister 是一个接口,它为给定的 class 和给定的类型(BEFORE_CREATE、AFTER_CREATE 等提供监听器) 在运行时,注入监听器需要的一切。

一切都很棒,我所要做的就是用给定的注释对侦听器进行注释。

问题是:由于该层处于存储库级别,因此它不会影响级联实体。

那么,我怎样才能让它也影响级联实体?

对我来说,完美的解决方案是“将层从存储库移动到 X(例如实体管理器,不确定),它会影响两者”,但我不知道 X 是什么。

或者还有其他解决方案,欢迎任何解决方案。

谢谢!

-芒硝

你想对听众做什么?你在使用实体监听器吗? https://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/listeners.html。你能创建一个实体侦听器并注释一个基本实体吗?

我在这里回答过一次类似的问题。

Using Hibernate 4's Integrator pattern and Spring's dependency injection

有了它,您可以使用 spring bean 作为处于最低级别的休眠侦听器。每个被刷新的实体都会触发监听器。

这取决于您使用听众的目的。 HibernateListeners 不应该修改或创建新实体,因为 ActionQueue 已经构建。 (但是 Envers 然而正在使用这些侦听器来创建修订历史记录。)

非常感谢 Martin Frey 的解决方案,我能够使用您的解决方案来调整我的解决方案。

我所做的是仅创建六个通用 Hibernate 监听器,一个用于我使用的每种事件类型,就像您的解决方案一样。但是后来我将存储库中的那些行移动到每个相应的休眠侦听器中,因此可用性没有变化。

我需要处理的其他事情:

1) 由于审计原因,在调用监听器之前必须进行实体检查(被审计的实体创建自己的 table,并且它确实通过监听器,但由于它没有自己的自己的 java 类型,它以地图的形式出现。所以我收到了 ClassCastException。

2) 我必须动态更新状态。没有太多的细节,但这就是我所说的:PreInsertEventListener object modifications not sticky

由于我的监听器是通用的,我不能只是对新值进行硬编码,所以我了解了 Hibernate 如何创建状态数组并重新创建和覆盖它。

最终代码现在如下所示:

@Component
public class HibernatePreInsertEventListener<T extends Entity> implements HibernateEventListener, PreInsertEventListener {

    @Autowired
    private Persister persister;

    @SuppressWarnings("unchecked")
    @Override
    public boolean onPreInsert(PreInsertEvent event) {
        Object someEntity = event.getEntity();
        if(Entity.class.isAssignableFrom(someEntity.getClass())) {
            T entity = (T) someEntity;
            Class<T> entityClass = (Class<T>) entity.getClass();

            persister.beforeCreateListenersFor(entityClass).execute(entity);
            updateState(event);
        }
        return false;
    }

    private void updateState(PreInsertEvent event) {
        Object[] newState = event.getPersister().getPropertyValuesToInsert(event.getEntity(), null, event.getSession());

        for (int i = 0; i < newState.length; i++) {
            Object o = newState[i];
            event.getState()[i] = o;
        }
    }
}