Я сделал это, используя Event Listeners
, вдохновленный этой статьей . Я создал 2 слушателя один для вставки и один для обновления / удаления. Они перехватывают изменения, и всякий раз, когда происходят изменения, я обновляю столбец modified_at
корневого объекта.
@Component
public class RootAwareInsertEventListener implements PersistEventListener {
private static final Logger logger = LoggerFactory.getLogger(RootAwareInsertEventListener.class);
@Autowired
private EntityManagerFactory emf;
@PostConstruct
private void init() {
SessionFactoryImpl sessionFactory = emf.unwrap(SessionFactoryImpl.class);
EventListenerRegistry registry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);
registry.getEventListenerGroup(EventType.PERSIST).appendListener(this);
}
/**
* Intercept hibernate persist - and if entity is RootAware it will update modified_at of root entity
*/
@Override
public void onPersist(PersistEvent event) throws HibernateException {
final Object entity = event.getObject();
if (entity instanceof RootAware) {
RootAware rootAware = (RootAware) entity;
MortgageCase root = (MortgageCase) rootAware.root();
logger.info("Modifing {} modified_at because a {} child entity has been inserted", root, entity);
root.setModifiedAt(new Date());
}
}
@Override
public void onPersist(PersistEvent event, Map createdAlready) throws HibernateException {
onPersist(event);
}
}
@Component
public class RootAwareUpdateAndDeleteEventListener implements FlushEntityEventListener {
private static final Logger logger = LoggerFactory.getLogger(RootAwareUpdateAndDeleteEventListener.class);
@Autowired
private EntityManagerFactory emf;
@PostConstruct
private void init() {
SessionFactoryImpl sessionFactory = emf.unwrap(SessionFactoryImpl.class);
EventListenerRegistry registry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);
registry.getEventListenerGroup(EventType.FLUSH_ENTITY).appendListener(this);
}
/**
* Intercept hibernate update / delete - and if entity is RootAware it will update modified_at of root entity
*/
@Override
public void onFlushEntity(FlushEntityEvent event) throws HibernateException {
final EntityEntry entry = event.getEntityEntry();
final Object entity = event.getEntity();
final boolean mightBeDirty = entry.requiresDirtyCheck(entity);
if (mightBeDirty && entity instanceof RootAware) {
RootAware rootAware = (RootAware) entity;
if (updated(event)) {
MortgageCase root = (MortgageCase) rootAware.root();
logger.info("Modifing {} modified_at because a {} child entity has been updated", root, entity);
root.setModifiedAt(new Date());
} else if (deleted(event)) {
MortgageCase root = (MortgageCase) rootAware.root();
logger.info("Modifing {} modified_at because a {} child entity has been deleted", root, entity);
root.setModifiedAt(new Date());
}
}
}
private boolean deleted(FlushEntityEvent event) {
return event.getEntityEntry().getStatus() == Status.DELETED;
}
private boolean updated(FlushEntityEvent event) {
final EntityEntry entry = event.getEntityEntry();
final Object entity = event.getEntity();
int[] dirtyProperties;
EntityPersister persister = entry.getPersister();
final Object[] values = event.getPropertyValues();
SessionImplementor session = event.getSession();
if (event.hasDatabaseSnapshot()) {
dirtyProperties = persister.findModified(event.getDatabaseSnapshot(), values, entity, session);
} else {
dirtyProperties = persister.findDirty(values, entry.getLoadedState(), entity, session);
}
return dirtyProperties != null;
}
}