I am testing the upgrade of Hibernate from 3.3.2 to 4.2.6.Final. I made the few required changes (CollectionOfElements to ElementCollection, etc..)
and everything seems to be working, with the exception of one Junit test (which has not given us problems before). I have the same issue running the
unit test against Hypersonic and MSSQL databases.
The test removes the last entry from a persisted list, that has 2 entries on it. When the transaction commits, some code in Hibernate seems to have
removed the first item from the list as well, and I get an ObjectDeletedException, complaining about the first entry on the list.
Below are the relevant parts of the 2 classes - a VmBackup contains a list of Snapshots.
Code:
public class VmBackup
{
@OneToMany(mappedBy = "vmBackup", cascade = CascadeType.ALL)
@OrderBy()
private List<Snapshot> backups = new ArrayList<Snapshot>();
}
Code:
public class Snapshot
{
@ManyToOne(fetch = FetchType.LAZY, optional = false)
private VmBackup vmBackup;
}
Below is the code that removes the last snapshot from the list:
Code:
public void deleteSnapshot()
{
List<Snapshot> snapshots = getBackups();
// Walk the list backwards, since we are removing items from it as we go
for (int i = snapshots.size() - 1; i >= 0; i--)
{
Snapshot snapshot = snapshots.get(i);
if (snapshot.getId().equals(restorePointId))
{
LOG.info("Deleting snapshot " + snapshot.toString());
// Remove the snapshot from the list of backups
snapshot = backups.remove(i);
session.delete(snapshot);
}
}
}
I've run the test thru Eclipse and set a breakpoint at the session.delete line. The call stack is as follows:
Quote:
deleteSnapshot
NativeMethodAccessorImpl.invoke()
NativeMethodAccessorImpl.invoke()
DelegatingMethodAccessorImpl()
Method.invoke()
JavassistLazyInitializer.invoke()
VmBackup_$$_javassist_29.deleteSnapshot
completeRestorePoint
If I look at the list when the deleteSnapshot method exits, there is the single entry on it, as there should be.
When the code returns to that last method on the call stack (completeRestorePoint), the list is empty, so somewhere in the
code on the call stack, the additional entry is removed from the list.
Below are what I believe are the relevant log messages from Hibernate, and the stack trace when I try to commit the transaction.
Snapshot#1 is the entry on the list that was not deleted by my code.
Quote:
2013-10-04 14:58:30,115 TRACE: Processing cascade ACTION_SAVE_UPDATE for: com.vc.mgmt.api.backup.VmBackup [Cascade[main]]
2013-10-04 14:58:30,115 TRACE: Cascade ACTION_SAVE_UPDATE for collection: com.vc.mgmt.api.backup.VmBackup.backups [Cascade[main]]
org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): [com.vc.mgmt.api.backup.Snapshot#1]
at org.hibernate.internal.SessionImpl.forceFlush(SessionImpl.java:1247)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:184)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:114)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:735)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:727)
at org.hibernate.engine.spi.CascadingAction$5.cascade(CascadingAction.java:258)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:388)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:331)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:209)
at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:418)
at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:358)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:334)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:209)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:166)
at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:162)
at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:153)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:89)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1234)
at com.vc.mgmt.api.TxFactory.commitTransaction(TxFactory.java:352)
at com.vc.mgmt.control.ControlServlet.handleRequest(ControlServlet.java:446)