Yes, I implemented equals() and hashCode() judiciously.
I have found a workaround for this issue but firstly let me tell you why this unwanted UPDATE action is causing this error.
The application I am developing is a migration project and the new app is using hbm and spring whereas the old app is all PowerBuilder. I turns out that for a period of time both versions of the apps must run side-by-side using the same database and data model. This imposes some extra-work as u might imagine because of optimistic locking and version columns, among other problems. To solve this problem, we have implemented triggers before update on all tables that could possibly be updated from the old power-builder app, so that version column value is incremented when update statements are fired from the old app. This trigger is always fired when an UPDATE statement is not changing the VERSION column (i am assuming that this kind of updates could never be issued by hbm...am i wrong ?).
so, when hbm fires this unwanted and unexpected UPDATE action my trigger is fired during the same database transaction and version column is incremented and consequently the DELETE action fails because of the clause 'WHERE VERSION = x ' (VERSION now is x + 1).
Still reading ? Ohh..thanks !
My workaround for this problem was:
- Implement a custom FlushEventListener:
MyCustomFlushEventListener extends DefaultFlushEventListener
and override
performExecutions like this:
Code:
public class TgsFlushEventListener extends DefaultFlushEventListener {
/**
* serial version uid
*/
private static final long serialVersionUID = -2641082688768377280L;
/**
* @see org.hibernate.event.def.AbstractFlushingEventListener#performExecutions(
* org.hibernate.engine.SessionImplementor)
*/
protected void performExecutions(SessionImplementor session) {
ActionQueue queue = session.getActionQueue();
try {
Collection updates = (Collection) ReflectionUtils.getField("updates", queue);
Collection deletions = (Collection) ReflectionUtils.getField("deletions", queue);
if (updates.size() > 0 && deletions.size() > 0) {
consolidateActions(updates, deletions);
}
} catch (SecurityException e) {
throw new UnexpectedException(e);
} catch (RuntimeException e) {
throw new UnexpectedException(e);
}
super.performExecutions(session);
}
/**
* @param updates
* la colección de acciones de update de tipo
* @link EntityUpdateAction
*
* @param deletions
* la colección de acciones de delete de tipo
* @link org.hibernate.action.EntityDeleteAction
*/
private void consolidateActions(Collection updates, Collection deletions) {
List actionsToRemove = new ArrayList();
for (Iterator iter = updates.iterator(); iter.hasNext();) {
EntityUpdateAction uAction = (EntityUpdateAction) iter.next();
if (noVersionIncrementExistsFor(uAction)) {
actionsToRemove.add(uAction);
}
}
updates.removeAll(actionsToRemove);
}
/**
* @param action una acción de tipo @link EntityUpdateAction
*
* @return <code>true</code> si la acción de update no determinó
* un incremento en la versión del objeto luego del update
*/
private boolean noVersionIncrementExistsFor(EntityUpdateAction action) {
Object lastVersion = ReflectionUtils.getField("lastVersion", action);
Object nextVersion = ReflectionUtils.getField("nextVersion", action);
return lastVersion.equals(nextVersion);
}
}