Hi
I am doing an upgrade of Hibernate from 2.1.8 to 3.3.1. While testing the upgrade, I am facing with a weird scenario.
The application is creating a new hibernate object, and calling SessionImpl.saveOrUpdate(obj); to save that to the database. And it was working good in 2.1.8. But when the new jars for 3.3.1 are added, this method some how assumes the object as a detached entry and proceed with updating the object. But since it is a new entry, there is nothing to update in database, and hence is throwing the following error while flushing the session at the end of the request
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1 at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:85) at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:70) at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:47) at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2431) at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2335) at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2635) at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:115) at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168) at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321) at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50) at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
The trace goes all the way to DefaultSaveOrUpdateEventListener as per the logs, and it enters protected int getEntityState(...) and goes to if ( ForeignKeys.isTransient( entityName, entity, getAssumedUnsaved(), source ) ) condition. This if condition is returning false hence by making hibernate assume that it is a detached instance.
The id attribute is generated for the object, and its definition is as below. There is no unsaved-value defined explicitly leaving it to default
<id name="assetId" type="long" column="ASSET_ID"> <generator class="assigned" /> </id>
How ever, when the same code is executed in 2.1.8, the functionality saves perfect. The trace on 2.1.8 goes to SessionImpl.saveOrUpdate(Object obj), the EntityEntry e = getEntry(object); returns a null, so go to else case and then calls save(obj); which is the expected case
Not sure why in 3.3.1, the entry is considered as detached instance on the first place, which is leading it to update the detached instance and fail at end breaking the application.
Immediately after the save is issued, I see the following trace from Hibernate Debug
org.hibernate.engine.IdentifierValue [4] [processAutoDecline] - id unsaved-value strategy NULL org.hibernate.event.def.DefaultSaveOrUpdateEventListener [4] [processAutoDecline] - updating detached instance org.hibernate.event.def.DefaultSaveOrUpdateEventListener [4] [processAutoDecline] - updating [com.i21.epay.model.AssetHolder#10000721] 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.DefaultSaveOrUpdateEventListener [4] [processAutoDecline] - calling onUpdate() 31 May 2009 20:38:36 INFO [WebContainer : 1] com.insurance21.framework.service.BusinessObject [4] [processAutoDecline] - in onUpdate 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.ReattachVisitor [4] [processAutoDecline] - collection dereferenced while transient [com.i21.epay.model.AssetHolder.financialAccts#10000721] 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.ReattachVisitor [4] [processAutoDecline] - collection dereferenced while transient [com.i21.epay.model.AssetHolder.autopayMemberHistory#10000721] 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.ReattachVisitor [4] [processAutoDecline] - collection dereferenced while transient [com.i21.epay.model.AssetHolder.assetDiaries#10000721] 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.ReattachVisitor [4] [processAutoDecline] - collection dereferenced while transient [com.i21.epay.model.AssetHolder.autoPayAgreement#10000721] 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.ReattachVisitor [4] [processAutoDecline] - collection dereferenced while transient [com.i21.epay.model.AssetHolder.enrollmentInfo#10000721] 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.ReattachVisitor [4] [processAutoDecline] - collection dereferenced while transient [com.i21.epay.model.AssetHolder.noticeWaivers#10000721] 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.DefaultSaveOrUpdateEventListener [4] [processAutoDecline] - updating [com.i21.epay.model.AssetHolder#10000721] 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.engine.Cascade [4] [processAutoDecline] - processing cascade ACTION_SAVE_UPDATE for: com.i21.epay.model.AssetHolder 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.engine.Cascade [4] [processAutoDecline] - cascade ACTION_SAVE_UPDATE for collection: com.i21.epay.model.AssetHolder.autopayMemberHistory 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.engine.CascadingAction [4] [processAutoDecline] - cascading to saveOrUpdate: com.i21.epay.model.AutoPayMemberHistory 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.engine.IdentifierValue [4] [processAutoDecline] - id unsaved-value strategy NONE 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.AbstractSaveEventListener [4] [processAutoDecline] - detached instance of: com.i21.epay.model.AutoPayMemberHistory 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.DefaultSaveOrUpdateEventListener [4] [processAutoDecline] - updating detached instance 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.DefaultSaveOrUpdateEventListener [4] [processAutoDecline] - updating [com.i21.epay.model.AutoPayMemberHistory#component[partitionId,assetId,historySeqNum]{historySeqNum=1, partitionId=272100, assetId=10000721}] 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.DefaultSaveOrUpdateEventListener [4] [processAutoDecline] - calling onUpdate() 31 May 2009 20:38:36 INFO [WebContainer : 1] com.insurance21.framework.service.BusinessObject [4] [processAutoDecline] - in onUpdate 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.DefaultSaveOrUpdateEventListener [4] [processAutoDecline] - updating [com.i21.epay.model.AutoPayMemberHistory#component[partitionId,assetId,historySeqNum]{historySeqNum=1, partitionId=272100, assetId=10000721}] 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.engine.Cascade [4] [processAutoDecline] - done cascade ACTION_SAVE_UPDATE for collection: com.i21.epay.model.AssetHolder.autopayMemberHistory 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.engine.CascadingAction [4] [processAutoDecline] - cascading to saveOrUpdate: com.i21.epay.model.AssetLock 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.engine.IdentifierValue [4] [processAutoDecline] - id unsaved-value strategy NULL 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.AbstractSaveEventListener [4] [processAutoDecline] - detached instance of: com.i21.epay.model.AssetLock 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.DefaultSaveOrUpdateEventListener [4] [processAutoDecline] - updating detached instance 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.DefaultSaveOrUpdateEventListener [4] [processAutoDecline] - updating [com.i21.epay.model.AssetLock#10000721] 31 May 2009 20:38:36 DEBUG [WebContainer : 1] org.hibernate.event.def.DefaultSaveOrUpdateEventListener [4] [processAutoDecline] - calling onUpdate() .......
I am comparatively new to Hibernate, any help is much appreciated.
|