存储库级别的实体侦听器 - 如何影响级联实体
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;
}
}
}
我通过覆盖 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;
}
}
}