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

时间:2015-04-09 23:08:13

标签: spring hibernate jpa spring-data cascade

我通过覆盖 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 是一个接口,它在运行时为给定类和给定类型(BEFORE_CREATE,AFTER_CREATE等)提供侦听器,并注入侦听器所需的所有内容。

一切都很有效,我所要做的就是用给定的注释注释听众。

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

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

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

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

谢谢!

-glauber

3 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

我在这里回答了一个类似的问题。

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

有了这个,你可以使用spring bean作为hibernate监听器,它们是最低级别的。刷新的每个实体都将触发监听器。

这取决于你使用听众的内容。由于ActionQueue已经构建,HibernateListeners不应该修改或创建新实体。 (但Envers正在使用这些侦听器来创建修订历史记录。)

答案 2 :(得分:0)

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

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

我需要照顾的其他事情:

由于审计(审计实体创建了自己的表,并且它确实通过了侦听器,但由于它没有自己的java类型,因此1)必须在调用侦听器之前进行实体检查。它来自一个地图。所以我得到了一个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;
        }
    }
}